Introduction¶
The Tektronix AWG70000A series internally use .seqx
files. The QCoDeS driver for the AWGs knows how to compile these files and broadbean knows what QCoDeS need to do so.
Step 1: Make a sequence¶
[1]:
# We make a sequence consisting of a bsic element with:
# a wait time, a ramp up, a sine, a ramp down, and more wait time
# And then we vary the sine frequency
%matplotlib notebook
import numpy as np
import broadbean as bb
from broadbean.plotting import plotter
sine = bb.PulseAtoms.sine
ramp = bb.PulseAtoms.ramp
##########################
# settings
SR = 25e9
t1 = 10e-9 # first wait time (s)
ramp_time = 5e-9 # the ramp time (s)
t_sine = 25e-9 # the sine time (s)
high_level = 0.1 # the high level (V)
sine_amp = 0.05 # the sine amplitude (V)
t2 = 150e-9 # the second wait time (s)
f0 = 1e9 # the base frequency of the sine (Hz)
baseshape = bb.BluePrint()
baseshape.insertSegment(0, ramp, (0, 0), dur=t1)
baseshape.insertSegment(1, ramp, (0, high_level), dur=ramp_time)
baseshape.insertSegment(
2, sine, (f0, sine_amp, high_level, 0), dur=t_sine, name="drive"
)
baseshape.insertSegment(3, ramp, (high_level, 0), dur=ramp_time)
baseshape.insertSegment(4, ramp, (0, 0), dur=t2, name="wait")
baseshape.setSegmentMarker("wait", (0, t_sine), 1)
baseshape.setSegmentMarker("drive", (0, t_sine), 2)
baseshape.setSR(SR)
[2]:
# Check that it looks the way we expect
plotter(baseshape)
[3]:
# Make it into a sequence
baseelem = bb.Element()
baseelem.addBluePrint(1, baseshape)
# Add elements and vary the sine freq.
sine_freqs = np.linspace(1e9, 2e9, 5)
seq = bb.Sequence()
seq.setSR(SR)
# We set each element of the sequence to wait for
# a trigger from trigger input 'A'
for index, freq in enumerate(sine_freqs):
elem = baseelem.copy()
elem.changeArg(1, "drive", "freq", freq)
seq.addElement(index + 1, elem)
seq.setSequencingTriggerWait(index + 1, 1) # 1: trigA, 2: trigB, 3: EXT
# and set the last element to point back to the first one
seq.setSequencingGoto(index + 1, 1)
seq.name = "tutorial_sequence" # the sequence name will be needed later
Step 2: Initialise the driver¶
[4]:
# import and initialise the driver and ensure that the sample
# rate and channel voltage is correct
from qcodes.instrument_drivers.tektronix.AWG70002A import AWG70002A
awg = AWG70002A("awg", "TCPIP0::172.20.2.243::inst0::INSTR")
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
Cell In[4], line 4
1 # import and initialise the driver and ensure that the sample
2 # rate and channel voltage is correct
----> 4 from qcodes.instrument_drivers.tektronix.AWG70002A import AWG70002A
6 awg = AWG70002A("awg", "TCPIP0::172.20.2.243::inst0::INSTR")
ModuleNotFoundError: No module named 'qcodes'
[5]:
awg.sample_rate(SR)
awg.ch1.awg_amplitude(0.5) # this is the peak-to-peak amplitude of the channel
# Now we must update the Sequence object with this information
seq.setChannelAmplitude(1, awg.ch1.awg_amplitude())
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[5], line 1
----> 1 awg.sample_rate(SR)
2 awg.ch1.awg_amplitude(0.5) # this is the peak-to-peak amplitude of the channel
4 # Now we must update the Sequence object with this information
NameError: name 'awg' is not defined
Step 3: Make output for the driver¶
[6]:
# If the sequence has been built correctly, it's a one-liner
seqx_input = seq.outputForSEQXFile()
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
Cell In[6], line 2
1 # If the sequence has been built correctly, it's a one-liner
----> 2 seqx_input = seq.outputForSEQXFile()
File /opt/hostedtoolcache/Python/3.11.10/x64/lib/python3.11/site-packages/broadbean/sequence.py:989, in Sequence.outputForSEQXFile(self)
972 """
973 Generate a tuple matching the call signature of the QCoDeS
974 AWG70000A driver's `makeSEQXFile` function. If channel delays
(...)
985 go_to, wfms, amplitudes, seqname)
986 """
988 # most of the footwork is done by the following function
--> 989 elements = self._prepareForOutputting()
990 # _prepareForOutputting asserts that channel amplitudes and
991 # full sequencing is specified
992 seqlen = len(elements)
File /opt/hostedtoolcache/Python/3.11.10/x64/lib/python3.11/site-packages/broadbean/sequence.py:883, in Sequence._prepareForOutputting(self)
881 ampkey = f"channel{chan}_amplitude"
882 if ampkey not in self._awgspecs.keys():
--> 883 raise KeyError(
884 "No amplitude specified for channel {chan}. Can not continue."
885 )
887 # Apply channel delays.
888 delays = []
KeyError: 'No amplitude specified for channel {chan}. Can not continue.'
Step 4: Build, send, load, and assign a .seqx file¶
[7]:
# compile a binary .seqx file
seqx_output = awg.makeSEQXFile(*seqx_input)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[7], line 2
1 # compile a binary .seqx file
----> 2 seqx_output = awg.makeSEQXFile(*seqx_input)
NameError: name 'awg' is not defined
[8]:
# transfer it to the awg harddrive
awg.sendSEQXFile(seqx_output, "tutorial.seqx")
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[8], line 2
1 # transfer it to the awg harddrive
----> 2 awg.sendSEQXFile(seqx_output, "tutorial.seqx")
NameError: name 'awg' is not defined
[9]:
# load it into awg active memory
awg.loadSEQXFile("tutorial.seqx")
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[9], line 2
1 # load it into awg active memory
----> 2 awg.loadSEQXFile("tutorial.seqx")
NameError: name 'awg' is not defined
[10]:
# assign tracks from the sequence to the awg sequencer
awg.ch1.setSequenceTrack("tutorial_sequence", 1)
# NB: Each channel has an assigned resolution, either 8, 9, or 10.
# 8 means 8 bits for the waveform, 2 bits for the markers (i.e. 2 markers)
# 9 means 9 bits for the waveform, 1 bit for the markers (i.e. 1 marker)
# 10 means 10 bit for the waveform, no markers
#
# Since we want to have two markers, we make sure that the resolution is 8
awg.ch1.resolution(8)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[10], line 2
1 # assign tracks from the sequence to the awg sequencer
----> 2 awg.ch1.setSequenceTrack("tutorial_sequence", 1)
4 # NB: Each channel has an assigned resolution, either 8, 9, or 10.
5 # 8 means 8 bits for the waveform, 2 bits for the markers (i.e. 2 markers)
6 # 9 means 9 bits for the waveform, 1 bit for the markers (i.e. 1 marker)
7 # 10 means 10 bit for the waveform, no markers
8 #
9 # Since we want to have two markers, we make sure that the resolution is 8
10 awg.ch1.resolution(8)
NameError: name 'awg' is not defined
Step 5: Play it¶
[11]:
awg.ch1.state(1)
awg.play()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[11], line 1
----> 1 awg.ch1.state(1)
2 awg.play()
NameError: name 'awg' is not defined
[12]:
# force trigger the instrument to play the next part of the sequence
awg.force_triggerA()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[12], line 2
1 # force trigger the instrument to play the next part of the sequence
----> 2 awg.force_triggerA()
NameError: name 'awg' is not defined
[13]:
# eventually shut down and turn off
awg.stop()
awg.ch1.state(0)
awg.close()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[13], line 2
1 # eventually shut down and turn off
----> 2 awg.stop()
3 awg.ch1.state(0)
4 awg.close()
NameError: name 'awg' is not defined