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))
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)
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
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
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)
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
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)
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
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)