See also
An IPython notebook version of this tutorial can be downloaded here:
Basic sequencing
In this tutorial we will demonstrate basic sequencer based operations (see section Sequencer). This includes creating a sequence, consisting of waveforms and a simple Q1ASM program, and executing this sequence synchronously on multiple sequencers.
The sequence is going to consecutively play two waveforms, a gaussian and block with a duration of 20ns each, with an increasing wait period in between them. We will increase the wait period 20ns a 100 times after which the sequence is stopped. The sequence will also trigger marker output 1 at every interval, so that the sequence can be easily monitored on an oscilloscope.
Setup
First, we are going to import the required packages and connect to the instrument.
[1]:
#Set up the environment.
import scipy.signal
import json
import matplotlib.pyplot
import numpy
import os
from qblox_instruments import Pulsar
#Close any existing connections to any Pulsar.
Pulsar.close_all()
#Connect to the Pulsar at default IP address.
pulsar = Pulsar("pulsar", "192.168.0.2")
#Reset the instrument for good measure.
pulsar.reset()
print("Status:")
print(pulsar.get_system_state())
Status:
SystemState(status=<SystemStatus.OKAY: 2>, flags=[])
Generate waveforms
Next, we need to create the gaussian and block waveforms for the sequence.
[2]:
#Waveform parameters
waveform_length = 20 #nanoseconds
#Waveform dictionary (data will hold the samples and index will be used to select the waveforms in the instrument).
waveforms = {
"gaussian": {"data": scipy.signal.gaussian(waveform_length, std=0.12 * waveform_length).tolist(), "index": 0},
"block": {"data": [1.0 for i in range(0, waveform_length)], "index": 1}
}
Let’s plot the waveforms to see what we have created.
[3]:
time = numpy.arange(0, max(map(lambda d: len(d["data"]), waveforms.values())), 1)
fig, ax = matplotlib.pyplot.subplots(1,1, figsize=(10, 10/1.61))
for wf, d in waveforms.items():
ax.plot(time[:len(d["data"])], d["data"], ".-", linewidth=0.5, label=wf)
ax.legend(loc=4)
ax.yaxis.grid()
ax.xaxis.grid()
ax.set_ylabel("Waveform primitive amplitude")
ax.set_xlabel("Time (ns)")
matplotlib.pyplot.draw()
matplotlib.pyplot.show()
Create Q1ASM program
Now that we have the waveforms for the sequence, we need a Q1ASM program that sequences the waveforms as previously described.
[4]:
#Sequence program.
seq_prog = """
move 100,R0 #Loop iterator.
move 20,R1 #Initial wait period in ns.
wait_sync 4 #Wait for sequencers to synchronize and then wait another 4ns.
loop: set_mrk 1 #Set marker output 1.
play 0,1,4 #Play a gaussian and a block on output path 0 and 1 respectively and wait 4ns.
set_mrk 0 #Reset marker output 1.
upd_param 16 #Update parameters and wait the remaining 16ns of the waveforms.
wait R1 #Wait period.
play 1,0,20 #Play a block and a gaussian on output path 0 and 1 respectively and wait 20ns.
wait 1000 #Wait a 1us in between iterations.
add R1,20,R1 #Increase wait period by 20ns.
loop R0,@loop #Subtract one from loop iterator.
stop #Stop the sequence after the last iteration.
"""
Upload sequence
Now that we have the waveforms and Q1ASM program, we can combine them in a sequence stored in a JSON file.
[5]:
#Add sequence to single dictionary and write to JSON file.
seqeunce = {"waveforms": waveforms, "weights": {}, "acquisitions": {}, "program": seq_prog}
with open("sequence.json", 'w', encoding='utf-8') as file:
json.dump(seqeunce, file, indent=4)
file.close()
Let’s write the JSON file to the instruments. We will use sequencer 0 and 1, which will drive outputs \(\text{O}^{[1-2]}\) and \(\text{O}^{[3-4]}\) respectively.
[6]:
#Upload sequence.
pulsar.sequencer0.sequence("sequence.json")
pulsar.sequencer1.sequence("sequence.json")
Play sequence
The sequence has been uploaded to the instrument. Now we need to configure the sequencers in the instrument to use the wait_sync
instruction at the start of the Q1ASM program to synchronize.
[7]:
#Configure the sequencers to synchronize.
pulsar.sequencer0.sync_en(True)
pulsar.sequencer1.sync_en(True)
#Map sequencers to specific outputs (but first disable all sequencer connections).
for sequencer in pulsar.sequencers:
for out in range(0, 4):
if hasattr(sequencer, "channel_map_path{}_out{}_en".format(out%2, out)):
sequencer.set("channel_map_path{}_out{}_en".format(out%2, out), False)
#If it is a QRM, we only map sequencer 0 to the outputs.
pulsar.sequencer0.channel_map_path0_out0_en(True)
pulsar.sequencer0.channel_map_path1_out1_en(True)
if pulsar.is_qcm_type:
pulsar.sequencer1.channel_map_path0_out2_en(True)
pulsar.sequencer1.channel_map_path1_out3_en(True)
Now let’s start the sequence. If you want to observe the sequence, this is the time to connect an oscilloscope to marker output 1 and one or more of the four outputs. Configure the oscilloscope to trigger on the marker output 1.
[8]:
#Arm and start both sequencers.
pulsar.arm_sequencer(0)
pulsar.arm_sequencer(1)
pulsar.start_sequencer()
#Print status of both sequencers.
print("Status:")
print(pulsar.get_sequencer_state(0))
print(pulsar.get_sequencer_state(1))
Status:
SequencerState(status=<SequencerStatus.STOPPED: 5>, flags=[])
SequencerState(status=<SequencerStatus.STOPPED: 5>, flags=[])
Stop
Finally, let’s stop the sequencers if they haven’t already and close the instrument connection.
[9]:
#Stop both sequencers.
pulsar.stop_sequencer()
#Print status of both sequencers (should now say it is stopped).
print("Status:")
print(pulsar.get_sequencer_state(0))
print(pulsar.get_sequencer_state(1))
print()
#Print an overview of the instrument parameters.
print("Snapshot:")
pulsar.print_readable_snapshot(update=True)
#Close the instrument connection.
pulsar.close()
Status:
SequencerState(status=<SequencerStatus.STOPPED: 5>, flags=[<SequencerStatusFlags.FORCED_STOP: 2>])
SequencerState(status=<SequencerStatus.STOPPED: 5>, flags=[<SequencerStatusFlags.FORCED_STOP: 2>])
Snapshot:
pulsar:
parameter value
--------------------------------------------------------------------------------
IDN : {'manufacturer': 'qblox', 'model': 'pulsar_qr...
in0_gain : -6 (dB)
in1_gain : -6 (dB)
out0_offset : 0 (V)
out1_offset : 0 (V)
reference_source : internal
scope_acq_avg_mode_en_path0 : False
scope_acq_avg_mode_en_path1 : False
scope_acq_sequencer_select : 0
scope_acq_trigger_level_path0 : 0
scope_acq_trigger_level_path1 : 0
scope_acq_trigger_mode_path0 : sequencer
scope_acq_trigger_mode_path1 : sequencer
pulsar_sequencer0:
parameter value
--------------------------------------------------------------------------------
channel_map_path0_out0_en : True
channel_map_path1_out1_en : True
cont_mode_en_awg_path0 : False
cont_mode_en_awg_path1 : False
cont_mode_waveform_idx_awg_path0 : 0
cont_mode_waveform_idx_awg_path1 : 0
demod_en_acq : False
discretization_threshold_acq : 0
gain_awg_path0 : 1
gain_awg_path1 : 1
integration_length_acq : 1024
marker_ovr_en : False
marker_ovr_value : 0
mixer_corr_gain_ratio : 1
mixer_corr_phase_offset_degree : -0
mod_en_awg : False
nco_freq : 0 (Hz)
nco_phase_offs : 0 (Degrees)
offset_awg_path0 : 0
offset_awg_path1 : 0
phase_rotation_acq : 0 (Degrees)
sequence : sequence.json
sync_en : True
upsample_rate_awg_path0 : 0
upsample_rate_awg_path1 : 0
pulsar_sequencer1:
parameter value
--------------------------------------------------------------------------------
channel_map_path0_out0_en : False
channel_map_path1_out1_en : False
cont_mode_en_awg_path0 : False
cont_mode_en_awg_path1 : False
cont_mode_waveform_idx_awg_path0 : 0
cont_mode_waveform_idx_awg_path1 : 0
demod_en_acq : False
discretization_threshold_acq : 0
gain_awg_path0 : 1
gain_awg_path1 : 1
integration_length_acq : 1024
marker_ovr_en : False
marker_ovr_value : 0
mixer_corr_gain_ratio : 1
mixer_corr_phase_offset_degree : -0
mod_en_awg : False
nco_freq : 0 (Hz)
nco_phase_offs : 0 (Degrees)
offset_awg_path0 : 0
offset_awg_path1 : 0
phase_rotation_acq : 0 (Degrees)
sequence : sequence.json
sync_en : True
upsample_rate_awg_path0 : 0
upsample_rate_awg_path1 : 0
pulsar_sequencer2:
parameter value
--------------------------------------------------------------------------------
channel_map_path0_out0_en : False
channel_map_path1_out1_en : False
cont_mode_en_awg_path0 : False
cont_mode_en_awg_path1 : False
cont_mode_waveform_idx_awg_path0 : 0
cont_mode_waveform_idx_awg_path1 : 0
demod_en_acq : False
discretization_threshold_acq : 0
gain_awg_path0 : 1
gain_awg_path1 : 1
integration_length_acq : 1024
marker_ovr_en : False
marker_ovr_value : 0
mixer_corr_gain_ratio : 1
mixer_corr_phase_offset_degree : -0
mod_en_awg : False
nco_freq : 0 (Hz)
nco_phase_offs : 0 (Degrees)
offset_awg_path0 : 0
offset_awg_path1 : 0
phase_rotation_acq : 0 (Degrees)
sequence : None
sync_en : False
upsample_rate_awg_path0 : 0
upsample_rate_awg_path1 : 0
pulsar_sequencer3:
parameter value
--------------------------------------------------------------------------------
channel_map_path0_out0_en : False
channel_map_path1_out1_en : False
cont_mode_en_awg_path0 : False
cont_mode_en_awg_path1 : False
cont_mode_waveform_idx_awg_path0 : 0
cont_mode_waveform_idx_awg_path1 : 0
demod_en_acq : False
discretization_threshold_acq : 0
gain_awg_path0 : 1
gain_awg_path1 : 1
integration_length_acq : 1024
marker_ovr_en : False
marker_ovr_value : 0
mixer_corr_gain_ratio : 1
mixer_corr_phase_offset_degree : -0
mod_en_awg : False
nco_freq : 0 (Hz)
nco_phase_offs : 0 (Degrees)
offset_awg_path0 : 0
offset_awg_path1 : 0
phase_rotation_acq : 0 (Degrees)
sequence : None
sync_en : False
upsample_rate_awg_path0 : 0
upsample_rate_awg_path1 : 0
pulsar_sequencer4:
parameter value
--------------------------------------------------------------------------------
channel_map_path0_out0_en : False
channel_map_path1_out1_en : False
cont_mode_en_awg_path0 : False
cont_mode_en_awg_path1 : False
cont_mode_waveform_idx_awg_path0 : 0
cont_mode_waveform_idx_awg_path1 : 0
demod_en_acq : False
discretization_threshold_acq : 0
gain_awg_path0 : 1
gain_awg_path1 : 1
integration_length_acq : 1024
marker_ovr_en : False
marker_ovr_value : 0
mixer_corr_gain_ratio : 1
mixer_corr_phase_offset_degree : -0
mod_en_awg : False
nco_freq : 0 (Hz)
nco_phase_offs : 0 (Degrees)
offset_awg_path0 : 0
offset_awg_path1 : 0
phase_rotation_acq : 0 (Degrees)
sequence : None
sync_en : False
upsample_rate_awg_path0 : 0
upsample_rate_awg_path1 : 0
pulsar_sequencer5:
parameter value
--------------------------------------------------------------------------------
channel_map_path0_out0_en : False
channel_map_path1_out1_en : False
cont_mode_en_awg_path0 : False
cont_mode_en_awg_path1 : False
cont_mode_waveform_idx_awg_path0 : 0
cont_mode_waveform_idx_awg_path1 : 0
demod_en_acq : False
discretization_threshold_acq : 0
gain_awg_path0 : 1
gain_awg_path1 : 1
integration_length_acq : 1024
marker_ovr_en : False
marker_ovr_value : 0
mixer_corr_gain_ratio : 1
mixer_corr_phase_offset_degree : -0
mod_en_awg : False
nco_freq : 0 (Hz)
nco_phase_offs : 0 (Degrees)
offset_awg_path0 : 0
offset_awg_path1 : 0
phase_rotation_acq : 0 (Degrees)
sequence : None
sync_en : False
upsample_rate_awg_path0 : 0
upsample_rate_awg_path1 : 0