Feedback

Qblox’s instruments support feedback using an integrated trigger network of four parallel trigger lines that interconnect all sequencers within the system and allows the user to create low-latency feedback sequences for these sequencers. Additionaly, the external trigger input on each instrument is connected to the same trigger network. This allows other instruments to also contribute to any feedback sequence.

Note

The trigger network needs to be calibrated. Currently, this calibration is ran 40 seconds after the instrument boots. Please refrain from running feedback sequences before that time. The reset() method, can be used to rerun calibration if required.

Overview

The figure below shows the four-line trigger network connecting the external trigger input and all sequencers. Access to this trigger network is address-based. When triggering the network using the external trigger input or any of the sequencers, the resulting trigger is converted into one of fifteen configurable addresses (i.e. 1 to 15). In turn, any sequencer can subscribe to one or multiple addresses and react to those incoming triggers using custom sequencer instructions to modify sequence flow (e.g. set_cond, latch_en, latch_rst) (see section Instructions). Of course, convential trigger synchronization remains possible as well, as discussed in the Trigger section.

Trigger network

Triggering

The trigger network operates on a 20ns timegrid. This timegrid is started/aligned during module synchronization using the wait_sync instruction. Once synchronized, triggers are sent on the nearest timegrid point in the future. In other words, triggers that are not sent on this timegrid get a maximum time penalty of 16ns. Any trigger that is sent on the trigger network takes 200ns (or 10 timegrid points) to propagate to any receiver on the trigger network. A trigger can be send on the trigger network every 240ns (or 12 timegrid points). The figure below shows an example of the trigger network timegrid.

Trigger network timegrid

Sending triggers on the trigger network can be done from the three following sources:

Thresholded acquisitions

Any thresholded acquisition result, as discussed in the Thresholded acquisitions section, can send a trigger on the trigger network. When the acquisition completes, the result is mapped to the trigger network following the next steps.

First, the mapping needs be enabled using the sequencer#.thresholded_acq_trigger_en() parameter. Next, a trigger address with which the trigger is send on the network needs to be selected using the sequencer#.thresholded_acq_trigger_address() parameter. Remember that this address needs to be used by the receiving sequencer to handle this trigger. Finally, the polarity of the result needs to be selected using the sequencer#.thresholded_acq_trigger_invert() parameter. If you want to set a trigger when the acquisition result is 1, the parameter must be set to false and vice versa.

TTL triggers

When acquiring TTL triggers, as discussed in the TTL trigger acquisitions section, any trigger detected during the acquisition period can be mapped to the trigger network as well. This effectively means that multiple triggers can be send on the network during a single acquisition period. However, remember that the trigger network can only be retriggered every 240ns, so the rate of the TTL triggers on the input must be limited to the maximum trigger network rate.

During a TTL trigger acquisition, all detected triggers are treated like thresholded acquisition results. Mapping the TTL triggers on the trigger network is therefore identical to mapping thresholded acquisition results on the network and uses the same parameters.

External trigger input

As mentioned at the start of this page, the external trigger input can also be mapped to the trigger network following the next steps. First, the mapping needs be enabled using the ext_trigger_input_trigger_en() parameter. Next, a trigger address with which the trigger is send on the network needs to be selected using the ext_trigger_input_trigger_address() parameter. Once sent on the trigger network, the external trigger behaves identical to any other trigger source and has the same propagation delay and trigger rate.

Note that the external trigger input will be sampled with the instrument’s internal clock. If an external trigger signal arrives in that clock’s setup or hold time, it can cause timing jitter on the execution of any related instruction like wait_trigger. Use the ext_trigger_input_delay() parameter to delay the external trigger signal and resolve any time jitter.

Trigger handling

On the receiving side of the trigger network, every sequencer has the basic capability to handle a trigger address by using the wait_trigger instruction and selecting that address as its first argument. On top of that, each sequencer also has more advanced trigger handling capabilities. Every sequencer has a seperate latch/counter combination for each trigger address on the network, from here on referred to as the trigger network address counters. These counters allow counting every triggered address on the network in real-time. These counters are controlled using the latch_en and latch_rst instructions, where the first enables/disables the counters for all trigger addresses and the latter resets the counters for all addresses back to zero (see section Instructions).

Once a trigger on the trigger network is captured in the counters, the sequencers can operate on the counter values to create a single boolean (true/false) condition on which to execute real-time instructions or simply skip them. Any real-time instruction following the set_cond instruction evaluates this condition and is either executed (when true) or skipped (when false). On a skip, the instruction is replaced by a wait time in nanoseconds as expressed in the else (i.e. fourth) argument of the instruction. This allows creating conditional playback scenarios by setting the else argument to the same duration as the skipped instruction. Alternatively, it allows creating repeat until success scenarios by setting the else argument to a short time (e.g. 4 nanoseconds) and quickly flushing instructions from the pipeline.

The boolean condition itself is based on a comparison between the counters and the sequencer#.trigger#_count_threshold() parameters. Each counter is individually compared (>=) with its associated threshold. The sequencer#.trigger#_threshold_invert() parameter can be used to invert this comparison (<). The results of these static comparisons create a vector of boolean conditions with a true/false indication for each trigger address. Next, the mask (i.e. second) argument of the set_cond instruction is used to select boolean conditions of specific trigger addresses from the vector to operate on. This is how a sequencer subscribes itself to one or multiple trigger addresses. The mask argument is expressed as a decimal value representing a vector of mask bits that in turn each represent a single trigger address (e.g. selecting trigger addresses 1 and 4 requires mask value 2**(1-1)+2**(4-1)=9). Finally, a logical operation, as determined by the operator (i.e. third argument) of the set_cond instruction, is performed on the selected boolean conditions which results in the final boolean condition used by the set_cond instruction. The following figure shows a block diagram of how the boolean condition is determined.

Trigger network conditional

The following table lists the operator argument values and the associated selection and logical operations:

Argument

Select

Operator

Comment

0

AND mask

OR

Return true if any of the selected counters crossed their thresholds

1

AND mask

NOR

Return true if none of the selected counters crossed their threshold

2

OR NOT(mask)

AND

Return true if all of the selected counters crossed their threshold

3

OR NOT(mask)

NAND

Return true if any of the selected counters did not cross their threshold

4

AND mask

XOR

Return true if an odd number of selected counters crossed their threshold

5

AND mask

XNOR

Return true if an even number of selected counters crossed their threshold

Examples

This section provides a few simplified feedback examples that can easily be adapted to your own needs.

Conditional playback

In this example sequencer 0 performs a measurement and sequencer 1 performs a conditional playback based on the measurement result.

Settings:

sequencer0.thresholded_acq_trigger_en(True)
sequencer0.thresholded_acq_trigger_address(12)
sequencer0.thresholded_acq_trigger_invert(False)

sequencer1.trigger12_count_threshold(1)
sequencer1.trigger12_threshold_invert(False)

Sequencer 0 (Readout):

wait_sync 4       #Wait for sequencers to synchronize

play 0,0,4        #Play readout pulse
wait 148          #Wait for readout pulse to return
acquire 0,0,100   #Acquire readout pulse

stop              #Stop program

Sequencer 1 (Playback):

wait_sync 4             #Wait for sequencers to synchronize

set_latch_en 1,4        #Latch any trigger
latch_rst 1000          #Reset the trigger network address counters, then wait on trigger address 12

set_cond 1,2048,0,4     #Play waveform if trigger is seen (condition: OR T12)
play 0,0,20             #""
set_cond 1,2048,1,4     #Play waveform if trigger is NOT seen (condition: NOR T12)
play 1,1,20             #""

stop                    #Stop program

Repeat until success

In this example sequencer 0 repeatedly measures the state of the qubit. When the qubit state reaches zero, it flushes the pipeline and continues it’s schedule.

Settings:

sequencer0.thresholded_acq_trigger_en(True)
sequencer0.thresholded_acq_trigger_address(12)
sequencer0.thresholded_acq_trigger_invert(False)

sequencer0.trigger12_count_threshold(1)
sequencer0.trigger12_threshold_invert(False)

Sequencer 0:

      move 10,R0            #Set loop iterator R0
      wait_sync 4           #Wait for sequencers to synchronize
      set_latch_en 1,4      #Latch any trigger

      play 0,0,4            #Play readout pulse
      wait 148              #Wait for readout pulse to return
      acquire 0,0,100       #Acquire readout pulse
      latch_rst 1000        #Reset the trigger network address counters, then wait on trigger address 12

      set_cond 1,2048,0,4   #Execute if trigger is seen else flush (condition: OR T12)
loop: play 0,0,4            #Play readout pulse
      wait 148              #Wait for readout pulse to return
      acquire 0,0,100       #Acquire readout pulse
      latch_rst 1000        #Reset the trigger network address counters, then wait on trigger address 12
      loop R0,@loop         #Loop

      set_cond 0,0,0,4      #Disable conditionality
      play 1,1,20           #Continue program

      stop                  #Stop program

Trigger counting

In this example the trigger network address counters are used to count TTL triggers on the inputs. Sequencer 0 detects the triggers on the input of the device and then counts the resulting triggers on the trigger network. Finally, it plays a waveform if 5 or more triggers are detected.

Settings:

sequencer0.ttl_acq_input_select(0)
sequencer0.ttl_acq_threshold(0.2)
sequencer0.ttl_acq_auto_bin_incr_en(false)

sequencer0.thresholded_acq_trigger_en(True)
sequencer0.thresholded_acq_trigger_address(12)
sequencer0.thresholded_acq_trigger_invert(False)

sequencer0.trigger12_count_threshold(5)
sequencer0.trigger12_threshold_invert(False)

Sequencer 0:

wait_sync 4            #Wait for sequencers to synchronize

set_latch_en 1,4       #Latch any trigger
latch_rst 4            #Reset the trigger network address counters

acquire_ttl 0,0,1,5000 #Acquire input triggers
acquire_ttl 0,0,0,4    #Stop acquiring triggers

set_cond 1,2048,0,20   #Play if 5 triggers have been seen (condition: OR T12)
play 0,0,20            #""

stop                   #Stop program