Keysight M3202A AWG example with digitizer¶
The Keysight M3202A is a 1 GSa/a arbitrary waveform generator.
An instance of M3202A represents a module with 4 output channels. The channels of one module share the uploaded waveforms and trigers.
This example loads loads waveforms in AWGs in slots 2 and 3 of chassis 0.
This example uses a digitizer from the keysightSD1 module to read the generated signals. The digitizer is in slot 5. The output channels 1 and 2 of the AWG in slot 2 should be connected to inputs 1 and 2 of the digitizer and output channels 3 and 4 of the AWG slot 3 should be conencted to inputs 3 and 4 of the digitizer.
[ ]:
import logging
import numpy as np
import matplotlib.pyplot as plt
try:
import keysightSD1
except:
# add the path where the keysight library probably resides and try again
import sys
sys.path.append(r'C:\Program Files (x86)\Keysight\SD1\Libraries\Python')
import keysightSD1
import qcodes
from qcodes_contrib_drivers.drivers.Keysight.M3202A import M3202A
import qcodes.logger as logger
from qcodes.logger import start_all_logging
start_all_logging()
# logger.get_file_handler().setLevel(logging.DEBUG)
[ ]:
# try to close station from previous run.
try:
station.close_all_registered_instruments()
except: pass
[ ]:
# Demonstration of some errors
try:
wrong_chassis = M3202A("wrong chassis", chassis = 5, slot = 16)
except Exception as e:
print('Expected failure:', e)
try:
empty_slot = M3202A("empty_slot", chassis = 0, slot = 16)
except Exception as e:
print('Expected failure:', e)
try:
not_M3202A = M3202A("Digitizer", chassis = 0, slot = 5)
except Exception as e:
print('Expected failure:', e)
[ ]:
awg1 = M3202A("AWG1", chassis = 0, slot = 2)
awg2 = M3202A("AWG2", chassis = 0, slot = 3)
station = qcodes.Station()
station.add_component(awg1)
station.add_component(awg2)
[ ]:
# utility functions to create waveforms
def get_divider(prescaler):
if prescaler == 0:
divider = 1
elif prescaler == 1:
divider = 5
else:
divider = prescaler * 10
return divider
def create_sawtooth(period, repetition, prescaler):
divider = get_divider(prescaler)
n_pts = period // divider
w = np.linspace(-1, 1, n_pts)
w = np.tile(w, repetition)
if len(w) < 2000:
raise Exception('not enough data')
return w
def create_sine(period, repetition, prescaler):
divider = get_divider(prescaler)
n_pts = repetition * period // divider
phi = np.linspace(0, np.pi*2*repetition, n_pts)
w = np.sin(phi)
if len(w) < 2000:
raise Exception('not enough data')
return w
[ ]:
# setup output channels
pxi1 = keysightSD1.SD_TriggerExternalSources.TRIGGER_PXI1
trigger_mode = keysightSD1.SD_TriggerBehaviors.TRIGGER_FALL
for awg in [awg1, awg2]:
for ch in range(1,5):
awg.set_channel_offset(0.0, ch)
awg.set_channel_amplitude(1.0, ch)
awg.set_channel_wave_shape(keysightSD1.SD_Waveshapes.AOU_AWG, ch)
awg.awg_queue_config(ch, keysightSD1.SD_QueueMode.CYCLIC)
awg.awg_config_external_trigger(ch, pxi1, trigger_mode)
awg2.amplitude_channel_1.set(0.5)
awg2.offset_channel_2.set(0.5)
Generate and enqueue waveforms¶
Signal duration 20 us: * “AWG1.1”: 20x sawtooth (followed by zeros) * “AWG1.2”: 20 steps (followed by zeros) * “AWG2.3”: 2 us zero, 4 us sine, 2 us zero, 12 us sine * “AWG2.4”: 4 us sine, 4 us zero, 8 us sine, 4 us zero
[ ]:
prescaler_1GSa = 0
prescaler_200MSa = 1
prescaler_50MSa = 2
# 2000 zero's for end
zeros = np.zeros(2000)
# sawtooth period = 1 us: 2 period in 1 sample
sawtooth_2us = 0.5 * create_sawtooth(1000, 2, prescaler_1GSa)
# 20 steps use prescaler to reduce total number of samples. 200MSa/s => 4000 pts; 200 per step
steps = np.concatenate([0.02*i*np.ones(200) for i in range(20)])
# sine wave 2 MHz, 4 periods
sine = 0.6 * create_sine(500, 4, prescaler_1GSa)
# start all uploads
zeros_awg1 = awg1.upload_waveform(zeros)
sawtooth_2us_awg1 = awg1.upload_waveform(sawtooth_2us)
steps_awg1 = awg1.upload_waveform(steps)
zeros_awg2 = awg2.upload_waveform(zeros)
sine_awg2 = awg2.upload_waveform(sine)
# enqueue wave references
delay = 0
ext_trigger = keysightSD1.SD_TriggerModes.EXTTRIG
auto_trigger = keysightSD1.SD_TriggerModes.AUTOTRIG
awg1.awg_queue_waveform(1, sawtooth_2us_awg1, ext_trigger, delay, 10, prescaler_1GSa)
awg1.awg_queue_waveform(1, zeros_awg1, auto_trigger, delay, 1, prescaler_1GSa)
awg1.awg_queue_waveform(2, steps_awg1, ext_trigger, delay, 1, prescaler_200MSa)
awg1.awg_queue_waveform(2, zeros_awg1, auto_trigger, delay, 1, prescaler_1GSa)
awg2.awg_queue_waveform(3, zeros_awg2, ext_trigger, delay, 1, prescaler_1GSa)
awg2.awg_queue_waveform(3, sine_awg2, auto_trigger, delay, 2, prescaler_1GSa)
awg2.awg_queue_waveform(3, zeros_awg2, auto_trigger, delay, 1, prescaler_1GSa)
awg2.awg_queue_waveform(3, sine_awg2, auto_trigger, delay, 6, prescaler_1GSa)
awg2.awg_queue_waveform(4, sine_awg2, ext_trigger, delay, 2, prescaler_1GSa)
awg2.awg_queue_waveform(4, zeros_awg2, auto_trigger, delay, 2, prescaler_1GSa)
awg2.awg_queue_waveform(4, sine_awg2, auto_trigger, delay, 4, prescaler_1GSa)
awg2.awg_queue_waveform(4, zeros_awg2, auto_trigger, delay, 2, prescaler_1GSa)
# start AWGs. They will wait for external trigger.
awg1.awg_start_multiple(0b0011)
awg2.awg_start_multiple(0b1100)
configure digitizer to capture signals¶
[ ]:
def check_error(error, s=''):
if (type(error) is int and error < 0):
print(keysightSD1.SD_Error.getErrorMessage(error), error, s)
PRODUCT = ""
CHASSIS = 0
# change slot numbers to your values
SLOT_IN = 5
NUM_CHANNELS = 4
# CREATE AND OPEN MODULE IN
moduleIn = keysightSD1.SD_AIN()
moduleInID = moduleIn.openWithSlot(PRODUCT, CHASSIS, SLOT_IN)
NUM_CYCLES = 1
DIG_PRESCALER = 0
# sample 21 us
IN_DURATION = 21
TOT_POINTS_IN = 500 * IN_DURATION
FULL_SCALE = 2.5
DELAY_IN = 200 // (DIG_PRESCALER + 1)
mask = 0
for ch in range(1,5):
moduleIn.DAQstop(ch)
moduleIn.DAQflush(ch)
for c in range(0, NUM_CHANNELS):
mask |= 1 << c
ch = c + 1
# MODULE IN
moduleIn.channelInputConfig(ch, FULL_SCALE, keysightSD1.AIN_Impedance.AIN_IMPEDANCE_HZ, keysightSD1.AIN_Coupling.AIN_COUPLING_DC)
moduleIn.channelPrescalerConfig(ch, DIG_PRESCALER)
moduleIn.DAQdigitalTriggerConfig(ch, pxi1, trigger_mode)
moduleIn.DAQconfig(ch, TOT_POINTS_IN, 1, DELAY_IN, ext_trigger)
moduleIn.DAQstartMultiple(mask)
Trigger AWGs and digitizer¶
[ ]:
# start AWGs and digitizers via PXI
# Note: PXI trigger can be set via any module
awg1.set_pxi_trigger(0, pxi1)
awg1.set_pxi_trigger(1, pxi1)
Retrieve digitizer data and plot result¶
[ ]:
POINTS_PER_READ = 20000
READ_TIMEOUT = 1000
numReadPoints = []
dataPoints = []
for c in range(0, NUM_CHANNELS):
numReadPoints.append(0)
dataPoints.append(np.empty(0, dtype=np.short))
readDone = False
print()
print("Reading data...")
cnt = 0
while not readDone:
if (cnt > 10):
print('no more data')
break
readDone = True
for c in range(0, NUM_CHANNELS):
npts = moduleIn.DAQcounterRead(c + 1)
if npts <= 0:
print(f'channel {c} counter {npts} {numReadPoints[c]}')
cnt += 1
else:
readPoints = moduleIn.DAQread(c + 1, min(POINTS_PER_READ, npts), READ_TIMEOUT)
check_error(readPoints)
if type(readPoints) is int or readPoints.size == 0:
cnt += 1
else:
cnt = 0
dataPoints[c] = np.append(dataPoints[c], readPoints)
numReadPoints[c] += readPoints.size
print(f'channel {c} counter {npts} read {readPoints.size} ({numReadPoints[c]})')
readDone = readDone and (numReadPoints[c] >= TOT_POINTS_IN)
for i in range(1,5):
fig = plt.figure(i)
fig.clear()
plt.plot(dataPoints[i-1])
plt.show()