Skip to content

Fast conditional playback based on DIO

In many experiments it's essential to perform conditional playback based on a external event. The PQSC and QHub can be used to create closed loop experiment with low-latency feedback based on the qubit readout results acquired by a QA.

If the source of feedback is a instruments not provided by Zurich Instruments, such feedback can be given to the DIO port of the HDAWG. The HDAWG can then perform conditional playback based on the values provided there.

To setup conditional playback, we need to setup few things. All the following code is in Python using the zhinst-toolkit library or seqc.

Define the valid condition

The DIO interface is continuously sampled, but due its parallel nature, a pin need to be used to specify when the signals are stable and can be used. This is called valid signal. Moreover, we can specify if we want this signal to be high or low, typically is the first.

hdawg.awgs[AWG_INDEX].dio.valid.polarity("high")
hdawg.awgs[AWG_INDEX].dio.valid.index(VALID_BIT_INDEX)

Define the masking

The DIO interface offers 32 bidirectional IOs. Typically, only few of them are used by one AWG to perform conditional playback and so they should be masked. Masking is done by a fixed right-shift followed by a binary mask: (word >> shift) & mask. For example, to look only at bits 3 and 4, we can set them as follow:

hdawg.awgs[AWG_INDEX].dio.mask.shift(3)
hdawg.awgs[AWG_INDEX].dio.mask.value(0b11)

Define the waveform table

The waveform table is the set of waveform that can be used for conditional playback. The output of the masking operation is used to address and play a waveform. There are two ways of defining the waveform table

Inside of the seqc with setWaveDIO

The instruction setWaveDIO can be used to populate the waveform table. The first index is the table index, while the others define the waveforms and their outputs. Only conditional waveform playback can be done, no other conditional command can be executed.

//setWaveDIO(index, channel, waveform, rate)
setWaveDIO(0, 1, ones(32));                                    //index == 0, output a square pulse on channel 1
setWaveDIO(1, 1, 2, ramp(128, -1.0, 1.0));                     //index == 1, output a ramp pulse on both channel 1 and 2
setWaveDIO(2, 1, gauss(256, 128, 32), 2, drag(256, 128, 32));  //index == 2, output a gauss on channel 1 and a drag on channel 2

This method has been removed in release 24.07 and the command table is recommended as replacement.

Command table

The command table is a extended waveform table, where real-time commands to control the AWG can be executed together with the waveform playback. It is defined outside the seqc, typically using the helper class in zhinst-toolkit (recommended) or uploaded directly as JSON.

See the to see how to define a command table. The example above using setWaveDIO can be done as follow:

seq_program = """
//Waveform definitions
//assignWaveIndex(waveform, index)
assignWaveIndex(1, ones(32), 0);                                    //index == 0, output a square pulse on channel 1
assignWaveIndex(1, 2, ramp(128, -1.0, 1.0), 1);                     //index == 1, output a ramp pulse on both channel 1 and 2
assignWaveIndex(1, gauss(256, 128, 32), 2, drag(256, 128, 32), 2);  //index == 2, output a gauss on channel 1 and a drag on channel 2
"""

## Load the sequence
awg.load_sequencer_program(seqc_program)

## Initialize command table
ct_schema = awg.commandtable.load_validation_schema()
ct = CommandTable(ct_schema)

#Create a command table with identical ct indices and wfm indices
for index in range(3):
    ct_index = index
    wfm_index = index
    ct.table[ct_index].waveform.index = wfm_index

## Upload command table
awg.commandtable.upload_to_device(ct)

Note that now we have two kind of indices that should not be confused: * The waveform index, specified as last argument in assignWaveIndex * The command table index

While in the example they are identical, they don't have to. You can also have multiple command tables entries pointing to the same waveform.

This method has been introduced in release 20.07 and is the only one available since release 24.07. It has also the advantage to be compatible with SHFSG/SHFQC, since the instruction setWaveDIOwas never available on these instruments.

Conditional playback

The conditional playback can be executed with the instruction playWaveDIO. Typically, this should be executed after a trigger or after some other playback:

while(true) {
  waitDIOTrigger();
  playWaveDIO();
}