Keysight M3202A AWG

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.

[ ]:
import logging

import numpy as np

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)

Trigger AWGs

[ ]:
# start AWGs via PXI
# Note: PXI trigger can be set via any module
awg1.set_pxi_trigger(0, pxi1)
awg1.set_pxi_trigger(1, pxi1)