Exemplo n.º 1
0
    def set_samplerate(self, samplerate):
        """ Set the sample rate of the Phasemeter.

        Options are {'veryslow','slow','medium','fast','veryfast','ultrafast'}
        corresponding to 30.5176 smp/s, 122.0703 smp/s, 1.9531 ksmp/s,
        15.625 ksmp/s, 125 ksps/s.

        :type samplerate: string, {'veryslow','slow','medium','fast',
        'veryfast','ultrafast'}
        :param samplerate: Desired sample rate

        :raises ValueError: If samplerate parameter is invalid.
        """
        _str_to_samplerate_index = {
            'ultrafast': _PM_LOGRATE_ULTRA_FAST,
            'veryfast': _PM_LOGRATE_VERY_FAST,
            'fast': _PM_LOGRATE_FAST,
            'medium': _PM_LOGRATE_MEDIUM,
            'slow': _PM_LOGRATE_SLOW,
            'veryslow': _PM_LOGRATE_VERY_SLOW
        }
        N = _utils.str_to_val(_str_to_samplerate_index, samplerate,
                              'samplerate')

        self.output_decimation = 2**N
        self.output_shift = N
        self.timestep = 1.0 / (_PM_UPDATE_RATE / self.output_decimation)
        log.info("Samplerate set to %.2f smp/s",
                 _PM_UPDATE_RATE / float(self.output_decimation))
Exemplo n.º 2
0
    def set_trigger(self,
                    source,
                    edge,
                    level,
                    minwidth=None,
                    maxwidth=None,
                    hysteresis=10e-3,
                    hf_reject=False,
                    mode='auto'):
        """ Sets trigger source and parameters.

        :type source: string, {'in1','in2','out1','out2','ext'}
        :param source: Trigger Source. May be either an input or output
                channel, or external. The output options allow triggering off
                an internally-generated waveform. External refers to the
                back-panel connector of the same name, allowing triggering
                from an externally-generated digital [LV]TTL or CMOS signal.

        :type edge: string, {'rising','falling','both'}
        :param edge: Which edge to trigger on. In Pulse Width modes this
                specifies whether the pulse is positive (rising)
                or negative (falling), with the 'both' option being invalid.

        :type level: float, [-10.0, 10.0] volts
        :param level: Trigger level

        :type minwidth: float, seconds
        :param minwidth: Minimum Pulse Width.
                0 <= minwidth < (2^32/samplerate). Can't be used with maxwidth.

        :type maxwidth: float, seconds
        :param maxwidth: Maximum Pulse Width.
                0 <= maxwidth < (2^32/samplerate). Can't be used with minwidth.

        :type hysteresis: float, [100e-6, 1.0] volts
        :param hysteresis: Hysteresis around trigger point.

        :type hf_reject: bool
        :param hf_reject: Enable high-frequency noise rejection

        :type mode: string, {'auto', 'normal'}
        :param mode: Trigger mode.

        .. note::
            Traditional Oscilloscopes have a "Single Trigger" mode that
            captures an event then pauses the instrument. In pymoku, there is
            no need to pause the instrument as you can simply choose to
            continue using the last captured frame.  That is, set trigger
            ``mode='normal'`` then retrieve a single frame using :any:
            `get_data <pymoku.instruments.Oscilloscope.get_data>`
            or :any:`get_realtime_data
            <pymoku.instruments.Oscilloscope.get_realtime_data>`
            with ``wait=True``.

        """
        source = _utils.str_to_val(_OSC_SOURCES, source, 'trigger source')
        self._set_trigger(source, edge, level, minwidth, maxwidth, hysteresis,
                          hf_reject, mode)
Exemplo n.º 3
0
    def set_trigger(self,
                    source,
                    edge,
                    level,
                    minwidth=None,
                    maxwidth=None,
                    hysteresis=10e-3,
                    hf_reject=False,
                    mode='auto'):
        """
        Set the trigger source for the monitor channel signals. This can be
        either of the input or monitor signals, or the external input.

        :type source: string, {'in1','in2','A','B','ext'}
        :param source: Trigger Source. May be either an input or monitor
                       channel (as set by
                       :py:meth:`~pymoku.instruments.LockInAmp.set_monitor`),
                       or external. External refers
                       to the back-panel connector of the same name, allowing
                       triggering from an
                       externally-generated digital [LV]TTL or CMOS signal.

        :type edge: string, {'rising','falling','both'}
        :param edge: Which edge to trigger on. In Pulse Width modes this
                     specifies whether the pulse is positive (rising)
                     or negative (falling), with the 'both' option being
                     invalid.

        :type level: float, [-10.0, 10.0] volts
        :param level: Trigger level

        :type minwidth: float, seconds
        :param minwidth: Minimum Pulse Width.
                         0 <= minwidth < (2^32/samplerate).
                         Can't be used with maxwidth.

        :type maxwidth: float, seconds
        :param maxwidth: Maximum Pulse Width.
                         0 <= maxwidth < (2^32/samplerate).
                         Can't be used with minwidth.

        :type hysteresis: float, [100e-6, 1.0] volts
        :param hysteresis: Hysteresis around trigger point.

        :type hf_reject: bool
        :param hf_reject: Enable high-frequency noise rejection

        :type mode: string, {'auto', 'normal'}
        :param mode: Trigger mode.
        """
        # Define the trigger sources appropriate to the LockInAmp instrument
        source = _utils.str_to_val(_LIA_OSC_SOURCES, source, 'trigger source')

        # This function is the portion of set_trigger shared among instruments
        # with embedded scopes.
        self._set_trigger(source, edge, level, minwidth, maxwidth, hysteresis,
                          hf_reject, mode)
    def set_xmode(self, xmode):
        """
        Set rendering mode for the horizontal axis.

        :type xmode: string, {'sweep','fullframe'}
        :param xmode:
            Respectively; Sweep Mode (bode function sweeping across the screen)
            or Full Frame (like sweep, but waits for the frame to be
            completed).
        """
        _str_to_xmode = {'sweep': SWEEP, 'fullframe': FULL_FRAME}
        xmode = _utils.str_to_val(_str_to_xmode, xmode, 'X-mode')
        self.x_mode = xmode
Exemplo n.º 5
0
    def set_xmode(self, xmode):
        """
        Set rendering mode for the horizontal axis.

        :type xmode: string, {'roll','sweep','fullframe'}
        :param xmode:
            Respectively; Roll Mode (scrolling), Sweep Mode (normal
            oscilloscope trace sweeping across the screen) or Full Frame
            (like sweep, but waits for the frame to be completed).
        """
        _str_to_xmode = {
            'roll': _OSC_ROLL,
            'sweep': _OSC_SWEEP,
            'fullframe': _OSC_FULL_FRAME
        }
        xmode = _utils.str_to_val(_str_to_xmode, xmode, 'X-mode')
        self.x_mode = xmode
Exemplo n.º 6
0
    def set_source(self, ch, source, lmode='round'):
        """ Sets the source of the channel data to either the analog input
        or internally looped-back digital output.

        This feature allows the user to preview the Waveform Generator outputs.

        :type ch: int; {1,2}
        :param ch: Channel Number

        :type source: string, {'in1','in2','out1','out2','ext'}
        :param source: Where the specified channel should source data from
                (either the input or internally looped back output)

        :type lmode: string, {'clip','round'}
        :param lmode: DAC Loopback mode (ignored 'in' sources)
        """
        # TODO: Add loopback mode functionality
        source = _utils.str_to_val(_OSC_SOURCES, source, 'channel data source')
        self._set_source(ch, source)
Exemplo n.º 7
0
    def _set_trigger(self, source, edge, level, minwidth, maxwidth, hysteresis,
                     hf_reject, mode):
        if (self._moku.get_hw_version() == 1.0) and source == _OSC_SOURCE_EXT:
            raise InvalidConfigurationException(
                'External trigger source is not available on your hardware.')

        # Convert the input parameter strings to bit-value mappings
        _utils.check_parameter_valid('range', level,
                                     [_OSC_TRIGLVL_MIN, _OSC_TRIGLVL_MAX],
                                     'trigger level', 'Volts')
        _utils.check_parameter_valid('bool', hf_reject,
                                     'High-frequency reject enable')
        _utils.check_parameter_valid('set',
                                     mode, ['auto', 'normal'],
                                     desc='mode')
        _utils.check_parameter_valid('range', hysteresis, [100e-6, 1.0],
                                     'hysteresis', 'Volts')
        if not (maxwidth is None or minwidth is None):
            raise InvalidConfigurationException("Can't set both 'minwidth' "
                                                "and 'maxwidth' for Pulse "
                                                "Width trigger mode. Choose "
                                                "one.")
        if (maxwidth or minwidth) and (edge == 'both'):
            raise InvalidConfigurationException("Can't set trigger edge type"
                                                " 'both' in Pulse Width "
                                                "trigger mode. Choose one of "
                                                "{'rising','falling'}.")

        _str_to_edge = {
            'rising': Trigger.EDGE_RISING,
            'falling': Trigger.EDGE_FALLING,
            'both': Trigger.EDGE_BOTH
        }
        edge = _utils.str_to_val(_str_to_edge, edge, 'edge type')

        self.hf_reject = hf_reject

        if mode == 'auto':
            # TODO these should scale with the timebase
            self.auto_timer = 20.0
            self.auto_holdoff = 5
        elif mode == 'normal':
            self.auto_timer = 0.0
            self.auto_holdoff = 0

        self.trig_ch = source
        # Locally store user settings and calculate regs at commit-time
        self._trig_level = level
        self._trig_duration = minwidth or maxwidth or 0.0
        self._trig_hysteresis = hysteresis

        self._trigger.edge = edge
        self._trigger.mode = mode
        if maxwidth:
            self._trigger.trigtype = Trigger.TYPE_PULSE
            self._trigger.pulsetype = Trigger.PULSE_MAX
        elif minwidth:
            self._trigger.trigtype = Trigger.TYPE_PULSE
            self._trigger.pulsetype = Trigger.PULSE_MIN
        else:
            self._trigger.trigtype = Trigger.TYPE_EDGE
Exemplo n.º 8
0
    def set_trigger(self,
                    source,
                    edge,
                    level,
                    minwidth=None,
                    maxwidth=None,
                    hysteresis=10e-2,
                    hf_reject=False,
                    mode='auto',
                    trig_on_scan_rising=False):
        """

        Set the trigger source for the monitor channel signals. This can be
        either of the input or monitor signals, the external input or the
        scan output.

        :type source: string, {'in1','in2','scan','A','B','ext'}
        :param source: Trigger Source. May be either an input or monitor
        channel (as set by
                :py:meth:`~pymoku.instruments.LockInAmp.set_monitor`),
                external or the scan output. External refers to the back-panel
                connector of the same name, allowing triggering from an
                externally-generated digital [LV]TTL or CMOS signal.

        :type edge: string, {'rising','falling','both'}
        :param edge: Which edge to trigger on. In Pulse Width modes this
        specifies whether the pulse is positive (rising) or negative
        (falling), with the 'both' option being invalid.

        :type level: float, [-10.0, 10.0] volts
        :param level: Trigger level

        :type minwidth: float, seconds
        :param minwidth: Minimum Pulse Width.
            0 <= minwidth < (2^32/samplerate). Can't be used with maxwidth.

        :type maxwidth: float, seconds
        :param maxwidth: Maximum Pulse Width.
            0 <= maxwidth < (2^32/samplerate). Can't be used with minwidth.

        :type hysteresis: float, [100e-6, 1.0] volts
        :param hysteresis: Hysteresis around trigger point.

        :type hf_reject: bool
        :param hf_reject: Enable high-frequency noise rejection

        :type mode: string, {'auto', 'normal'}
        :param mode: Trigger mode.

        :type trig_on_scan_rising: bool
        :param trig_on_scan_rising: trigger only during rising portion of scan
            signal.
        """
        _utils.check_parameter_valid('set', source,
                                     ['in1', 'in2', 'scan', 'A', 'B', 'ext'],
                                     'trigger source')
        _utils.check_parameter_valid('set', edge,
                                     ['rising', 'falling', 'both'],
                                     'trigger edge')
        _utils.check_parameter_valid('range',
                                     level, [-10.0, 10.0],
                                     desc='trigger level',
                                     units='volts')

        if minwidth is not None:
            _utils.check_parameter_valid('range',
                                         minwidth, [0, 2**32 / 62.5e6],
                                         desc='PWM triggering minwidth',
                                         units='seconds')
        if maxwidth is not None:
            _utils.check_parameter_valid('range',
                                         minwidth, [0, 2**32 / 62.5e6],
                                         desc='PWM triggering maxwidth',
                                         units='seconds')

        _utils.check_parameter_valid('range',
                                     hysteresis, [100.0e-6, 1.0],
                                     desc='hysteresis',
                                     units='volts')
        _utils.check_parameter_valid('set', hf_reject, [True, False],
                                     'hf reject')
        _utils.check_parameter_valid('set', mode, ['auto', 'normal'],
                                     'trigger mode')
        _utils.check_parameter_valid('set', trig_on_scan_rising, [True, False],
                                     'trigger only on scan rising edge')

        if source == 'scan':
            self.trig_aux = 1
        else:
            self.trig_aux = 0

        if trig_on_scan_rising:
            self.cond_trig = 1
        else:
            self.cond_trig = 0

        # Define the trigger sources appropriate to the LaserLockBox instrument
        source = _utils.str_to_val(_LLB_OSC_SOURCES, source, 'trigger source')
        # This function is the portion of set_trigger shared
        # among instruments with embedded scopes.
        self._set_trigger(source, edge, level, minwidth, maxwidth, hysteresis,
                          hf_reject, mode)
Exemplo n.º 9
0
    def set_waveform_trigger(self,
                             ch,
                             source,
                             edge,
                             level,
                             minwidth=None,
                             maxwidth=None,
                             hysteresis=False):
        """ Specify what constitutes a trigger event for the given output
        channel.
        This takes effect only when the channel has triggered output mode
        enabled (see :any:`set_waveform_trigger_output
        <pymoku.instruments.ArbitraryWaveGen.set_waveform_trigger_output>`).

        :type ch: int; {1,2}
        :param ch: Output channel to set triggering on

        :type source: string, {'in1','in2','ext'}
        :param source: Trigger source. May be either input channel, or the
        external 'Trig' back-panel connector allowing triggering from an
        externally-generated digital [LV]TTL or CMOS signal.

        :type edge: string, {'rising','falling','both'}
        :param edge: Which edge to trigger on. In 'Pulse Width' mode this
        specifies whether the pulse is positive (rising) or negative (falling),
        with the 'both' option being invalid.

        :type level: float, [-5.0, 5.0] volts
        :param level: Trigger level. Ignored in 'ext' mode.

        :type minwidth: float, seconds
        :param minwidth:
            Minimum Pulse Width. 0 <= minwidth < (2^32/samplerate).
            Can't be used with maxwidth.

        :type maxwidth: float, seconds
        :param maxwidth:
            Maximum Pulse Width. 0 <= maxwidth < (2^32/samplerate).
            Can't be used with minwidth.

        :type hysteresis: bool
        :param hysteresis: Enable hysteresis around trigger point.

        """
        valid('set', ch, [1, 2], 'channel')
        valid('set', source, ['in1', 'in2', 'ext'], 'trigger source')
        valid('set', edge, ['rising', 'falling', 'both'])
        valid('range', level, [_ARB_TRIG_LVL_MIN, _ARB_TRIG_LVL_MAX],
              'trigger level', 'Volts')

        if not (maxwidth is None or minwidth is None):
            raise InvalidConfigurationException(
                "Can't set both 'minwidth' and 'maxwidth' for Pulse Width "
                "trigger mode. Choose one.")
        if (maxwidth or minwidth) and (edge == 'both'):
            raise InvalidConfigurationException(
                "Can't set trigger edge type 'both' in Pulse Width trigger "
                "mode. Choose one of {'rising','falling'}.")

        # External trigger source is only available on Moku 20
        if (self._moku.get_hw_version() == 1.0) and source == 'ext':
            raise InvalidConfigurationException(
                "External trigger source is not available on your hardware.")
        if source == 'ext' and level:
            log.warning(
                "Trigger level ignored when triggering from source 'ext'.")

        # TODO: Add timer source
        _str_to_source = {
            'in1': _ARB_TRIG_SRC_CH1,
            'in2': _ARB_TRIG_SRC_CH2,
            'ext': _ARB_TRIG_SRC_EXT
        }
        _str_to_edge = {
            'rising': Trigger.EDGE_RISING,
            'falling': Trigger.EDGE_FALLING,
            'both': Trigger.EDGE_BOTH
        }
        source = str_to_val(_str_to_source, source, 'trigger source')
        edge = str_to_val(_str_to_edge, edge, 'edge type')

        if ch == 1:
            self.trig_source1 = source
            self.trig_level1 = level
        elif ch == 2:
            self.trig_source2 = source
            self.trig_level2 = level
        else:
            raise ValueOutOfRangeException("Incorrect channel number %d", ch)

        trig_channels = [self._trigger1, self._trigger2]

        # AKA: Normal trigger mode only (HG-2598)
        trig_channels[ch - 1].timer = 0.0
        trig_channels[ch - 1].auto_holdoff = 0

        trig_channels[ch - 1].edge = edge
        trig_channels[ch - 1].duration = minwidth or maxwidth or 0.0
        # TODO: Enable setting hysteresis level. For now we use the iPad LSB
        # values for ON/OFF.
        trig_channels[ch - 1].hysteresis = 25 if hysteresis else 0

        if maxwidth:
            trig_channels[ch - 1].trigtype = Trigger.TYPE_PULSE
            trig_channels[ch - 1].pulsetype = Trigger.PULSE_MAX
        elif minwidth:
            trig_channels[ch - 1].trigtype = Trigger.TYPE_PULSE
            trig_channels[ch - 1].pulsetype = Trigger.PULSE_MIN
        else:
            trig_channels[ch - 1].trigtype = Trigger.TYPE_EDGE
Exemplo n.º 10
0
    def write_lut(self, ch, data, mode=None):
        """Writes the signal lookup table to memory in the Moku:Lab.

        You can also choose the output rate of the AWG, which influences the
        maximum length of the look-up table as follows:

        - 1000MSPS: 8192 points per channel
        - 500MSPS: 16384 points per channel
        - 250MSPS: 32768 points per channel
        - 125MSPS: 65536 points per channel

        If you don't specify a mode, the fastest output rate for the given data
        length will be automatically chosen. This is correct in almost all
        circumstances.

        If you specify a particular mode along with a data array too big for
        that mode, the behaviour is undefined.

        To avoid unexpected output signals during write, disable the outputs
        by using the :any:`enable_output` function.

        :type ch: int; {1,2}
        :param ch: Output channel to load the LUT to

        :type data: float array;
        :param data: Lookup table coefficients normalised to range [-1.0, 1.0].

        :type mode: int; {125, 250, 500, 1000} MSmps
        :param mode: defines the output sample rate of the AWG.

        :raises ValueError: if the channel is invalid
        :raises ValueOutOfRangeException: if wave parameters are out of range
        """
        valid('set', ch, [1, 2], 'output channel')
        valid('set',
              mode, [125, 250, 500, 1000],
              desc='output sample rate',
              units="MSmps",
              allow_none=True)

        # Check that all coefficients are between -1.0 and 1.0
        if not all(map(lambda x: abs(x) <= 1.0, data)):
            raise ValueOutOfRangeException(
                "Lookup table coefficients must be in the range [-1.0, 1.0].")

        n_points = len(data)

        if n_points <= 2**13:
            max_lut_samplerate = 1000
        elif n_points <= 2**14:
            max_lut_samplerate = 500
        elif n_points <= 2**15:
            max_lut_samplerate = 250
        elif n_points <= 2**16:
            max_lut_samplerate = 125
        else:
            raise ValueOutOfRangeException(
                "Maximum data length is 65535 samples")

        if not mode:
            mode = max_lut_samplerate

        if mode > max_lut_samplerate:
            raise InvalidConfigurationException(
                "Maximum samplerate for {} lookup table coefficients "
                "is {}Msmps.".format(n_points, max_lut_samplerate))

        _str_to_mode = {
            '1000': _ARB_MODE_1000,
            '500': _ARB_MODE_500,
            '250': _ARB_MODE_250,
            '125': _ARB_MODE_125
        }

        mode = str_to_val(_str_to_mode, str(mode), "operating mode")

        self._set_mode(ch, mode, len(data))
        self.commit()

        # picks the stepsize and the steps based in the mode
        steps, stepsize = [(8, 8192), (4, 8192 * 2), (2, 8192 * 4),
                           (1, 8192 * 8)][mode]

        byte_data = bytearray()
        for step in range(steps):
            byte_data += bytearray(b''.join([
                struct.pack('<hh', int(math.ceil((2.0**15 - 1) * d)), 0)
                for d in data
            ]))
            byte_data += bytearray(b'\0' * (stepsize * 4 - (len(data) * 4)))

        # Write the data to AWG memory map
        self._set_mmap_access(True)
        self._moku._send_file_bytes('j',
                                    '',
                                    byte_data,
                                    offset=_ARB_LUT_LENGTH * 8 * 4 * (ch - 1))
        self._set_mmap_access(False)

        # Release the memory map "file" to other resources
        self._moku._fs_finalise('j', '', _ARB_LUT_LENGTH * 8 * 4 * 2)