This page was generated from docs/examples/driver_examples/Qcodes example with Tektronix AWG70002A.ipynb. Interactive online version: Binder badge.

QCoDeS Example with Tektronix AWG70002A

The Tektronix awg70002A can operate in two modes: function generator mode or AWG mode. This example notebook briefly covers both.

[1]:
%matplotlib notebook
import numpy as np

from qcodes.instrument_drivers.tektronix import TektronixAWG70002A
[2]:
awg = TektronixAWG70002A('awg', 'TCPIP0::172.20.2.243::inst0::INSTR')
Connected to: TEKTRONIX AWG70002A (serial:B020397, firmware:FV:5.3.0128.0) in 0.54s
[3]:
# Let's have a look at the available parameters

awg.print_readable_snapshot(update=True)
awg:
        parameter               value
--------------------------------------------------------------------------------
IDN                      :      {'firmware': 'FV:5.3.0128.0', 'model': 'AWG70002A'...
clock_external_frequency :      6.25e+09 (Hz)
clock_source             :      Internal
current_directory        :      "\Users\OEM\Documents"
mode                     :      AWG
sample_rate              :      2.5e+10 (Sa/s)
timeout                  :      10 (s)
awg_ch1:
        parameter        value
--------------------------------------------------------------------------------
awg_amplitude     :     0.5 (V)
fgen_amplitude    :     0.074 (V)
fgen_dclevel      :     0 (V)
fgen_frequency    :     1e+07 (Hz)
fgen_offset       :     0.12 (V)
fgen_period       :     1e-07 (s)
fgen_phase        :     25 (degrees)
fgen_signalpath   :     direct
fgen_symmetry     :     50 (%)
fgen_type         :     EXPONENTIALDECAY
marker1_high      :     0.1 (V)
marker1_low       :     -0.4 (V)
marker1_waitvalue :     HIGH
marker2_high      :     0.1 (V)
marker2_low       :     -0.4 (V)
marker2_waitvalue :     HIGH
resolution        :     8
state             :     1
awg_ch2:
        parameter        value
--------------------------------------------------------------------------------
awg_amplitude     :     0.3 (V)
fgen_amplitude    :     0.5 (V)
fgen_dclevel      :     0 (V)
fgen_frequency    :     1e+07 (Hz)
fgen_offset       :     0 (V)
fgen_period       :     1e-07 (s)
fgen_phase        :     0 (degrees)
fgen_signalpath   :     direct
fgen_symmetry     :     50 (%)
fgen_type         :     TRIANGLE
marker1_high      :     1.4 (V)
marker1_low       :     0 (V)
marker1_waitvalue :     LOW
marker2_high      :     1 (V)
marker2_low       :     0 (V)
marker2_waitvalue :     LOW
resolution        :     8
state             :     0

Function Generator Style Operation

[4]:
# Set the intrument mode to function generator
awg.mode('FGEN')

# Build some signal
awg.ch1.fgen_type('EXPONENTIALDECAY')
awg.ch1.fgen_frequency(10e6)
awg.ch1.fgen_amplitude(0.074)
awg.ch1.fgen_offset(0.12)
awg.ch1.fgen_phase(25)

# Switch channel 1 on
awg.ch1.state(1)

# Start outputting...
awg.play()
[5]:
# switch off the output eventually
awg.stop()

# and disable the channel
awg.ch1.state(0)

AWG Style Operation

The instrument can be operated as an awg where the user uploads arrays describing the waveforms.

Each channel operates in one of three resolution modes:

  • 8 bit signal + 2 markers

  • 9 bit signal + 1 marker

  • 10 bit signal with no markers

Waveforms can be sent to the waveform list via .wfmx files. A .wfmx file can contain marker data. If the resolution of the instrument does not allow for markers, these are simply ignored.

Making and sending waveforms to the waveform list

[6]:
# set the instrument in awg mode
awg.mode('AWG')
# set the resolution to 8 bits plus two markers
awg.ch1.resolution(8)
[7]:
# clear the sequence list and waveform list (NOT ALWAYS A GOOD IDEA! BE CAREFUL!)
awg.clearSequenceList()
awg.clearWaveformList()
[8]:
# Let us make a sine, upload it and play it

N = 50000  # minimal length allowed is 2400 points

m1 = np.concatenate((np.ones(int(N/2)), np.zeros(int(N/2))))
m2 = np.concatenate((np.zeros(int(N/2)), np.ones(int(N/2))))

ramp = 0.075*np.linspace(0, 1, N)

mysine = 0.1*np.sin(10*2*np.pi*np.linspace(0, 1, N)) + ramp

data = np.array([mysine, m1, m2])
[9]:
# The .wfmx file needs a name in the memory of the instrument
# The name of the waveform in the waveform list is that same name
# with no .wfmx extension
filename = 'examplewaveform1.wfmx'
[10]:
# now compile the binary file
wfmx_file = awg.makeWFMXFile(data, 0.350)
[11]:
# and send it and load it into memory
awg.sendWFMXFile(wfmx_file, filename)
awg.loadWFMXFile(filename)
[12]:
# The waveform is now in the waveform list
awg.waveformList
[12]:
['examplewaveform1']
[13]:
# now assign it to channel 1
awg.ch1.setWaveform(filename.replace('.wfmx', ''))
[14]:
# Switch channel 1 on
awg.ch1.state(1)

# Start outputting...
awg.play()
[15]:
# switch off the output eventually
awg.stop()

# and disable the channel
awg.ch1.state(0)
[16]:
awg.ch2.setWaveform(filename.replace('.wfmx', ''))
[17]:
awg.ch2.state(0)

Making and sending sequences

Sequences are much better off being generated using the broadbean module, but for now let’s reduce the number of moving parts and compose a little sequence by hand.

[18]:
# set the instrument in awg mode
awg.mode('AWG')
# set the resolution to 8 bits plus two markers
awg.ch1.resolution(8)
[19]:
# Let's make a sequence where a sine plays on one channel while the other channel ramps
# and then the roles reverse

# As a preparation, let's set both channels to 300 mV peak-to-peak
awg.ch1.awg_amplitude(0.3)
awg.ch2.awg_amplitude(0.3)

N = 20000  # minimally 2400

SR = 1e9
awg.sample_rate(SR)  # set the sample rate on the instrument
ramp_target = 0.1  # ramp target (V)

time = np.linspace(0, N/SR, N)
sinesignal = 0.15*np.sin(SR/N*2*np.pi*time)
m1 = np.concatenate((np.ones(int(N/2)), np.zeros(int(N/2))))
m2 = np.concatenate((np.zeros(int(N/2)), np.zeros(int(N/2))))
rampsignal = np.linspace(0, ramp_target, N)

# Then we compose and upload a .seqx file in 6 steps

# Step 1: cast the waveform data into the .wfmx format
# To make a .wfmx, we need to know the amplitude of the output channel
ch1_amp = awg.ch1.awg_amplitude()
ch2_amp = awg.ch2.awg_amplitude()

#wfm_ch1_n1 = awg.makeWFMXFile(np.array([sinesignal, m1, m2]), ch1_amp)
#wfm_ch1_n2 = awg.makeWFMXFile(np.array([rampsignal, m1, m2]), ch1_amp)
#wfm_ch2_n1 = awg.makeWFMXFile(np.array([rampsignal, m1, m2]), ch2_amp)
#wfm_ch2_n2 = awg.makeWFMXFile(np.array([sinesignal, m1, m2]), ch2_amp)


wfm_ch1_n1 = np.array([sinesignal, m1, m2])
wfm_ch1_n2 = np.array([rampsignal, m1, m2])
wfm_ch2_n1 = np.array([rampsignal, m1, m2])
wfm_ch2_n2 = np.array([sinesignal, m1, m2])

# Step 2: decide on sequencing information
# This information is provided as lists of the same length as the
# sequence
trig_waits = [0, 0]  # 0: off, 1: trigA, 2: trigB, 3: EXT
nreps = [2, 3]  # 0 corresponds to infinite
event_jumps = [0, 0] # 0: off, 1: trigA, 2: trigB, 3: EXT
event_jump_to = [0, 0]  # irrelevant if event-jump is 0, else the sequence pos. to jump to
go_to = [0, 1]  # 0 means next

# Step 3: make the .seqx file
# The sequence must be given a name

seqname = 'tutorial_sequence'

wfms = [[wfm_ch1_n1, wfm_ch1_n2], [wfm_ch2_n1, wfm_ch2_n2]]

seqx = awg.makeSEQXFile(trig_waits,
                        nreps,
                        event_jumps,
                        event_jump_to,
                        go_to,
                        wfms,
                        [ch1_amp, ch2_amp],
                        seqname)

# Step 4: Transfer the seqx file
awg.sendSEQXFile(seqx, 'thursday.seqx')

# Step 5: Load the seqx file
awg.loadSEQXFile('thursday.seqx')
# Now the sequence should appear in the sequencelist, but it is not yet assigned to channels

# Step 6: Assign tracks from the sequence to the channels
# Unlike older/other AWG models, this can be done on a per-channel basis
awg.ch1.setSequenceTrack(seqname, 1)
awg.ch2.setSequenceTrack(seqname, 2)
[20]:
# Now play it!
awg.ch1.state(1)
awg.ch2.state(1)
awg.play()
[21]:
awg.stop()
[22]:
# Finally irreversibly tear down the instrument
awg.close()