See also
An IPython notebook version of this tutorial can be downloaded here:
Binned acquisition
In this tutorial we will demonstrate the sequencer based acquisition binning procedure. The binning process is applied on the input path after real-time demodulation, (weighed) integration, IQ rotation and discretization. It allows storing both the integration and discretization results on the fly without intervention of the host PC in up to 131072 bins. It also allows averaging those bins on the fly as well (see section Acquisition). We will show this by using a Pulsar QRM and directly connecting outputs \(\text{O}^{[1-2]}\) to inputs \(\text{I}^{[1-2]}\) respectively. We will then use the Pulsar QRM’s sequencers to sequence waveforms on the outputs and simultaneously acquire the resulting waveforms on the inputs.
Setup
First, we are going to import the required packages and connect to the instrument.
[1]:
#Set up the environment.
import scipy.signal
import math
import json
import matplotlib.pyplot
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 and weights
Next, we need to create the waveforms used by the sequence for playback on the outputs as well as weights used by the sequence for weighed integrations.
[2]:
#Waveform and weight parameters
waveform_weight_length = 600 #nanoseconds
#Waveform dictionary (data will hold the samples and index will be used to select the waveforms in the instrument).
waveforms_weights = {
"gaussian": {"data": scipy.signal.gaussian(waveform_weight_length, std=0.12 * waveform_weight_length).tolist(), "index": 0},
"sine": {"data": [math.sin((2*math.pi/waveform_weight_length)*i) for i in range(0, waveform_weight_length)], "index": 1},
"block": {"data": [1.0 for _ in range(0, waveform_weight_length)], "index": 2}
}
Specify acquisitions
We also need to specify the acquisitions so that the instrument can allocate the required memory for it’s acquisition list. In this case we will create 4 acquisition specifications that each create multiple bins.
[3]:
#Acquisitions
acquisitions = {"non_weighed": {"num_bins": 10,
"index": 0},
"weighed": {"num_bins": 10,
"index": 1},
"large": {"num_bins": 131072,
"index": 2},
"avg": {"num_bins": 10,
"index": 3}}
Create Q1ASM program
Now that we have the waveform and acquisition specifications for the sequence, we need a simple Q1ASM program that sequences the waveforms and triggers the acquisitions. In this case we will simply trigger 10 non-weighed acquisitions and store each acquisition in a separate bin.
[4]:
#Sequence program.
seq_prog = """
move 0,R0 #Loop iterator.
nop
loop: acquire 0,R0,1200 #Acquire bins and store them in "non_weighed" acquisition.
add R0,1,R0 #Increment iterator
nop #Wait a cycle for R0 to be available.
jlt R0,10,@loop #Run until number of iterations is done.
stop #Stop.
"""
Upload sequence
Now that we have the waveform, weights and acquisition specifications and Q1ASM program, we can combine them in a sequence stored in a JSON file.
[5]:
#Add sequence program, waveforms, weights and acquistitions to single dictionary and write to JSON file.
sequence = {"waveforms": waveforms_weights, "weights": waveforms_weights, "acquisitions": acquisitions, "program": seq_prog}
with open("sequence.json", 'w', encoding='utf-8') as file:
json.dump(sequence, file, indent=4)
file.close()
Let’s write the JSON file to the instruments. We will use sequencer 0, which will drive outputs \(\text{O}^{[1-2]}\) and acquire on inputs \(\text{I}^{[1-2]}\).
[6]:
#Upload sequence.
pulsar.sequencer0.sequence("sequence.json")
Play sequence
The sequence has been uploaded to the instrument. Now we need to configure the sequencers. To keep it simple we will set a DC signal on the outputs of the instrument by enabling the sequencer offsets and disabling the modulation. These DC signals will then be acquired through the inputs, so we will also disable the demodulation on the input path. Furthermore, since we are running non-weighed integrations we need to specify the integration length. This integration length will be used for every non-weighed integration moving forward. We will also put the integration result phase rotation to 0 degrees and discretation threshold to 0.
[7]:
#Configure scope mode
pulsar.scope_acq_sequencer_select(0)
pulsar.scope_acq_trigger_mode_path0("sequencer")
pulsar.scope_acq_trigger_mode_path1("sequencer")
#Configure the sequencer
pulsar.sequencer0.offset_awg_path0(0.5)
pulsar.sequencer0.offset_awg_path1(0.5)
pulsar.sequencer0.mod_en_awg(False)
pulsar.sequencer0.demod_en_acq(False)
pulsar.sequencer0.integration_length_acq(1000)
pulsar.sequencer0.phase_rotation_acq(0)
pulsar.sequencer0.discretization_threshold_acq(0)
#Map sequencer to specific outputs (but first disable all sequencer connections)
for sequencer in pulsar.sequencers:
for out in range(0, 2):
sequencer.set("channel_map_path{}_out{}_en".format(out%2, out), False)
pulsar.sequencer0.channel_map_path0_out0_en(True)
pulsar.sequencer0.channel_map_path1_out1_en(True)
Now let’s start the sequence.
[8]:
#Arm and start sequencer.
pulsar.arm_sequencer(0)
pulsar.start_sequencer()
#Print status of sequencer.
print("Status:")
print(pulsar.get_sequencer_state(0, 1))
Status:
SequencerState(status=<SequencerStatus.STOPPED: 5>, flags=[<SequencerStatusFlags.ACQ_SCOPE_DONE_PATH_0: 9>, <SequencerStatusFlags.ACQ_SCOPE_DONE_PATH_1: 12>, <SequencerStatusFlags.ACQ_BINNING_DONE: 15>])
Retrieve acquisition
Next we will have a quick look at the input signal, so that we can compare it to the integration results. Since we are integrating over a DC signal we are expecting the integration results to be roughly equal to the average DC value.
[9]:
#Wait for the sequencer to stop with a timeout period of one minute.
pulsar.get_acquisition_state(0, 1)
#Move acquisition data from temporary memory to acquisition list.
pulsar.store_scope_acquisition(0, "non_weighed")
#Get acquisition list from instrument.
non_weighed_acq = pulsar.get_acquisitions(0)["non_weighed"]
#Plot acquired signal on both inputs.
fig, ax = matplotlib.pyplot.subplots(1, 1, figsize=(15, 15/2/1.61))
ax.plot(non_weighed_acq["acquisition"]["scope"]["path0"]["data"][0:1000])
ax.plot(non_weighed_acq["acquisition"]["scope"]["path1"]["data"][0:1000])
ax.set_xlabel('Time (ns)')
ax.set_ylabel('Relative amplitude')
matplotlib.pyplot.show()
To check if the integration results match with what we expect, we need to divide the integration results by the integration length which was set through the corresponding QCoDeS parameter. Note that the ‘valid’ key of the dictionary indicates if the bin was actually set during the sequence.
[10]:
int_len = pulsar.sequencer0.integration_length_acq()
bins = non_weighed_acq["acquisition"]["bins"]
bins["integration"]["path0"] = [(val/int_len) for val in bins["integration"]["path0"]]
bins["integration"]["path1"] = [(val/int_len) for val in bins["integration"]["path1"]]
bins
[10]:
{'integration': {'path0': [0.2635559355153884,
0.26339960918417193,
0.26320078163165606,
0.263257449926722,
0.26332535417684416,
0.26319589643380553,
0.263085979482169,
0.2630996580361505,
0.2630850024425989,
0.26313629702002933],
'path1': [0.26191157791890574,
0.26181485100146556,
0.2616990718124084,
0.26159355153883734,
0.261609672691744,
0.2615451880801173,
0.261352711284807,
0.26146067415730334,
0.2614621397166585,
0.2616468001954079]},
'threshold': [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
'avg_cnt': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}
Weighed acquisition
Next we will show weighed integrations. To do this, we will need to modify the sequence program slightly and reupload the program. We will be using a the gaussian weight to integrate over input path 0 and the sine weight to integrate over input path 1. The integration length of a weighed integration is determined by the weight length.
[11]:
#Sequence program.
seq_prog = """
move 0,R0 #Loop iterator.
move 0,R1 #Weight for path 0.
move 1,R2 #Weight for path 1.
nop
loop: acquire_weighed 1,R0,R1,R2,1200 #Acquire bins and store them in "weighed" acquisition.
add R0,1,R0 #Increment iterator
nop #Wait a cycle for R0 to be available.
jlt R0,10,@loop #Run until number of iterations is done.
stop #Stop.
"""
[12]:
#Add sequence program, waveforms, weights and acquistitions to single dictionary and write to JSON file.
sequence = {"waveforms": waveforms_weights, "weights": waveforms_weights, "acquisitions": acquisitions, "program": seq_prog}
with open("sequence.json", 'w', encoding='utf-8') as file:
json.dump(sequence, file, indent=4)
file.close()
[13]:
#Upload sequence.
pulsar.sequencer0.sequence("sequence.json")
Let’s start the sequence and retrieve the results.
[14]:
#Arm and start sequencer.
pulsar.arm_sequencer(0)
pulsar.start_sequencer()
#Print status of sequencer.
print("Status:")
print(pulsar.get_sequencer_state(0, 1))
Status:
SequencerState(status=<SequencerStatus.STOPPED: 5>, flags=[<SequencerStatusFlags.ACQ_SCOPE_DONE_PATH_0: 9>, <SequencerStatusFlags.ACQ_SCOPE_DONE_PATH_1: 12>, <SequencerStatusFlags.ACQ_BINNING_DONE: 15>])
[15]:
#Wait for the sequencer to stop with a timeout period of one minute.
pulsar.get_acquisition_state(0, 1)
#Get acquisition list from instrument.
weighed_acq = pulsar.get_acquisitions(0)["weighed"]
To check if the integration results match with what we expect, we need to divide the integration results by the integration length again. In this case the integration length is determined by the length of the weights.
[16]:
int_len = waveform_weight_length
bins = weighed_acq["acquisition"]["bins"]
bins["integration"]["path0"] = [(val/int_len) for val in bins["integration"]["path0"]]
bins["integration"]["path1"] = [(val/int_len) for val in bins["integration"]["path1"]]
bins
[16]:
{'integration': {'path0': [0.07916094837592429,
0.07916951079687592,
0.07911602221591651,
0.07907064142464812,
0.07909695037486993,
0.07909239292518981,
0.07909721010733992,
0.07913038148375574,
0.07913985833801289,
0.07913173225170073],
'path1': [-1.0347534772927397e-05,
4.001391497814707e-07,
-9.497219192010073e-05,
-8.144263607535249e-05,
-7.67765999261612e-05,
-6.0858937267011425e-05,
-1.8570672727780403e-05,
-2.4567589190260756e-05,
-7.955410656922681e-05,
-1.7491569831799164e-05]},
'threshold': [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
'avg_cnt': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}
Large number of bins
The Pulsar QRM supports up to 131072 bins. To show that, we need to change the program slightly again. We will use the non-weighed acquisition program, but now we will loop over the maximum number of acquisitions while storing each result in a separate bin.
[17]:
#Sequence program.
seq_prog = """
move 0,R0 #Loop iterator.
nop
loop: acquire 2,R0,1200 #Acquire bins and store them in "large" acquisition.
add R0,1,R0 #Increment iterator
nop #Wait a cycle for R0 to be available.
jlt R0,131072,@loop #Run until number of iterations is done.
stop #Stop.
"""
[18]:
#Add sequence program, waveforms, weights and acquistitions to single dictionary and write to JSON file.
sequence = {"waveforms": waveforms_weights, "weights": waveforms_weights, "acquisitions": acquisitions, "program": seq_prog}
with open("sequence.json", 'w', encoding='utf-8') as file:
json.dump(sequence, file, indent=4)
file.close()
[19]:
#Upload sequence.
pulsar.sequencer0.sequence("sequence.json")
Let’s start the sequence and retrieve the results.
[20]:
#Arm and start sequencer.
pulsar.arm_sequencer(0)
pulsar.start_sequencer()
#Print status of sequencer.
print("Status:")
print(pulsar.get_sequencer_state(0, 1))
Status:
SequencerState(status=<SequencerStatus.STOPPED: 5>, flags=[<SequencerStatusFlags.ACQ_SCOPE_DONE_PATH_0: 9>, <SequencerStatusFlags.ACQ_SCOPE_DONE_PATH_1: 12>, <SequencerStatusFlags.ACQ_BINNING_DONE: 15>])
[21]:
#Wait for the sequencer to stop with a timeout period of one minute.
pulsar.get_acquisition_state(0, 1)
#Get acquisition list from instrument.
large_acq = pulsar.get_acquisitions(0)["large"]
Since the number of bins is now to large to simply print, we will check the number of bins and we will check the bins for NaN values which indicate that a bin is not written.
[22]:
int_len = pulsar.sequencer0.integration_length_acq()
bins = large_acq["acquisition"]["bins"]
bins["integration"]["path0"] = [(val/int_len) for val in bins["integration"]["path0"]]
bins["integration"]["path1"] = [(val/int_len) for val in bins["integration"]["path1"]]
print("Number of bins: {}".format(len(bins["avg_cnt"])))
for it, val in enumerate(bins["integration"]["path0"]):
if math.isnan(val):
Exception("NaN found at index {}.".format(it))
for it, val in enumerate(bins["integration"]["path0"]):
if math.isnan(val):
Exception("NaN found at index {}.".format(it))
for it, val in enumerate(bins["integration"]["path0"]):
if math.isnan(val):
Exception("NaN found at index {}.".format(it))
print("All values are valid.")
Number of bins: 131072
All values are valid.
We will also plot the integration results in every bin to visualize the contents.
[23]:
#Plot bins
fig, ax = matplotlib.pyplot.subplots(1, 1, figsize=(15, 15/2/1.61))
ax.plot(bins["integration"]["path0"])
ax.plot(bins["integration"]["path1"])
ax.set_xlabel('Bin index')
ax.set_ylabel('Relative amplitude')
matplotlib.pyplot.show()
Averaging
As you might have noticed, the acquisition results also contain an average counter. This average counter reflects the number of times a bin as been averaged during the sequence. Each time a the sequence writes to the same bin the results are automatically accumulated and the average counter is increased. Upon retrieval of the acquisition results, each result is divided by the average counter and therefore automatically averaged. To show this, we will change the sequence one last time. This time we will average 10 bins a 1000 times each.
[24]:
#Sequence program.
seq_prog = """
move 0,R1 #Average iterator.
avg: move 0,R0 #Bin iterator.
nop
loop: acquire 3,R0,1200 #Acquire bins and store them in "avg" acquisition.
add R0,1,R0 #Increment bin iterator
nop #Wait a cycle for R0 to be available.
jlt R0,10,@loop #Run until number of avg iterations is done.
add R1,1,R1 #Increment avg iterator
nop #Wait a cycle for R1 to be available.
jlt R1,1000,@avg #Run until number of average iterations is done.
stop #Stop.
"""
[25]:
#Add sequence program, waveforms, weights and acquistitions to single dictionary and write to JSON file.
sequence = {"waveforms": waveforms_weights, "weights": waveforms_weights, "acquisitions": acquisitions, "program": seq_prog}
with open("sequence.json", 'w', encoding='utf-8') as file:
json.dump(sequence, file, indent=4)
file.close()
[26]:
#Upload sequence.
pulsar.sequencer0.sequence("sequence.json")
Let’s start the sequence and retrieve the results.
[27]:
#Arm and start sequencer.
pulsar.arm_sequencer(0)
pulsar.start_sequencer()
#Print status of sequencer.
print("Status:")
print(pulsar.get_sequencer_state(0, 1))
Status:
SequencerState(status=<SequencerStatus.STOPPED: 5>, flags=[<SequencerStatusFlags.ACQ_SCOPE_DONE_PATH_0: 9>, <SequencerStatusFlags.ACQ_SCOPE_DONE_PATH_1: 12>, <SequencerStatusFlags.ACQ_BINNING_DONE: 15>])
Note that the average count of each bin is now set to a 1000.
[28]:
#Wait for the sequencer to stop with a timeout period of one minute.
pulsar.get_acquisition_state(0, 1)
#Get acquisition list from instrument.
avg_acq = pulsar.get_acquisitions(0)["avg"]
[29]:
int_len = pulsar.sequencer0.integration_length_acq()
bins = avg_acq["acquisition"]["bins"]
bins["integration"]["path0"] = [(val/int_len) for val in bins["integration"]["path0"]]
bins["integration"]["path1"] = [(val/int_len) for val in bins["integration"]["path1"]]
bins
[29]:
{'integration': {'path0': [0.2623417083536883,
0.262341149975574,
0.26234430679042503,
0.26233862139716657,
0.26234086223742065,
0.26233900097703955,
0.26234284171958966,
0.26233949340498286,
0.2623389868099658,
0.2623407870053737],
'path1': [0.26079631900341965,
0.26079322129946264,
0.2607985070835369,
0.26079389838788475,
0.26079962725940403,
0.26079663800683933,
0.26079394968246217,
0.26080307376648754,
0.2607952457254519,
0.2607946853932584]},
'threshold': [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
'avg_cnt': [1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000]}
Stop
Finally, let’s stop the sequencers if they haven’t already and close the instrument connection.
[30]:
#Stop sequencer.
pulsar.stop_sequencer()
#Print status of sequencer.
print("Status:")
print(pulsar.get_sequencer_state(0))
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>, <SequencerStatusFlags.ACQ_SCOPE_DONE_PATH_0: 9>, <SequencerStatusFlags.ACQ_SCOPE_DONE_PATH_1: 12>, <SequencerStatusFlags.ACQ_BINNING_DONE: 15>])
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 : 1000
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.49998
offset_awg_path1 : 0.49998
phase_rotation_acq : 0 (Degrees)
sequence : sequence.json
sync_en : False
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 : None
sync_en : False
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