class Inst:
        """Mock instrument class."""
        def __init__(self):
            """Set up the mocker spies and send command placeholder."""
            # spies
            self.spy_query = mocker.spy(self, 'query')
            self.spy_sendcmd = mocker.spy(self, 'sendcmd')

            # variable to set with send command
            self._sendcmd = None

        def query(self, cmd):
            """Return the command minus the ? which is sent along."""
            return f"{cmd[:-1]}"

        def sendcmd(self, cmd):
            """Sets the command to `self._sendcmd`."""
            self._sendcmd = cmd

        class SomeEnum(Enum):
            test = "enum"

        bool_property = bool_property("ON")  # return True

        enum_property = enum_property("enum", SomeEnum)

        unitless_property = unitless_property("42")

        int_property = int_property("42")

        unitful_property = unitful_property("42", u.K)

        string_property = string_property("'STRING'")
 class StringMock(MockInstrument):
     mock_property = string_property('MOCK', set_cmd='FOOBAR')
 class StringMock(MockInstrument):
     mock_property = string_property('MOCK', bookmark_symbol='')
 class StringMock(MockInstrument):
     mock_property = string_property('MOCK')
Example #5
0
    class Channel(DataSource, OscilloscopeChannel):
        """
        Class representing a channel on the Tektronix DPO 70000.

        This class inherits from `TekDPO70000.DataSource`.

        .. warning:: This class should NOT be manually created by the user. It
            is designed to be initialized by the `TekDPO70000` class.
        """
        def __init__(self, parent, idx):
            self._parent = parent
            self._idx = idx + 1  # 1-based.

            # Initialize as a data source with name CH{}.
            super(TekDPO70000.Channel, self).__init__(self._parent,
                                                      "CH{}".format(self._idx))

        def sendcmd(self, cmd):
            """
            Wraps commands sent from property factories in this class with
            identifiers for the specified channel.

            :param str cmd: Command to send to the instrument
            """
            self._parent.sendcmd("CH{}:{}".format(self._idx, cmd))

        def query(self, cmd, size=-1):
            """
            Wraps queries sent from property factories in this class with
            identifiers for the specified channel.

            :param str cmd: Query command to send to the instrument
            :param int size: Number of characters to read from the response.
                Default value reads until a termination character is found.
            :return: The query response
            :rtype: `str`
            """
            return self._parent.query("CH{}:{}".format(self._idx, cmd), size)

        class Coupling(Enum):
            """
            Enum containing valid coupling modes for the oscilloscope channel
            """
            ac = "AC"
            dc = "DC"
            dc_reject = "DCREJ"
            ground = "GND"

        coupling = enum_property("COUP",
                                 Coupling,
                                 doc="""
            Gets/sets the coupling for the specified channel.

            Example usage:

            >>> import instruments as ik
            >>> inst = ik.tektronix.TekDPO70000.open_tcpip("192.168.0.1", 8080)
            >>> channel = inst.channel[0]
            >>> channel.coupling = channel.Coupling.ac
            """)

        bandwidth = unitful_property('BAN', u.Hz)

        deskew = unitful_property('DESK', u.second)

        termination = unitful_property('TERM', u.ohm)

        label = string_property('LAB:NAM',
                                doc="""
            Just a human readable label for the channel.
            """)

        label_xpos = unitless_property('LAB:XPOS',
                                       doc="""
            The x position, in divisions, to place the label.
            """)

        label_ypos = unitless_property('LAB:YPOS',
                                       doc="""
            The y position, in divisions, to place the label.
            """)

        offset = unitful_property('OFFS',
                                  u.volt,
                                  doc="""
            The vertical offset in units of volts. Voltage is given by
            ``offset+scale*(5*raw/2^15 - position)``.
            """)

        position = unitless_property('POS',
                                     doc="""
            The vertical position, in divisions from the center graticule,
            ranging from ``-8`` to ``8``. Voltage is given by
            ``offset+scale*(5*raw/2^15 - position)``.
            """)

        scale = unitful_property('SCALE',
                                 u.volt,
                                 doc="""
            Vertical channel scale in units volts/division. Voltage is given
            by ``offset+scale*(5*raw/2^15 - position)``.
            """)

        def _scale_raw_data(self, data):
            scale = self.scale
            position = self.position
            offset = self.offset

            if numpy:
                return scale * (
                    (TekDPO70000.VERT_DIVS / 2) * data.astype(float) /
                    (2**15) - position) + offset

            return tuple(scale * ((TekDPO70000.VERT_DIVS / 2) * d /
                                  (2**15) - position) + offset
                         for d in map(float, data))
Example #6
0
class TekDPO70000(SCPIInstrument, Oscilloscope):
    """
    The Tektronix DPO70000 series  is a multi-channel oscilloscope with analog
    bandwidths ranging up to 33GHz.

    This class inherits from `~instruments.generic_scpi.SCPIInstrument`.

    Example usage:

    >>> import instruments as ik
    >>> tek = ik.tektronix.TekDPO70000.open_tcpip("192.168.0.2", 8888)
    >>> [x, y] = tek.channel[0].read_waveform()
    """

    # CONSTANTS #

    # The number of horizontal and vertical divisions.
    HOR_DIVS = 10
    VERT_DIVS = 10

    # ENUMS #

    class AcquisitionMode(Enum):
        """
        Enum containing valid acquisition modes for the Tektronix 70000 series
        oscilloscopes.
        """
        sample = "SAM"
        peak_detect = "PEAK"
        hi_res = "HIR"
        average = "AVE"
        waveform_db = "WFMDB"
        envelope = "ENV"

    class AcquisitionState(Enum):
        """
        Enum containing valid acquisition states for the Tektronix 70000 series
        oscilloscopes.
        """
        on = 'ON'
        off = 'OFF'
        run = 'RUN'
        stop = 'STOP'

    class StopAfter(Enum):
        """
        Enum containing valid stop condition modes for the Tektronix 70000
        series oscilloscopes.
        """
        run_stop = 'RUNST'
        sequence = 'SEQ'

    class SamplingMode(Enum):
        """
        Enum containing valid sampling modes for the Tektronix 70000
        series oscilloscopes.
        """
        real_time = "RT"
        equivalent_time_allowed = "ET"
        interpolation_allowed = "IT"

    class HorizontalMode(Enum):
        """
        Enum containing valid horizontal scan modes for the Tektronix 70000
        series oscilloscopes.
        """
        auto = "AUTO"
        constant = "CONST"
        manual = "MAN"

    class WaveformEncoding(Enum):
        """
        Enum containing valid waveform encoding modes for the Tektronix 70000
        series oscilloscopes.
        """
        # NOTE: For some reason, it uses the full names here instead of
        # returning the mneonics listed in the manual.
        ascii = "ASCII"
        binary = "BINARY"

    class BinaryFormat(Enum):
        """
        Enum containing valid binary formats for the Tektronix 70000
        series oscilloscopes (int, unsigned-int, floating-point).
        """
        int = "RI"
        uint = "RP"
        float = "FP"  # Single-precision!

    class ByteOrder(Enum):
        """
        Enum containing valid byte order (big-/little-endian) for the
        Tektronix 70000 series oscilloscopes.
        """
        little_endian = "LSB"
        big_endian = "MSB"

    class TriggerState(Enum):
        """
        Enum containing valid trigger states for the Tektronix 70000
        series oscilloscopes.
        """
        armed = "ARMED"
        auto = "AUTO"
        dpo = "DPO"
        partial = "PARTIAL"
        ready = "READY"

    # STATIC METHODS #

    @staticmethod
    def _dtype(binary_format, byte_order, n_bytes):
        return "{}{}{}".format({
            TekDPO70000.ByteOrder.big_endian: ">",
            TekDPO70000.ByteOrder.little_endian: "<"
        }[byte_order], (n_bytes if n_bytes is not None else ""), {
            TekDPO70000.BinaryFormat.int: "i",
            TekDPO70000.BinaryFormat.uint: "u",
            TekDPO70000.BinaryFormat.float: "f"
        }[binary_format])

    # CLASSES #

    class DataSource(OscilloscopeDataSource):
        """
        Class representing a data source (channel, math, or ref) on the
        Tektronix DPO 70000.

        .. warning:: This class should NOT be manually created by the user. It
            is designed to be initialized by the `TekDPO70000` class.
        """
        @property
        def name(self):
            return self._name

        @abc.abstractmethod
        def _scale_raw_data(self, data):
            """
            Takes the int16 data and figures out how to make it unitful.
            """

        # pylint: disable=protected-access
        def read_waveform(self, bin_format=True):
            # We want to get the data back in binary, as it's just too much
            # otherwise.
            with self:
                self._parent.select_fastest_encoding()
                n_bytes = self._parent.outgoing_n_bytes
                dtype = self._parent._dtype(
                    self._parent.outgoing_binary_format,
                    self._parent.outgoing_byte_order,
                    n_bytes=None)
                self._parent.sendcmd("CURV?")
                raw = self._parent.binblockread(n_bytes, fmt=dtype)
                # Clear the queue by reading the end of line character
                self._parent._file.read_raw(1)

                return self._scale_raw_data(raw)

        def __enter__(self):
            self._old_dsrc = self._parent.data_source
            if self._old_dsrc != self:
                # Set the new data source, and let __exit__ cleanup.
                self._parent.data_source = self
            else:
                # There's nothing to do or undo in this case.
                self._old_dsrc = None

        def __exit__(self, type, value, traceback):
            if self._old_dsrc is not None:
                self._parent.data_source = self._old_dsrc

    class Math(DataSource):
        """
        Class representing a math channel on the Tektronix DPO 70000.

        This class inherits from `TekDPO70000.DataSource`.

        .. warning:: This class should NOT be manually created by the user. It
            is designed to be initialized by the `TekDPO70000` class.
        """
        def __init__(self, parent, idx):
            self._parent = parent
            self._idx = idx + 1  # 1-based.

            # Initialize as a data source with name MATH{}.
            super(TekDPO70000.Math, self).__init__(parent,
                                                   "MATH{}".format(self._idx))

        def sendcmd(self, cmd):
            """
            Wraps commands sent from property factories in this class with
            identifiers for the specified math channel.

            :param str cmd: Command to send to the instrument
            """
            self._parent.sendcmd("MATH{}:{}".format(self._idx, cmd))

        def query(self, cmd, size=-1):
            """
            Wraps queries sent from property factories in this class with
            identifiers for the specified math channel.

            :param str cmd: Query command to send to the instrument
            :param int size: Number of characters to read from the response.
                Default value reads until a termination character is found.
            :return: The query response
            :rtype: `str`
            """
            return self._parent.query("MATH{}:{}".format(self._idx, cmd), size)

        class FilterMode(Enum):
            """
            Enum containing valid filter modes for a math channel on the
            TekDPO70000 series oscilloscope.
            """
            centered = "CENT"
            shifted = "SHIF"

        class Mag(Enum):
            """
            Enum containing valid amplitude units for a math channel on the
            TekDPO70000 series oscilloscope.
            """
            linear = "LINEA"
            db = "DB"
            dbm = "DBM"

        class Phase(Enum):
            """
            Enum containing valid phase units for a math channel on the
            TekDPO70000 series oscilloscope.
            """
            degrees = "DEG"
            radians = "RAD"
            group_delay = "GROUPD"

        class SpectralWindow(Enum):
            """
            Enum containing valid spectral windows for a math channel on the
            TekDPO70000 series oscilloscope.
            """
            rectangular = "RECTANG"
            hamming = "HAMM"
            hanning = "HANN"
            kaiser_besse = "KAISERB"
            blackman_harris = "BLACKMANH"
            flattop2 = "FLATTOP2"
            gaussian = "GAUSS"
            tek_exponential = "TEKEXP"

        define = string_property("DEF",
                                 doc="""
            A text string specifying the math to do, ex. CH1+CH2
            """)

        filter_mode = enum_property("FILT:MOD", FilterMode)

        filter_risetime = unitful_property("FILT:RIS", u.second)

        label = string_property("LAB:NAM",
                                doc="""
            Just a human readable label for the channel.
            """)

        label_xpos = unitless_property("LAB:XPOS",
                                       doc="""
            The x position, in divisions, to place the label.
            """)

        label_ypos = unitless_property(
            "LAB:YPOS",
            doc="""The y position, in divisions, to place the label.
            """)

        num_avg = unitless_property("NUMAV",
                                    doc="""
            The number of acquisistions over which exponential averaging is
            performed.
            """)

        spectral_center = unitful_property("SPEC:CENTER",
                                           u.Hz,
                                           doc="""
            The desired frequency of the spectral analyzer output data span
            in Hz.
            """)

        spectral_gatepos = unitful_property("SPEC:GATEPOS",
                                            u.second,
                                            doc="""
            The gate position. Units are represented in seconds, with respect
            to trigger position.
            """)

        spectral_gatewidth = unitful_property("SPEC:GATEWIDTH",
                                              u.second,
                                              doc="""
            The time across the 10-division screen in seconds.
            """)

        spectral_lock = bool_property("SPEC:LOCK",
                                      inst_true="ON",
                                      inst_false="OFF")

        spectral_mag = enum_property("SPEC:MAG",
                                     Mag,
                                     doc="""
            Whether the spectral magnitude is linear, db, or dbm.
            """)

        spectral_phase = enum_property("SPEC:PHASE",
                                       Phase,
                                       doc="""
            Whether the spectral phase is degrees, radians, or group delay.
            """)

        spectral_reflevel = unitless_property("SPEC:REFL",
                                              doc="""
            The value that represents the topmost display screen graticule.
            The units depend on spectral_mag.
            """)

        spectral_reflevel_offset = unitless_property("SPEC:REFLEVELO")

        spectral_resolution_bandwidth = unitful_property("SPEC:RESB",
                                                         u.Hz,
                                                         doc="""
            The desired resolution bandwidth value. Units are represented in
            Hertz.
            """)

        spectral_span = unitful_property("SPEC:SPAN",
                                         u.Hz,
                                         doc="""
            Specifies the frequency span of the output data vector from the
            spectral analyzer.
            """)

        spectral_suppress = unitless_property("SPEC:SUPP",
                                              doc="""
            The magnitude level that data with magnitude values below this
            value are displayed as zero phase.
            """)

        spectral_unwrap = bool_property("SPEC:UNWR",
                                        inst_true="ON",
                                        inst_false="OFF",
                                        doc="""
            Enables or disables phase wrapping.
            """)

        spectral_window = enum_property("SPEC:WIN", SpectralWindow)

        threshhold = unitful_property("THRESH",
                                      u.volt,
                                      doc="""
            The math threshhold in volts
            """)

        unit_string = string_property("UNITS",
                                      doc="""
            Just a label for the units...doesn"t actually change anything.
            """)

        autoscale = bool_property("VERT:AUTOSC",
                                  inst_true="ON",
                                  inst_false="OFF",
                                  doc="""
            Enables or disables the auto-scaling of new math waveforms.
            """)

        position = unitless_property("VERT:POS",
                                     doc="""
            The vertical position, in divisions from the center graticule.
            """)

        scale = unitful_property("VERT:SCALE",
                                 u.volt,
                                 doc="""
            The scale in volts per division. The range is from
            ``100e-36`` to ``100e+36``.
            """)

        def _scale_raw_data(self, data):
            # TODO: incorperate the unit_string somehow
            if numpy:
                return self.scale * (
                    (TekDPO70000.VERT_DIVS / 2) * data.astype(float) /
                    (2**15) - self.position)

            scale = self.scale
            position = self.position
            rval = tuple(scale * ((TekDPO70000.VERT_DIVS / 2) * d /
                                  (2**15) - position)
                         for d in map(float, data))
            return rval

    class Channel(DataSource, OscilloscopeChannel):
        """
        Class representing a channel on the Tektronix DPO 70000.

        This class inherits from `TekDPO70000.DataSource`.

        .. warning:: This class should NOT be manually created by the user. It
            is designed to be initialized by the `TekDPO70000` class.
        """
        def __init__(self, parent, idx):
            self._parent = parent
            self._idx = idx + 1  # 1-based.

            # Initialize as a data source with name CH{}.
            super(TekDPO70000.Channel, self).__init__(self._parent,
                                                      "CH{}".format(self._idx))

        def sendcmd(self, cmd):
            """
            Wraps commands sent from property factories in this class with
            identifiers for the specified channel.

            :param str cmd: Command to send to the instrument
            """
            self._parent.sendcmd("CH{}:{}".format(self._idx, cmd))

        def query(self, cmd, size=-1):
            """
            Wraps queries sent from property factories in this class with
            identifiers for the specified channel.

            :param str cmd: Query command to send to the instrument
            :param int size: Number of characters to read from the response.
                Default value reads until a termination character is found.
            :return: The query response
            :rtype: `str`
            """
            return self._parent.query("CH{}:{}".format(self._idx, cmd), size)

        class Coupling(Enum):
            """
            Enum containing valid coupling modes for the oscilloscope channel
            """
            ac = "AC"
            dc = "DC"
            dc_reject = "DCREJ"
            ground = "GND"

        coupling = enum_property("COUP",
                                 Coupling,
                                 doc="""
            Gets/sets the coupling for the specified channel.

            Example usage:

            >>> import instruments as ik
            >>> inst = ik.tektronix.TekDPO70000.open_tcpip("192.168.0.1", 8080)
            >>> channel = inst.channel[0]
            >>> channel.coupling = channel.Coupling.ac
            """)

        bandwidth = unitful_property('BAN', u.Hz)

        deskew = unitful_property('DESK', u.second)

        termination = unitful_property('TERM', u.ohm)

        label = string_property('LAB:NAM',
                                doc="""
            Just a human readable label for the channel.
            """)

        label_xpos = unitless_property('LAB:XPOS',
                                       doc="""
            The x position, in divisions, to place the label.
            """)

        label_ypos = unitless_property('LAB:YPOS',
                                       doc="""
            The y position, in divisions, to place the label.
            """)

        offset = unitful_property('OFFS',
                                  u.volt,
                                  doc="""
            The vertical offset in units of volts. Voltage is given by
            ``offset+scale*(5*raw/2^15 - position)``.
            """)

        position = unitless_property('POS',
                                     doc="""
            The vertical position, in divisions from the center graticule,
            ranging from ``-8`` to ``8``. Voltage is given by
            ``offset+scale*(5*raw/2^15 - position)``.
            """)

        scale = unitful_property('SCALE',
                                 u.volt,
                                 doc="""
            Vertical channel scale in units volts/division. Voltage is given
            by ``offset+scale*(5*raw/2^15 - position)``.
            """)

        def _scale_raw_data(self, data):
            scale = self.scale
            position = self.position
            offset = self.offset

            if numpy:
                return scale * (
                    (TekDPO70000.VERT_DIVS / 2) * data.astype(float) /
                    (2**15) - position) + offset

            return tuple(scale * ((TekDPO70000.VERT_DIVS / 2) * d /
                                  (2**15) - position) + offset
                         for d in map(float, data))

    # PROPERTIES ##

    @property
    def channel(self):
        return ProxyList(self, self.Channel, range(4))

    @property
    def math(self):
        return ProxyList(self, self.Math, range(4))

    @property
    def ref(self):
        raise NotImplementedError

    # For some settings that probably won't be used that often, use
    # string_property instead of setting up an enum property.
    acquire_enhanced_enob = string_property('ACQ:ENHANCEDE',
                                            bookmark_symbol='',
                                            doc="""
        Valid values are AUTO and OFF.
        """)

    acquire_enhanced_state = bool_property(
        'ACQ:ENHANCEDE:STATE',
        inst_false='0',  # TODO: double check that these are correct
        inst_true='1')

    acquire_interp_8bit = string_property('ACQ:INTERPE',
                                          bookmark_symbol='',
                                          doc="""
        Valid values are AUTO, ON and OFF.
        """)

    acquire_magnivu = bool_property('ACQ:MAG',
                                    inst_true='ON',
                                    inst_false='OFF')

    acquire_mode = enum_property('ACQ:MOD', AcquisitionMode)

    acquire_mode_actual = enum_property('ACQ:MOD:ACT',
                                        AcquisitionMode,
                                        readonly=True)

    acquire_num_acquisitions = int_property('ACQ:NUMAC',
                                            readonly=True,
                                            doc="""
        The number of waveform acquisitions that have occurred since starting
        acquisition with the ACQuire:STATE RUN command
        """)

    acquire_num_avgs = int_property('ACQ:NUMAV',
                                    doc="""
        The number of waveform acquisitions to average.
        """)

    acquire_num_envelop = int_property('ACQ:NUME',
                                       doc="""
        The number of waveform acquisitions to be enveloped
        """)

    acquire_num_frames = int_property('ACQ:NUMFRAMESACQ',
                                      readonly=True,
                                      doc="""
        The number of frames acquired when in FastFrame Single Sequence and
        acquisitions are running.
        """)

    acquire_num_samples = int_property('ACQ:NUMSAM',
                                       doc="""
        The minimum number of acquired samples that make up a waveform
        database (WfmDB) waveform for single sequence mode and Mask Pass/Fail
        Completion Test. The default value is 16,000 samples. The range is
        5,000 to 2,147,400,000 samples.
        """)

    acquire_sampling_mode = enum_property('ACQ:SAMP', SamplingMode)

    acquire_state = enum_property('ACQ:STATE',
                                  AcquisitionState,
                                  doc="""
        This command starts or stops acquisitions.
        """)

    acquire_stop_after = enum_property('ACQ:STOPA',
                                       StopAfter,
                                       doc="""
        This command sets or queries whether the instrument continually
        acquires acquisitions or acquires a single sequence.
        """)

    data_framestart = int_property('DAT:FRAMESTAR')

    data_framestop = int_property('DAT:FRAMESTOP')

    data_start = int_property('DAT:STAR',
                              doc="""
        The first data point that will be transferred, which ranges from 1 to
        the record length.
        """)

    # TODO: Look into the following troublesome datasheet note: "When using the
    # CURVe command, DATa:STOP is ignored and WFMInpre:NR_Pt is used."
    data_stop = int_property('DAT:STOP',
                             doc="""
        The last data point that will be transferred.
        """)

    data_sync_sources = bool_property('DAT:SYNCSOU',
                                      inst_true='ON',
                                      inst_false='OFF')

    @property
    def data_source(self):
        """
        Gets/sets the data source for the oscilloscope. This will return
        the actual Channel/Math/DataSource object as if it was accessed
        through the usual `TekDPO70000.channel`, `TekDPO70000.math`, or
        `TekDPO70000.ref` properties.

        :type: `TekDPO70000.Channel` or `TekDPO70000.Math`
        """
        val = self.query('DAT:SOU?')
        if val[0:2] == 'CH':
            out = self.channel[int(val[2]) - 1]
        elif val[0:2] == 'MA':
            out = self.math[int(val[4]) - 1]
        elif val[0:2] == 'RE':
            out = self.ref[int(val[3]) - 1]
        else:
            raise NotImplementedError
        return out

    @data_source.setter
    def data_source(self, newval):
        if not isinstance(newval, self.DataSource):
            raise TypeError("{} is not a valid data source.".format(
                type(newval)))
        self.sendcmd("DAT:SOU {}".format(newval.name))

        # Some Tek scopes require this after the DAT:SOU command, or else
        # they will stop responding.
        time.sleep(0.02)

    horiz_acq_duration = unitful_property('HOR:ACQDURATION',
                                          u.second,
                                          readonly=True,
                                          doc="""
        The duration of the acquisition.
        """)

    horiz_acq_length = int_property('HOR:ACQLENGTH',
                                    readonly=True,
                                    doc="""
        The record length.
        """)

    horiz_delay_mode = bool_property('HOR:DEL:MOD',
                                     inst_true='1',
                                     inst_false='0')

    horiz_delay_pos = unitful_property('HOR:DEL:POS',
                                       u.percent,
                                       doc="""
        The percentage of the waveform that is displayed left of the center
        graticule.
        """)

    horiz_delay_time = unitful_property('HOR:DEL:TIM',
                                        u.second,
                                        doc="""
        The base trigger delay time setting.
        """)

    horiz_interp_ratio = unitless_property('HOR:MAI:INTERPR',
                                           readonly=True,
                                           doc="""
        The ratio of interpolated points to measured points.
        """)

    horiz_main_pos = unitful_property('HOR:MAI:POS',
                                      u.percent,
                                      doc="""
        The percentage of the waveform that is displayed left of the center
        graticule.
        """)

    horiz_unit = string_property('HOR:MAI:UNI')

    horiz_mode = enum_property('HOR:MODE', HorizontalMode)

    horiz_record_length_lim = int_property('HOR:MODE:AUTO:LIMIT',
                                           doc="""
        The recond length limit in samples.
        """)

    horiz_record_length = int_property('HOR:MODE:RECO',
                                       doc="""
        The recond length in samples. See `horiz_mode`; manual mode lets you
        change the record length, while the length is readonly for auto and
        constant mode.
        """)

    horiz_sample_rate = unitful_property('HOR:MODE:SAMPLER',
                                         u.Hz,
                                         doc="""
        The sample rate in samples per second.
        """)

    horiz_scale = unitful_property('HOR:MODE:SCA',
                                   u.second,
                                   doc="""
        The horizontal scale in seconds per division. The horizontal scale is
        readonly when `horiz_mode` is manual.
        """)

    horiz_pos = unitful_property('HOR:POS',
                                 u.percent,
                                 doc="""
        The position of the trigger point on the screen, left is 0%, right
        is 100%.
        """)

    horiz_roll = string_property('HOR:ROLL',
                                 bookmark_symbol='',
                                 doc="""
        Valid arguments are AUTO, OFF, and ON.
        """)

    trigger_state = enum_property('TRIG:STATE', TriggerState)

    # Waveform Transfer Properties
    outgoing_waveform_encoding = enum_property('WFMO:ENC',
                                               WaveformEncoding,
                                               doc="""
        Controls the encoding used for outgoing waveforms (instrument → host).
        """)

    outgoing_binary_format = enum_property("WFMO:BN_F",
                                           BinaryFormat,
                                           doc="""
        Controls the data type of samples when transferring waveforms from
        the instrument to the host using binary encoding.
        """)

    outgoing_byte_order = enum_property("WFMO:BYT_O",
                                        ByteOrder,
                                        doc="""
        Controls whether binary data is returned in little or big endian.
        """)

    outgoing_n_bytes = int_property("WFMO:BYT_N",
                                    valid_set=set((1, 2, 4, 8)),
                                    doc="""
        The number of bytes per sample used in representing outgoing
        waveforms in binary encodings.

        Must be either 1, 2, 4 or 8.
        """)

    # METHODS #

    def select_fastest_encoding(self):
        """
        Sets the encoding for data returned by this instrument to be the
        fastest encoding method consistent with the current data source.
        """
        self.sendcmd("DAT:ENC FAS")

    def force_trigger(self):
        """
        Forces a trigger event to happen for the oscilloscope.
        """
        self.sendcmd('TRIG FORC')

    # TODO: consider moving the next few methods to Oscilloscope.
    def run(self):
        """
        Enables the trigger for the oscilloscope.
        """
        self.sendcmd(":RUN")

    def stop(self):
        """
        Disables the trigger for the oscilloscope.
        """
        self.sendcmd(":STOP")
Example #7
0
    class Math(DataSource):
        """
        Class representing a math channel on the Tektronix DPO 70000.

        This class inherits from `TekDPO70000.DataSource`.

        .. warning:: This class should NOT be manually created by the user. It
            is designed to be initialized by the `TekDPO70000` class.
        """
        def __init__(self, parent, idx):
            self._parent = parent
            self._idx = idx + 1  # 1-based.

            # Initialize as a data source with name MATH{}.
            super(TekDPO70000.Math, self).__init__(parent,
                                                   "MATH{}".format(self._idx))

        def sendcmd(self, cmd):
            """
            Wraps commands sent from property factories in this class with
            identifiers for the specified math channel.

            :param str cmd: Command to send to the instrument
            """
            self._parent.sendcmd("MATH{}:{}".format(self._idx, cmd))

        def query(self, cmd, size=-1):
            """
            Wraps queries sent from property factories in this class with
            identifiers for the specified math channel.

            :param str cmd: Query command to send to the instrument
            :param int size: Number of characters to read from the response.
                Default value reads until a termination character is found.
            :return: The query response
            :rtype: `str`
            """
            return self._parent.query("MATH{}:{}".format(self._idx, cmd), size)

        class FilterMode(Enum):
            """
            Enum containing valid filter modes for a math channel on the
            TekDPO70000 series oscilloscope.
            """
            centered = "CENT"
            shifted = "SHIF"

        class Mag(Enum):
            """
            Enum containing valid amplitude units for a math channel on the
            TekDPO70000 series oscilloscope.
            """
            linear = "LINEA"
            db = "DB"
            dbm = "DBM"

        class Phase(Enum):
            """
            Enum containing valid phase units for a math channel on the
            TekDPO70000 series oscilloscope.
            """
            degrees = "DEG"
            radians = "RAD"
            group_delay = "GROUPD"

        class SpectralWindow(Enum):
            """
            Enum containing valid spectral windows for a math channel on the
            TekDPO70000 series oscilloscope.
            """
            rectangular = "RECTANG"
            hamming = "HAMM"
            hanning = "HANN"
            kaiser_besse = "KAISERB"
            blackman_harris = "BLACKMANH"
            flattop2 = "FLATTOP2"
            gaussian = "GAUSS"
            tek_exponential = "TEKEXP"

        define = string_property("DEF",
                                 doc="""
            A text string specifying the math to do, ex. CH1+CH2
            """)

        filter_mode = enum_property("FILT:MOD", FilterMode)

        filter_risetime = unitful_property("FILT:RIS", u.second)

        label = string_property("LAB:NAM",
                                doc="""
            Just a human readable label for the channel.
            """)

        label_xpos = unitless_property("LAB:XPOS",
                                       doc="""
            The x position, in divisions, to place the label.
            """)

        label_ypos = unitless_property(
            "LAB:YPOS",
            doc="""The y position, in divisions, to place the label.
            """)

        num_avg = unitless_property("NUMAV",
                                    doc="""
            The number of acquisistions over which exponential averaging is
            performed.
            """)

        spectral_center = unitful_property("SPEC:CENTER",
                                           u.Hz,
                                           doc="""
            The desired frequency of the spectral analyzer output data span
            in Hz.
            """)

        spectral_gatepos = unitful_property("SPEC:GATEPOS",
                                            u.second,
                                            doc="""
            The gate position. Units are represented in seconds, with respect
            to trigger position.
            """)

        spectral_gatewidth = unitful_property("SPEC:GATEWIDTH",
                                              u.second,
                                              doc="""
            The time across the 10-division screen in seconds.
            """)

        spectral_lock = bool_property("SPEC:LOCK",
                                      inst_true="ON",
                                      inst_false="OFF")

        spectral_mag = enum_property("SPEC:MAG",
                                     Mag,
                                     doc="""
            Whether the spectral magnitude is linear, db, or dbm.
            """)

        spectral_phase = enum_property("SPEC:PHASE",
                                       Phase,
                                       doc="""
            Whether the spectral phase is degrees, radians, or group delay.
            """)

        spectral_reflevel = unitless_property("SPEC:REFL",
                                              doc="""
            The value that represents the topmost display screen graticule.
            The units depend on spectral_mag.
            """)

        spectral_reflevel_offset = unitless_property("SPEC:REFLEVELO")

        spectral_resolution_bandwidth = unitful_property("SPEC:RESB",
                                                         u.Hz,
                                                         doc="""
            The desired resolution bandwidth value. Units are represented in
            Hertz.
            """)

        spectral_span = unitful_property("SPEC:SPAN",
                                         u.Hz,
                                         doc="""
            Specifies the frequency span of the output data vector from the
            spectral analyzer.
            """)

        spectral_suppress = unitless_property("SPEC:SUPP",
                                              doc="""
            The magnitude level that data with magnitude values below this
            value are displayed as zero phase.
            """)

        spectral_unwrap = bool_property("SPEC:UNWR",
                                        inst_true="ON",
                                        inst_false="OFF",
                                        doc="""
            Enables or disables phase wrapping.
            """)

        spectral_window = enum_property("SPEC:WIN", SpectralWindow)

        threshhold = unitful_property("THRESH",
                                      u.volt,
                                      doc="""
            The math threshhold in volts
            """)

        unit_string = string_property("UNITS",
                                      doc="""
            Just a label for the units...doesn"t actually change anything.
            """)

        autoscale = bool_property("VERT:AUTOSC",
                                  inst_true="ON",
                                  inst_false="OFF",
                                  doc="""
            Enables or disables the auto-scaling of new math waveforms.
            """)

        position = unitless_property("VERT:POS",
                                     doc="""
            The vertical position, in divisions from the center graticule.
            """)

        scale = unitful_property("VERT:SCALE",
                                 u.volt,
                                 doc="""
            The scale in volts per division. The range is from
            ``100e-36`` to ``100e+36``.
            """)

        def _scale_raw_data(self, data):
            # TODO: incorperate the unit_string somehow
            if numpy:
                return self.scale * (
                    (TekDPO70000.VERT_DIVS / 2) * data.astype(float) /
                    (2**15) - self.position)

            scale = self.scale
            position = self.position
            rval = tuple(scale * ((TekDPO70000.VERT_DIVS / 2) * d /
                                  (2**15) - position)
                         for d in map(float, data))
            return rval
Example #8
0
class Wavetek39A(SCPIInstrument, FunctionGenerator):
    """
    The Wavetek 39A is a 40MS/s function generator. Arbitraty waveforms can have up to 65536 horizontal points,
    vertical range is -2048 to +2047 (12 bit), maximum peak-to-peak is 20V. Up to 100 waveforms, 256 KB NVRAM.
    Channel memory is 64 KB.

    Example usage:

    >>> import instruments as ik
    >>> import instruments.units as u
    >>> fg = ik.wavetek.Wavetek39A.open_gpib('/dev/ttyUSB0', 1)
    >>> fg.frequency = 1 * u.MHz
    >>> print(fg.offset)
    >>> fg.function = fg.Function.triangle
    """
    def __init__(self, filelike):
        super(Wavetek39A, self).__init__(filelike)
        self.terminator = ""

    # CONSTANTS #

    _UNIT_MNEMONICS = {
        FunctionGenerator.VoltageMode.peak_to_peak: "VPP",
        FunctionGenerator.VoltageMode.rms: "VRMS",
        FunctionGenerator.VoltageMode.dBm: "DBM",
    }

    _MNEMONIC_UNITS = dict(
        (mnem, unit) for unit, mnem in _UNIT_MNEMONICS.items())

    # FunctionGenerator CONTRACT #

    def _get_amplitude_(self):
        return (
            0.0,  # amplitude is writeonly (FIXME: trigger exception instead?)
            self._MNEMONIC_UNITS["VPP"])

    def _set_amplitude_(self, magnitude, units):
        self.sendcmd("AMPUNIT {}".format(self._UNIT_MNEMONICS[units]))
        self.sendcmd("AMPL {}".format(magnitude))

    # ENUMS ##

    class Function(Enum):
        """
        Enum containing valid output function modes for the Wavetek 39A
        """
        #: sinusoidal
        sinusoid = "SINE"
        #: square
        square = "SQUARE"
        #: triangular
        triangle = "TRIANG"
        #: constant voltage
        dc = "DC"
        #: positive ramp
        positive_ramp = "POSRMP"
        #: negative ramp
        negative_ramp = "NEGRMP"
        #: cosine
        cosine = "COSINE"
        #: haversine, sin^2(x/2)=(1-cos x)/2
        haversine = "HAVSIN"
        #: havercosine, (1+cos x)/2
        havercosine = "HAVCOS"
        #: sinc(x)=sin(x)/x
        sinc = "SINC"
        #: pulse
        pulse = "PULSE"
        #: pulse train
        pulse_train = "PULSTRN"
        #: arbitrary waveform
        arbitrary = "ARB"
        #: sequence of up to 16 waveforms
        sequence = "SEQ"

    class ZLoad(Enum):
        """
        Enum containing the output load settings
        """
        #: 50 Ohm termination
        Z50 = "50"
        #: 600 Ohm termination
        Z600 = "600"
        #: Z=ininity, open circuit
        OPEN = "OPEN"

    class OutputMode(Enum):
        """
        Enum containing the output mode settings
        """
        #: normal (non-inverted) output
        normal = "NORMAL"
        #: inverted output (around the same offset if offset is non-zero!)
        invert = "INVERT"

    class Mode(Enum):
        """
        Enum containing the mode settings
        """
        #: continuous operation
        cont = "CONT"
        continuous = "CONT"
        #: gated
        gate = "GATE"
        gated = "GATE"
        #: triggered burst mode (each active edge of the trigger signal produces one
        #: burst of the waveform)
        trig = "TRIG"
        triggered = "TRIG"
        #: sweep
        sweep = "SWEEP"
        #: tone mode
        tone = "TONE"

    class SweepType(Enum):
        """
        Enum containing the sweep type
        """
        #: continuous operation
        cont = "CONT"
        continuous = "CONT"
        #: triggered sweep (front TRIG IN socket, remote command, manually with MAN TRIG key)
        #: Sweep is initiated on the rising edge of the trigger signal.
        trig = "TRIG"
        triggered = "TRIG"
        #: triggered, hold and reset
        triggered_hold_reset = "THLDRST"
        #: manual sweeping (using rotary control or cursor keys)
        manual = "MANUAL"

    class SweepDirection(Enum):
        """
        Enum containing the sweep direction
        """
        #: up
        up = "UP"
        #: down
        down = "DOWN"
        #: up/down
        updn = "UPDN"
        updown = "UPDN"
        #: down/up
        dnup = "DNUP"
        downup = "DNUP"

    class SweepSpacing(Enum):
        """
        Enum containing the sweep spacing
        """
        #: linear
        lin = "LIN"
        linear = "LIN"
        #: logarithmic
        log = "LOG"
        logarithmic = "LOG"

    class SweepManual(Enum):
        """
        Enum containing the sweep manual parameters [???]
        """
        #: up
        up = "UP"
        #: down
        down = "DOWN"

    class SweepManualSpeed(Enum):
        """
        Enum containing the manual sweep step size.
        """
        #: fast
        fast = "FAST"
        #: slow
        slow = "SLOW"

    class SweepManualWrap(Enum):
        """
        Enum containing the manual sweep wrapping.
        """
        #: wrap on
        wrapon = "WRAPON"
        #: wrap off
        wrapoff = "WRAPOFF"

    class SyncOutMode(Enum):
        """
        Enum containing sync output settings
        """
        #: automatic
        auto = "AUTO"
        #: waveform sync (sync marker, for standward waveform raising edge at 0 deg point,
        #: for arbitrary waveform coincident with the first point)
        waveform_sync = "WFMSYNC"
        #: position marker for arbitrary waveform, for standard waveforms short pulse at the start of cycle
        position_marker = "POSNMKR"
        #: burst sequence done (low while the waveform is active)
        burst_done = "BSTDONE"
        #: sync signal low during the last cycle of the last waveform in a sequence, high at all other times
        sequence_sync = "SEQSYNC"
        #: positive going version of the trigger signal
        trigger = "TRIGGER"
        #: goes high at the start of the sweep, goes low at the end of the sweep
        sweep = "SWPTRG"
        #: positive edge coincident with the start of the current waveform
        phase_lock = "PHASLOC"

    class TriggerInput(Enum):
        """
        Enum containing trigger input settings
        """
        internal = "INT"
        external = "EXT"
        manual = "MAN"

    class TriggerInputEdge(Enum):
        """
        Enum containing external trigger input edge
        """
        positive = "POS"
        negative = "NEG"

    class HoldMode(Enum):
        """
        Enum containing the hold mode
        """
        #: on/off are the same as pressing the MAN HOLD key
        on = "ON"
        off = "OFF"
        #: enable/disable enable or disable the action of the MAN HOLD key
        enable = "ENAB"
        disable = "DISAB"

    class Filter(Enum):
        """
        Enum containing the output filter types
        """
        #: automatic (most appropriate for the current waveform)
        auto = "AUTO"
        #: 10MHz elliptic
        elliptic10 = "EL10"
        #: 16MHz elliptic (sine, cosine, haversine, havercosine above 10Mhz)
        elliptic16 = "EL16"
        #: 10MHz Bessel (positive and negative ramps, arbitrary and sequence)
        Bessel = "BESS"
        #: no output filtering (square wave, pulse, pulse trains)
        none = "NONE"

    class BeepMode(Enum):
        """
        Enum containing beep modes
        """
        on = "ON"
        off = "OFF"
        warnings = "WARN"
        errors = "ERROR"

    # PROPERTIES ##

    frequency = unitful_property(command="WAVFREQ",
                                 units=u.Hz,
                                 writeonly=True,
                                 doc="""
        Sets the output frequency.

        :units: As specified, or assumed to be :math:`\\text{Hz}` otherwise.
        :type: `float` or `~quantities.quantity.Quantity`
        """)

    period = unitful_property(command="WAVPER",
                              units=u.s,
                              writeonly=True,
                              doc="""
        Sets the output period.

        :units: As specified, or assumed to be :math:`\\text{s}` otherwise.
        :type: `float` or `~quantities.quantity.Quantity`
        """)

    clock_frequency = unitful_property(command="CLKFREQ",
                                       units=u.Hz,
                                       writeonly=True,
                                       doc="""
        Sets the arbitrary sample clock frequency. Range 0.1Hz to 40MHz.

        :units: As specified, or assumed to be :math:`\\text{Hz}` otherwise.
        :type: `float` or `~quantities.quantity.Quantity`
        """)

    clock_period = unitful_property(command="CLKPER",
                                    units=u.s,
                                    writeonly=True,
                                    doc="""
        Sets the arbitrary sample clock period.

        :units: As specified, or assumed to be :math:`\\text{s}` otherwise.
        :type: `float` or `~quantities.quantity.Quantity`
        """)

    zload = enum_property(command="ZLOAD",
                          enum=ZLoad,
                          writeonly=True,
                          doc="""
        Sets the output load.

        :type: `~Wavetek39A.ZLoad`
        """)

    offset = unitful_property(command="DCOFFS",
                              units=u.volt,
                              writeonly=True,
                              doc="""
        Sets the offset voltage for the output waveform.

        :units: As specified, or assumed to be :math:`\\text{V}` otherwise.
        :type: `float` or `~quantities.quantity.Quantity`
        """)

    function = enum_property(command="WAVE",
                             enum=Function,
                             writeonly=True,
                             doc="""
        Sets the output function of the function generator.

        :type: `~Wavetek39A.Function`
        """)

    pulse_period = unitful_property(command="PULSPER",
                                    units=u.s,
                                    writeonly=True,
                                    doc="""
        Sets the pulse period.

        :units: As specified, or assumed to be :math:`\\text{s}` otherwise.
        :type: `float` or `~quantities.quantity.Quantity`
        """)

    pulse_width = unitful_property(command="PULSWID",
                                   units=u.s,
                                   writeonly=True,
                                   doc="""
        Sets the pulse width.

        :units: As specified, or assumed to be :math:`\\text{s}` otherwise.
        :type: `float` or `~quantities.quantity.Quantity`
        """)

    pulse_delay = unitful_property(command="PULSDLY",
                                   units=u.s,
                                   writeonly=True,
                                   doc="""
        Sets the pulse delay.

        :units: As specified, or assumed to be :math:`\\text{s}` otherwise.
        :type: `float` or `~quantities.quantity.Quantity`
        """)

    pulse_train_length = int_property(command="PULSTRNLEN",
                                      writeonly=True,
                                      doc="""
        Sets the number of pulses in the pulse-train.

        :units: Number.
        :type: `int`
        """)

    pulse_train_period = unitful_property(command="PULSTRNPER",
                                          units=u.s,
                                          writeonly=True,
                                          doc="""
        Sets the pulse-train period.

        :units: As specified, or assumed to be :math:`\\text{s}` otherwise.
        :type: `float` or `~quantities.quantity.Quantity`
        """)

    pulse_train_base_line = unitful_property(command="PULSTRNBASE",
                                             units=u.V,
                                             writeonly=True,
                                             doc="""
        Sets the pulse-train base line voltage.

        :units: As specified, or assumed to be :math:`\\text{V}` otherwise.
        :type: `float` or `~quantities.quantity.Quantity`
        """)

    # pulse_train_level = unitful_property(  ## has two parameters!

    arbitrary = string_property(command="ARB",
                                writeonly=True,
                                bookmark_symbol='',
                                doc="""
        Select an arbitray waveform for output.

        :type: `str`
        """)

    arbitrary_list_ch = string_property(command="ARBLISTCH",
                                        readonly=True,
                                        bookmark_symbol='',
                                        doc="""
        List of all arbitrary waveforms in the channel's memory.

        :type: `str`
        """)

    arbitrary_list = string_property(command="ARBLIST",
                                     readonly=True,
                                     bookmark_symbol='',
                                     doc="""
        List of all arbitrary waveforms in the backup memory.

        :type: `str`
        """)

    def arbitrary_delete(self, cpd):
        """
        Delete an arbitrary wavefrom from backup memory.
        A waveform used by a non-active sequence can be deleted but the sequence will not subsequently
        run properly and should be modified to exclude the deleted waveform.

        :type: `str`
        """
        check_arb_name(cpd)
        self.sendcmd("ARBDELETE {}".format(cpd))

    def arbitrary_clear(self, cpd):
        """
        Delete an arbitrary wavefrom from channel memory.
        A waveform cannot be deleted from a channel’s memory if it is running on that channel.
        If an arb waveform sequence is running no waveforms can be deleted from that channel,
        whether they are used in the sequence or not.
        Waveforms must be deleted from the channel’s memory before they can be deleted from the back-up memory.
        (i.e. call arbitrary_clear before arbitrary_delete)

        :type: `str`
        """
        check_arb_name(cpd)
        self.sendcmd("ARBCLR {}".format(cpd))

    def arbitrary_create(self, cpd, nrf):
        """
        Create a new blank arbitrary waveform.

        :type cpd: `str`
        :type nrf: `int`
        """
        check_arb_name(cpd)
        self.sendcmd("ARBCREATE {},{}".format(cpd, nrf))

    def _arbitrary_send_data_csv(self, cpd, csv, command):
        length, csvint = prepare_for_sending(cpd, csv)
        cmd = "{} {},{},{}".format(command, cpd, str(length),
                                   ",".join([str(i) for i in csvint]))
        self.sendcmd(cmd)

    def _arbitrary_send_data(self, cpd, csv, command):
        length, csvint = prepare_for_sending(cpd, csv)
        bin_data = struct.pack('>{}h'.format(length), *csvint)
        size_str = str(len(bin_data))
        len_size_str = len(size_str)
        header = '#{}{}'.format(len_size_str, size_str)
        cmd = "{} {},{},{}{}".format(command, cpd, str(length), header,
                                     bin_data)
        self.sendcmd(cmd)

    def arbitrary_define_csv(self, cpd, csv):
        """
        Define a new or existing arbitrary waveform from a list.

        :type cpd: `str`
        :type csv: `iterable`
        """
        self._arbitrary_send_data_csv(cpd, csv, "ARBDEFCSV")

    def arbitrary_define(self, cpd, csv):
        """
        Define a new or existing arbitrary waveform from a list.

        :type cpd: `str`
        :type csv: `iterable`
        """
        self._arbitrary_send_data(cpd, csv, "ARBDEF")

    def arbitrary_get_data_csv(self, cpd):
        """
        Returns the arbitrary waveform data as ASCII data.

        :rtype: `str`
        """
        check_arb_name(cpd)
        self.query("ARBDATACSV? {}".format(cpd))

    def arbitray_edit_limits(self, nrf1, nrf2):
        """
        Define editing limits for the currently edited arbitrary waveform.

        :type nrf1: `int`
        :type nrf2: `int`
        """
        self.sendcmd("ARBEDLMTS {},{}".format(nrf1, nrf2))

    def arbitrary_data_csv(self, cpd, csv):
        self._arbitrary_send_data_csv(cpd, csv, "ARBDATACSV")

    def arbitrary_data(self, cpd, csv):
        self._arbitrary_send_data(cpd, csv, "ARBDATA")

    phase = unitful_property(command="PHASE",
                             units=u.degree,
                             writeonly=True,
                             doc="""
        Sets the phase for the output waveform.

        :units: As specified, or assumed to be degrees (:math:`{}^{\\circ}`)
            otherwise.
        :type: `float` or `~quantities.quantity.Quantity`
        """)

    sweep_start_frequency = unitful_property(command="SWPSTARTFRQ",
                                             units=u.Hz,
                                             writeonly=True,
                                             doc="""
        Sets the sweep start frequency. Minimum is 1 mHz.

        :units: As specified, or assumed to be Hz otherwise.
        :type: `float` or `~quantities.quantity.Quantity`   
        """)

    sweep_stop_frequency = unitful_property(command="SWPSTOPFRQ",
                                            units=u.Hz,
                                            writeonly=True,
                                            doc="""
        Sets the sweep stop frequency. Maximum is 16 MHz for all waveforms,
        including triangle, ramp and square wave.

        :units: As specified, or assumed to be Hz otherwise.
        :type: `float` or `~quantities.quantity.Quantity`   
        """)

    sweep_centre_frequency = unitful_property(command="SWPCENTFRQ",
                                              units=u.Hz,
                                              writeonly=True,
                                              doc="""
        Sets the sweep centre frequency.

        :units: As specified, or assumed to be Hz otherwise.
        :type: `float` or `~quantities.quantity.Quantity`   
        """)

    sweep_span = unitful_property(command="SWPSPAN",
                                  units=u.Hz,
                                  writeonly=True,
                                  doc="""
        Sets the sweep frequency span.

        :units: As specified, or assumed to be Hz otherwise.
        :type: `float` or `~quantities.quantity.Quantity`   
        """)

    sweep_time = unitful_property(command="SWPTIME",
                                  units=u.s,
                                  writeonly=True,
                                  doc="""
        Sets the sweep time. 0.03s to 999s with 3-digit resolution.

        :units: As specified, or assumed to be s otherwise.
        :type: `float` or `~quantities.quantity.Quantity`   
        """)

    sweep_type = enum_property(command="SWPTYPE",
                               enum=SweepType,
                               writeonly=True,
                               doc="""
        Sets the sweep type.

        :type: `~Wavetek39A.SweepType`
        """)

    sweep_direction = enum_property(command="SWPDIRN",
                                    enum=SweepDirection,
                                    writeonly=True,
                                    doc="""
        Sets the sweep direction.

        :type: `~Wavetek39A.SweepDirection`
        """)

    sweep_sync = bool_property("SWPSYNC",
                               inst_true="ON",
                               inst_false="OFF",
                               writeonly=True,
                               doc="""
        Sets the sweep syncs on and off. If on (default), the generator steps from the stop
        frequency to zero frequency and then starts the next sweep from the first point of the
        waveform, synchronized to the internally generated trigger signal.
        """)

    sweep_spacing = enum_property(command="SWPSPACING",
                                  enum=SweepSpacing,
                                  writeonly=True,
                                  doc="""
        Sets the sweep spacing.

        :type: `~Wavetek39A.SweepSpacing`
        """)

    sweep_marker = unitful_property(command="SWPMARKER",
                                    units=u.Hz,
                                    writeonly=True,
                                    doc="""
        Sets the sweep marker (rear panel CURSOR/MARKER OUT socket).

        :units: As specified, or assumed to be Hz otherwise.
        :type: `float` or `~quantities.quantity.Quantity`
        """)

    sweep_manual_speed = enum_property(command="SWPMANUAL",
                                       enum=SweepManualSpeed,
                                       writeonly=True,
                                       doc="""
        Sets the manual step size.

        :type: `~Wavetek39A.SweepManualSpeed`
        """)

    sweep_manual_wrap = bool_property("SWPMANUAL",
                                      inst_true="WRAPON",
                                      inst_false="WRAPOFF",
                                      writeonly=True,
                                      doc="""
        Sets the sweep wrapping on/off.
        """)

    output = bool_property("OUTPUT",
                           inst_true="ON",
                           inst_false="OFF",
                           writeonly=True,
                           doc="""
        Sets the output on and off.
        """)

    output_mode = enum_property(command="OUTPUT",
                                enum=OutputMode,
                                writeonly=True,
                                doc="""
        Sets the output mode (normal vs. inverted).

        :type: `~Wavetek39A.OutputMode`
        """)

    mode = enum_property(command="MODE",
                         enum=Mode,
                         writeonly=True,
                         doc="""
        Sets the mode.

        :type: `~Wavetek39A.Mode`
        """)

    syncout = bool_property("SYNCOUT",
                            inst_true="ON",
                            inst_false="OFF",
                            writeonly=True,
                            doc="""
        Sets the sync output on and off.
        """)

    syncout_mode = enum_property(command="SYNCOUT",
                                 enum=SyncOutMode,
                                 writeonly=True,
                                 doc="""
        Sets the sync output mode.

        :type: `~Wavetek39A.SyncOut`
        """)

    trigger_input = enum_property(command="TRIGIN",
                                  enum=TriggerInput,
                                  writeonly=True,
                                  doc="""
        Sets the trigger input.

        :type: `~Wavetek39A.TriggerInput`
        """)

    trigger_input_edge = enum_property(command="TRIGIN",
                                       enum=TriggerInputEdge,
                                       writeonly=True,
                                       doc="""
        Sets the edge for external trigger input.

        :type: `~Wavetek39A.TriggerInputEdge`
        """)

    trigger_period = unitful_property(command="TRIGPER",
                                      units=u.s,
                                      writeonly=True,
                                      doc="""
        Sets the internal trigger period.

        :units: As specified, or assumed to be seconds otherwise.
        :type: `float` or `~quantities.quantity.Quantity`
        """)

    def reset(self):
        """
        Resets the instrument parameters to their default values.
        """
        self.sendcmd("*RST")

    def force_trigger(self):
        """
        Force a trigger
        """
        self.sendcmd("FORCETRG")

    burst_count = int_property(command="BSTCNT",
                               writeonly=True,
                               doc="""
        Sets the burst count.

        :units: Number of cycles.
        :type: `int`
        """)

    def recall(self, nrf):
        """
        Recall the set up in store 'nrf'. 0-9. 0 are default settings.
        """
        if not 0 <= nrf <= 9:
            raise RuntimeError("out of range {}".format(nrf))
        self.sendcmd("*RCL {}".format(nrf))

    def save(self, nrf):
        """
        Save the set up in store 'nrf'. 1-9.
        """
        if not 1 <= nrf <= 9:
            raise RuntimeError("out of range {}".format(nrf))
        self.sendcmd("*SAV {}".format(nrf))

    def manual_trigger(self):
        """
        Same as pressing the MAN TRIG key.
        """
        self.sendcmd("*TRG")

    holdmode = enum_property(command="HOLD",
                             enum=HoldMode,
                             writeonly=True,
                             doc="""
        Sets the hold mode.

        :type: `~Wavetek39A.HoldMode`
        """)

    filter = enum_property(command="FILTER",
                           enum=Filter,
                           writeonly=True,
                           doc="""
        Sets the output filter type.

        :type: `~Wavetek39A.Filter`
        """)

    beepmode = enum_property(command="BEEPMODE",
                             enum=BeepMode,
                             writeonly=True,
                             doc="""
        Sets the beep mode.

        :type: `~Wavetek39A.BeepMode`
        """)

    def beep(self):
        """
        Beep once
        """
        self.sendcmd("BEEP")

    def local(self):
        """
        Returns the instrument to local operation and unlock the keyboard.
        """
        self.sendcmd("LOCAL")