Interfacing with Instruments and Making Measurements

What is an instrument?

For the purposes of this package, an instrument is just something connected to the computer that we need to communicate with, and which can apply some stimulus or measure something. Every instrument may connect to the computer by different hardware, comms protocols, and command dialects.

All instruments are Julia objects, subtypes of the abstract type Instrument. The implementation of each subtype (it's fields, constructors, etc) depend on the specific instrument.

VISA

Many instruments are able to be addressed using the VISA standard (Virtual Instrument Software Architecture), currently maintained by the IVI Foundation.

To talk to VISA instruments will require the Julia package VISA.jl as well as the National Instruments VISA libraries. Installation instructions are available at each link.

Alazar digitizers

Digitizers made by AlazarTech are notably not compatible with the VISA standard. All Alazar digitizers are addressable by an API supplied by the company, which talks to the card through a shared library (a .dll on Windows or .so on Linux). InstrumentAlazar is an abstract subtype of Instrument.

The shared library files and API documentation are only available from AlazarTech.

How do we configure instruments?

Properties

Instrument properties are configured and inspected using two functions, setindex! and getindex, which are methods from the Base module that have been overloaded in this package to work with instrument objects. This results in a convenient and concise syntax (credit due to Oliver Schulz for this idea).

For example:

awg[TriggerSlope] = :Rising
awg[SampleRate] = 10e6

How do we take measurements?

Source and measure

Two functions are provided to abstract away many kinds of measurements: source and measure. In an experiment you source some stimulus and measure a response. Therefore source takes as arguments: an instance of some subtype of the Stimulus type (which can have different fields for different subtypes), as well as the numerical value(s) for the particular stimulus. measure takes as argument an instance of some subtype of type Response. The idea is to write new subtypes of Stimulus and Response to describe what you are doing, as well as new methods for source and measure that know how to communicate with the instrument(s) based on the Stimuli and Response arguments passed to them

Stimuli

All stimuli are objects, subtyped from the abstract Stimulus type. Many stimuli, either general or associated with the capabilities of particular instruments, are already implemented. The implementation of each subtype depends on the specific goals of the user: demonstrations of different stimuli being used can be found in the example notebooks.

As a simple example, consider the PropertyStimulus type (defined in ICCommon.jl) :

mutable struct PropertyStimulus{T<:InstrumentProperty} <: Stimulus
    typ::Type{T}
    ins::Instrument    
    tuple::Tuple
    axisname::Symbol
    axislabel::String
end

with corresponding source method:

function source(ch::PropertyStimulus, val)
    ch.ins[ch.typ, ch.tuple...] = val
end

Notable among the fields of PropertyStimulus are the typ and ins fields: typ is the instrument property the stimulus object is associated with, and ins is the instrument which that property corresponds to (Type{T} is a special kind of abstract type whose only instance is the object T; visit the docs for further discussion). tuple are essentially "qualifiers" or "infixes" for the instrument property. For example, if we wanted to change (source) the amplitude of a waveform in a waveform generator instrument with multiple channels, the instrument property at hand is SourceLevel while tuple would specify on what channel we are changing the amplitude.

Thus, this Stimulus object holds all the necessary information for a source method to change the value of instrument property T to any value passed to it. And the corresponding source function in fact does just that: it calls a setindex! method to change property T (with qualifiers tuple) on instrument ins to value val. Again, stimuli need not be tied to a particular property; rather, this is just one convenient and easily generalizable example.

For a concrete example on the use of PropertyStimulus, consider needing to source various frequencies in our E8257D signal generator, where the frequency of a signal generator is an instrument property called Frequency. We can accomplish this task using PropertyStimulus in the following way:

stim = PropertyStimulus(siggen::E8257D, Frequency)
for freq in 1e9:1e8:5e9     # 1 GHz to 5 GHz in steps of 100 MHz
    source(stim, freq)
    # measure(something)
end

Easy right?

Note that one may assign whatever fields and constructor one wishes for a newly created Stimulus subtype. Also, note that not all stimuli need to be associated with a physical instrument. For instance, sourcing a DelayStimulus will cause the script to block until a specified time after creation of the DelayStimulus object. Moreover, a Stimulus could also be associated with several instruments. Maybe a stimulus that makes sense for a particular experiment would be to change all gate voltages at once. These gate voltages could of course be sourced by several physical instruments.

Responses

All responses are objects, subtyped from the abstract Response type. Usually a response is associated with a particular instrument. The implementation of each subtype depends on the specific goals of the user: demonstrations of different response being used can be found in the example notebooks.

(put example here)

However, responses need not come from instruments. For test purposes, suppose we want to mimic a measurement by generating random numbers. RandomResponse produces a random number in the unit interval when it is measured. A TimerResponse will measure the time since creation of the TimerResponse object.

Difference between stimuli and instrument properties

Because a stimulus is defined so broadly, the difference between a stimulus and an instrument property is not obvious. While in many cases there is an overlap between stimuli and properties, a stimulus is like a generalized instrument property: sourcing a stimulus may entail configuring zero or more instrument properties, on zero or more different instruments. As was mentioned earlier, a useful stimulus could be to change gate voltages on multiple different instruments all at once.

It is useful to think of a stimulus as something which has a chance to react to what you are measuring. For example, this could be applied voltage, sourced by one or more instruments. The applied voltages would be seen by the device under test, which would respond accordingly. The stimulus could also just be a time delay, provided by the measurement computer. It could even be the number of threads used by Julia for real-time processing.

An instrument property is any persistent setting of an instrument. Tweaking an instrument property could affect the device under test, but it might not. Averaging is a good example. With averaging a measurement may look less noisy, but your device under test doesn't know the difference.