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.
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.
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.
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