Source code for instruments.tektronix.tekawg2000
#!/usr/bin/env python
"""
Provides support for the Tektronix AWG2000 series arbitrary wave generators.
"""
# IMPORTS #####################################################################
from enum import Enum
from instruments.generic_scpi import SCPIInstrument
from instruments.optional_dep_finder import numpy
from instruments.units import ureg as u
from instruments.util_fns import assume_units, ProxyList
# CLASSES #####################################################################
[docs]
class TekAWG2000(SCPIInstrument):
"""
Communicates with a Tektronix AWG2000 series instrument using the SCPI
commands documented in the user's guide.
"""
# INNER CLASSES #
[docs]
class Channel:
"""
Class representing a physical channel on the Tektronix AWG 2000
.. warning:: This class should NOT be manually created by the user. It
is designed to be initialized by the `TekAWG2000` class.
"""
def __init__(self, tek, idx):
self._tek = tek
# Zero-based for pythonic convienence, so we need to convert to
# Tektronix's one-based notation here.
self._name = f"CH{idx + 1}"
# Remember what the old data source was for use as a context manager
self._old_dsrc = None
# PROPERTIES #
@property
def name(self):
"""
Gets the name of this AWG channel
:type: `str`
"""
return self._name
@property
def amplitude(self):
"""
Gets/sets the amplitude of the specified channel.
:units: As specified (if a `~pint.Quantity`) or assumed to be
of units Volts.
:type: `~pint.Quantity` with units Volts peak-to-peak.
"""
return u.Quantity(
float(self._tek.query(f"FG:{self._name}:AMPL?").strip()), u.V
)
@amplitude.setter
def amplitude(self, newval):
self._tek.sendcmd(
"FG:{}:AMPL {}".format(
self._name, assume_units(newval, u.V).to(u.V).magnitude
)
)
@property
def offset(self):
"""
Gets/sets the offset of the specified channel.
:units: As specified (if a `~pint.Quantity`) or assumed to be
of units Volts.
:type: `~pint.Quantity` with units Volts.
"""
return u.Quantity(
float(self._tek.query(f"FG:{self._name}:OFFS?").strip()), u.V
)
@offset.setter
def offset(self, newval):
self._tek.sendcmd(
"FG:{}:OFFS {}".format(
self._name, assume_units(newval, u.V).to(u.V).magnitude
)
)
@property
def frequency(self):
"""
Gets/sets the frequency of the specified channel when using the built-in
function generator.
::units: As specified (if a `~pint.Quantity`) or assumed to be
of units Hertz.
:type: `~pint.Quantity` with units Hertz.
"""
return u.Quantity(float(self._tek.query("FG:FREQ?").strip()), u.Hz)
@frequency.setter
def frequency(self, newval):
self._tek.sendcmd(
f"FG:FREQ {assume_units(newval, u.Hz).to(u.Hz).magnitude}HZ"
)
@property
def polarity(self):
"""
Gets/sets the polarity of the specified channel.
:type: `TekAWG2000.Polarity`
"""
return TekAWG2000.Polarity(self._tek.query(f"FG:{self._name}:POL?").strip())
@polarity.setter
def polarity(self, newval):
if not isinstance(newval, TekAWG2000.Polarity):
raise TypeError(
"Polarity settings must be a "
"`TekAWG2000.Polarity` value, got {} "
"instead.".format(type(newval))
)
self._tek.sendcmd(f"FG:{self._name}:POL {newval.value}")
@property
def shape(self):
"""
Gets/sets the waveform shape of the specified channel. The AWG will
use the internal function generator for these shapes.
:type: `TekAWG2000.Shape`
"""
return TekAWG2000.Shape(
self._tek.query(f"FG:{self._name}:SHAP?").strip().split(",")[0]
)
@shape.setter
def shape(self, newval):
if not isinstance(newval, TekAWG2000.Shape):
raise TypeError(
"Shape settings must be a `TekAWG2000.Shape` "
"value, got {} instead.".format(type(newval))
)
self._tek.sendcmd(f"FG:{self._name}:SHAP {newval.value}")
# ENUMS #
[docs]
class Polarity(Enum):
"""
Enum containing valid polarity modes for the AWG2000
"""
normal = "NORMAL"
inverted = "INVERTED"
[docs]
class Shape(Enum):
"""
Enum containing valid waveform shape modes for hte AWG2000
"""
sine = "SINUSOID"
pulse = "PULSE"
ramp = "RAMP"
square = "SQUARE"
triangle = "TRIANGLE"
# Properties #
@property
def waveform_name(self):
"""
Gets/sets the destination waveform name for upload.
This is the file name that will be used on the AWG for any following
waveform data that is uploaded.
:type: `str`
"""
return self.query("DATA:DEST?").strip()
@waveform_name.setter
def waveform_name(self, newval):
if not isinstance(newval, str):
raise TypeError("Waveform name must be specified as a string.")
self.sendcmd(f'DATA:DEST "{newval}"')
@property
def channel(self):
"""
Gets a specific channel on the AWG2000. The desired channel is accessed
like one would access a list.
Example usage:
>>> import instruments as ik
>>> inst = ik.tektronix.TekAWG2000.open_gpibusb("/dev/ttyUSB0", 1)
>>> print(inst.channel[0].frequency)
:return: A channel object for the AWG2000
:rtype: `TekAWG2000.Channel`
"""
return ProxyList(self, self.Channel, range(2))
# METHODS #