Exemple #1
0
class SR830(VisaInstrument):
    """
    This is the qcodes driver for the Stanford Research Systems SR830
    Lock-in Amplifier
    """

    _VOLT_TO_N = {
        2e-9: 0,
        5e-9: 1,
        10e-9: 2,
        20e-9: 3,
        50e-9: 4,
        100e-9: 5,
        200e-9: 6,
        500e-9: 7,
        1e-6: 8,
        2e-6: 9,
        5e-6: 10,
        10e-6: 11,
        20e-6: 12,
        50e-6: 13,
        100e-6: 14,
        200e-6: 15,
        500e-6: 16,
        1e-3: 17,
        2e-3: 18,
        5e-3: 19,
        10e-3: 20,
        20e-3: 21,
        50e-3: 22,
        100e-3: 23,
        200e-3: 24,
        500e-3: 25,
        1: 26
    }
    _N_TO_VOLT = {v: k for k, v in _VOLT_TO_N.items()}

    _CURR_TO_N = {
        2e-15: 0,
        5e-15: 1,
        10e-15: 2,
        20e-15: 3,
        50e-15: 4,
        100e-15: 5,
        200e-15: 6,
        500e-15: 7,
        1e-12: 8,
        2e-12: 9,
        5e-12: 10,
        10e-12: 11,
        20e-12: 12,
        50e-12: 13,
        100e-12: 14,
        200e-12: 15,
        500e-12: 16,
        1e-9: 17,
        2e-9: 18,
        5e-9: 19,
        10e-9: 20,
        20e-9: 21,
        50e-9: 22,
        100e-9: 23,
        200e-9: 24,
        500e-9: 25,
        1e-6: 26
    }
    _N_TO_CURR = {v: k for k, v in _CURR_TO_N.items()}

    _VOLT_ENUM = Enum(*_VOLT_TO_N.keys())
    _CURR_ENUM = Enum(*_CURR_TO_N.keys())

    _INPUT_CONFIG_TO_N = {
        'a': 0,
        'a-b': 1,
        'I 1M': 2,
        'I 100M': 3,
    }

    _N_TO_INPUT_CONFIG = {v: k for k, v in _INPUT_CONFIG_TO_N.items()}

    def __init__(self, name, address, **kwargs):
        super().__init__(name, address, **kwargs)

        # Reference and phase
        self.add_parameter('phase',
                           label='Phase',
                           get_cmd='PHAS?',
                           get_parser=float,
                           set_cmd='PHAS {:.2f}',
                           unit='deg',
                           vals=Numbers(min_value=-360, max_value=729.99))

        self.add_parameter('reference_source',
                           label='Reference source',
                           get_cmd='FMOD?',
                           set_cmd='FMOD {}',
                           val_mapping={
                               'external': 0,
                               'internal': 1,
                           },
                           vals=Enum('external', 'internal'))

        self.add_parameter('frequency',
                           label='Frequency',
                           get_cmd='FREQ?',
                           get_parser=float,
                           set_cmd='FREQ {:.4f}',
                           unit='Hz',
                           vals=Numbers(min_value=1e-3, max_value=102e3))

        self.add_parameter('ext_trigger',
                           label='External trigger',
                           get_cmd='RSLP?',
                           set_cmd='RSLP {}',
                           val_mapping={
                               'sine': 0,
                               'TTL rising': 1,
                               'TTL falling': 2,
                           })

        self.add_parameter('harmonic',
                           label='Harmonic',
                           get_cmd='HARM?',
                           get_parser=int,
                           set_cmd='HARM {:d}',
                           vals=Ints(min_value=1, max_value=19999))

        self.add_parameter('amplitude',
                           label='Amplitude',
                           get_cmd='SLVL?',
                           get_parser=float,
                           set_cmd='SLVL {:.3f}',
                           unit='V',
                           vals=Numbers(min_value=0.004, max_value=5.000))

        # Input and filter
        self.add_parameter('input_config',
                           label='Input configuration',
                           get_cmd='ISRC?',
                           get_parser=self._get_input_config,
                           set_cmd='ISRC {}',
                           set_parser=self._set_input_config,
                           vals=Enum(*self._INPUT_CONFIG_TO_N.keys()))

        self.add_parameter('input_shield',
                           label='Input shield',
                           get_cmd='IGND?',
                           set_cmd='IGND {}',
                           val_mapping={
                               'float': 0,
                               'ground': 1,
                           })

        self.add_parameter('input_coupling',
                           label='Input coupling',
                           get_cmd='ICPL?',
                           set_cmd='ICPL {}',
                           val_mapping={
                               'AC': 0,
                               'DC': 1,
                           })

        self.add_parameter('notch_filter',
                           label='Notch filter',
                           get_cmd='ILIN?',
                           set_cmd='ILIN {}',
                           val_mapping={
                               'off': 0,
                               'line in': 1,
                               '2x line in': 2,
                               'both': 3,
                           })

        # Gain and time constant
        self.add_parameter(name='sensitivity',
                           label='Sensitivity',
                           get_cmd='SENS?',
                           set_cmd='SENS {:d}',
                           get_parser=self._get_sensitivity,
                           set_parser=self._set_sensitivity)

        self.add_parameter('reserve',
                           label='Reserve',
                           get_cmd='RMOD?',
                           set_cmd='RMOD {}',
                           val_mapping={
                               'high': 0,
                               'normal': 1,
                               'low noise': 2,
                           })

        self.add_parameter('time_constant',
                           label='Time constant',
                           get_cmd='OFLT?',
                           set_cmd='OFLT {}',
                           unit='s',
                           val_mapping={
                               10e-6: 0,
                               30e-6: 1,
                               100e-6: 2,
                               300e-6: 3,
                               1e-3: 4,
                               3e-3: 5,
                               10e-3: 6,
                               30e-3: 7,
                               100e-3: 8,
                               300e-3: 9,
                               1: 10,
                               3: 11,
                               10: 12,
                               30: 13,
                               100: 14,
                               300: 15,
                               1e3: 16,
                               3e3: 17,
                               10e3: 18,
                               30e3: 19,
                           })

        self.add_parameter('filter_slope',
                           label='Filter slope',
                           get_cmd='OFSL?',
                           set_cmd='OFSL {}',
                           unit='dB/oct',
                           val_mapping={
                               6: 0,
                               12: 1,
                               18: 2,
                               24: 3,
                           })

        self.add_parameter('sync_filter',
                           label='Sync filter',
                           get_cmd='SYNC?',
                           set_cmd='SYNC {}',
                           val_mapping={
                               'off': 0,
                               'on': 1,
                           })

        def parse_offset_get(s):
            parts = s.split(',')

            return float(parts[0]), int(parts[1])

        # TODO: Parameters that can be set with multiple arguments
        # For the OEXP command for example two arguments are needed
        self.add_parameter('X_offset',
                           get_cmd='OEXP? 1',
                           get_parser=parse_offset_get)

        self.add_parameter('Y_offset',
                           get_cmd='OEXP? 2',
                           get_parser=parse_offset_get)

        self.add_parameter('R_offset',
                           get_cmd='OEXP? 3',
                           get_parser=parse_offset_get)

        # Aux input/output
        for i in [1, 2, 3, 4]:
            self.add_parameter('aux_in{}'.format(i),
                               label='Aux input {}'.format(i),
                               get_cmd='OAUX? {}'.format(i),
                               get_parser=float,
                               unit='V')

            self.add_parameter('aux_out{}'.format(i),
                               label='Aux output {}'.format(i),
                               get_cmd='AUXV? {}'.format(i),
                               get_parser=float,
                               set_cmd='AUXV {0}, {{}}'.format(i),
                               unit='V')

        # Setup
        self.add_parameter('output_interface',
                           label='Output interface',
                           get_cmd='OUTX?',
                           set_cmd='OUTX {}',
                           val_mapping={
                               'RS232': '0\n',
                               'GPIB': '1\n',
                           })

        # Channel setup
        for ch in range(1, 3):

            # detailed validation and mapping performed in set/get functions
            self.add_parameter('ch{}_ratio'.format(ch),
                               label='Channel {} ratio'.format(ch),
                               get_cmd=partial(self._get_ch_ratio, ch),
                               set_cmd=partial(self._set_ch_ratio, ch),
                               vals=Strings())
            self.add_parameter('ch{}_display'.format(ch),
                               label='Channel {} display'.format(ch),
                               get_cmd=partial(self._get_ch_display, ch),
                               set_cmd=partial(self._set_ch_display, ch),
                               vals=Strings())
            self.add_parameter('ch{}_databuffer'.format(ch),
                               channel=ch,
                               parameter_class=ChannelBuffer)

        # Data transfer
        self.add_parameter('X', get_cmd='OUTP? 1', get_parser=float, unit='V')

        self.add_parameter('Y', get_cmd='OUTP? 2', get_parser=float, unit='V')

        self.add_parameter('R', get_cmd='OUTP? 3', get_parser=float, unit='V')

        self.add_parameter('P',
                           get_cmd='OUTP? 4',
                           get_parser=float,
                           unit='deg')

        # Data buffer settings
        self.add_parameter('buffer_SR',
                           label='Buffer sample rate',
                           get_cmd='SRAT ?',
                           set_cmd=self._set_buffer_SR,
                           unit='Hz',
                           val_mapping={
                               62.5e-3: 0,
                               0.125: 1,
                               0.250: 2,
                               0.5: 3,
                               1: 4,
                               2: 5,
                               4: 6,
                               8: 7,
                               16: 8,
                               32: 9,
                               64: 10,
                               128: 11,
                               256: 12,
                               512: 13,
                               'Trigger': 14
                           },
                           get_parser=int)

        self.add_parameter('buffer_acq_mode',
                           label='Buffer acquistion mode',
                           get_cmd='SEND ?',
                           set_cmd='SEND {}',
                           val_mapping={
                               'single shot': 0,
                               'loop': 1
                           },
                           get_parser=int)

        self.add_parameter('buffer_trig_mode',
                           label='Buffer trigger start mode',
                           get_cmd='TSTR ?',
                           set_cmd='TSTR {}',
                           val_mapping={
                               'ON': 1,
                               'OFF': 0
                           },
                           get_parser=int)

        self.add_parameter('buffer_npts',
                           label='Buffer number of stored points',
                           get_cmd='SPTS ?',
                           get_parser=int)

        # Auto functions
        self.add_function('auto_gain', call_cmd='AGAN')
        self.add_function('auto_reserve', call_cmd='ARSV')
        self.add_function('auto_phase', call_cmd='APHS')
        self.add_function('auto_offset',
                          call_cmd='AOFF {0}',
                          args=[Enum(1, 2, 3)])

        # Interface
        self.add_function('reset', call_cmd='*RST')

        self.add_function('disable_front_panel', call_cmd='OVRM 0')
        self.add_function('enable_front_panel', call_cmd='OVRM 1')

        self.add_function('send_trigger',
                          call_cmd='TRIG',
                          docstring=("Send a software trigger. "
                                     "This command has the same effect as a "
                                     "trigger at the rear panel trigger"
                                     " input."))

        self.add_function('buffer_start',
                          call_cmd='STRT',
                          docstring=("The buffer_start command starts or "
                                     "resumes data storage. buffer_start"
                                     " is ignored if storage is already in"
                                     " progress."))

        self.add_function('buffer_pause',
                          call_cmd='PAUS',
                          docstring=("The buffer_pause command pauses data "
                                     "storage. If storage is already paused "
                                     "or reset then this command is ignored."))

        self.add_function('buffer_reset',
                          call_cmd='REST',
                          docstring=("The buffer_reset command resets the data"
                                     " buffers. The buffer_reset command can "
                                     "be sent at any time - any storage in "
                                     "progress, paused or not, will be reset."
                                     " This command will erase the data "
                                     "buffer."))

        # Initialize the proper units of the outputs and sensitivities
        self.input_config()

        # start keeping track of buffer setpoints
        self._buffer1_ready = False
        self._buffer2_ready = False

        self.connect_message()

    SNAP_PARAMETERS = {
        'x': '1',
        'y': '2',
        'r': '3',
        'p': '4',
        'phase': '4',
        'θ': '4',
        'aux1': '5',
        'aux2': '6',
        'aux3': '7',
        'aux4': '8',
        'freq': '9',
        'ch1': '10',
        'ch2': '11'
    }

    def snap(self, *parameters: str) -> Tuple[float, ...]:
        """
        Get between 2 and 6 parameters at a single instant. This provides a 
        coherent snapshot of measured signals. Pick up to 6 from: X, Y, R, θ, 
        the aux inputs 1-4, frequency, or what is currently displayed on 
        channels 1 and 2.

        Reading X and Y (or R and θ) gives a coherent snapshot of the signal.
        Snap is important when the time constant is very short, a time constant
        less than 100 ms.

        Args:
            *parameters
                From 2 to 6 strings of names of parameters for which the values
                are requested. including: 'x', 'y', 'r', 'p', 'phase' or 'θ',
                'aux1', 'aux2', 'aux3', 'aux4', 'freq', 'ch1', and 'ch2'.
            
        Returns:
            A tuple of floating point values in the same order as requested.

        Examples:
            lockin.snap('x','y') -> tuple(x,y)
            
            lockin.snap('aux1','aux2','freq','phase') 
                -> tuple(aux1,aux2,freq,phase)

        Note:
            Volts for x, y, r, and aux 1-4
            Degrees for θ
            Hertz for freq
            Unknown for ch1 and ch2. It will depend on what was set.

             - If X,Y,R and θ are all read, then the values of X,Y are recorded
               approximately 10 µs apart from R,θ. Thus, the values of X and Y 
               may not yield the exact values of R and θ from a single snap.
             - The values of the Aux Inputs may have an uncertainty of 
               up to 32 µs.
             - The frequency is computed only every other period or 40 ms, 
               whichever is longer.  
        """
        if not 2 <= len(parameters) <= 6:
            raise KeyError(
                'It is only possible to request values of 2 to 6 parameters'
                ' at a time.')

        for name in parameters:
            if name.lower() not in self.SNAP_PARAMETERS:
                raise KeyError(f'{name} is an unknown parameter. Refer'
                               f' to `SNAP_PARAMETERS` for a list of valid'
                               f' parameter names')

        p_ids = [self.SNAP_PARAMETERS[name.lower()] for name in parameters]
        output = self.ask(f'SNAP? {",".join(p_ids)}')

        return tuple(float(val) for val in output.split(','))

    def increment_sensitivity(self):
        """
        Increment the sensitivity setting of the lock-in. This is equivalent
        to pushing the sensitivity up button on the front panel. This has no
        effect if the sensitivity is already at the maximum.

        Returns:
            Whether or not the sensitivity was actually changed.
        """
        return self._change_sensitivity(1)

    def decrement_sensitivity(self):
        """
        Decrement the sensitivity setting of the lock-in. This is equivalent
        to pushing the sensitivity down button on the front panel. This has no
        effect if the sensitivity is already at the minimum.

        Returns:
            Whether or not the sensitivity was actually changed.
        """
        return self._change_sensitivity(-1)

    def _change_sensitivity(self, dn):
        _ = self.sensitivity.get()
        n = int(self.sensitivity.raw_value)
        if self.input_config() in ['a', 'a-b']:
            n_to = self._N_TO_VOLT
        else:
            n_to = self._N_TO_CURR

        if n + dn > max(n_to.keys()) or n + dn < min(n_to.keys()):
            return False

        self.sensitivity.set(n_to[n + dn])
        return True

    def _set_buffer_SR(self, SR):
        self.write('SRAT {}'.format(SR))
        self._buffer1_ready = False
        self._buffer2_ready = False

    def _get_ch_ratio(self, channel):
        val_mapping = {
            1: {
                0: 'none',
                1: 'Aux In 1',
                2: 'Aux In 2'
            },
            2: {
                0: 'none',
                1: 'Aux In 3',
                2: 'Aux In 4'
            }
        }
        resp = int(self.ask('DDEF ? {}'.format(channel)).split(',')[1])

        return val_mapping[channel][resp]

    def _set_ch_ratio(self, channel, ratio):
        val_mapping = {
            1: {
                'none': 0,
                'Aux In 1': 1,
                'Aux In 2': 2
            },
            2: {
                'none': 0,
                'Aux In 3': 1,
                'Aux In 4': 2
            }
        }
        vals = val_mapping[channel].keys()
        if ratio not in vals:
            raise ValueError('{} not in {}'.format(ratio, vals))
        ratio = val_mapping[channel][ratio]
        disp_val = int(self.ask('DDEF ? {}'.format(channel)).split(',')[0])
        self.write('DDEF {}, {}, {}'.format(channel, disp_val, ratio))
        self._buffer_ready = False

    def _get_ch_display(self, channel):
        val_mapping = {
            1: {
                0: 'X',
                1: 'R',
                2: 'X Noise',
                3: 'Aux In 1',
                4: 'Aux In 2'
            },
            2: {
                0: 'Y',
                1: 'Phase',
                2: 'Y Noise',
                3: 'Aux In 3',
                4: 'Aux In 4'
            }
        }
        resp = int(self.ask('DDEF ? {}'.format(channel)).split(',')[0])

        return val_mapping[channel][resp]

    def _set_ch_display(self, channel, disp):
        val_mapping = {
            1: {
                'X': 0,
                'R': 1,
                'X Noise': 2,
                'Aux In 1': 3,
                'Aux In 2': 4
            },
            2: {
                'Y': 0,
                'Phase': 1,
                'Y Noise': 2,
                'Aux In 3': 3,
                'Aux In 4': 4
            }
        }
        vals = val_mapping[channel].keys()
        if disp not in vals:
            raise ValueError('{} not in {}'.format(disp, vals))
        disp = val_mapping[channel][disp]
        # Since ratio AND display are set simultaneously,
        # we get and then re-set the current ratio value
        ratio_val = int(self.ask('DDEF ? {}'.format(channel)).split(',')[1])
        self.write('DDEF {}, {}, {}'.format(channel, disp, ratio_val))
        self._buffer_ready = False

    def _set_units(self, unit):
        # TODO:
        # make a public parameter function that allows to change the units
        for param in [self.X, self.Y, self.R, self.sensitivity]:
            param.unit = unit

    def _get_input_config(self, s):
        mode = self._N_TO_INPUT_CONFIG[int(s)]

        if mode in ['a', 'a-b']:
            self.sensitivity.vals = self._VOLT_ENUM
            self._set_units('V')
        else:
            self.sensitivity.vals = self._CURR_ENUM
            self._set_units('A')

        return mode

    def _set_input_config(self, s):
        if s in ['a', 'a-b']:
            self.sensitivity.vals = self._VOLT_ENUM
            self._set_units('V')
        else:
            self.sensitivity.vals = self._CURR_ENUM
            self._set_units('A')

        return self._INPUT_CONFIG_TO_N[s]

    def _get_sensitivity(self, s):
        if self.input_config() in ['a', 'a-b']:
            return self._N_TO_VOLT[int(s)]
        else:
            return self._N_TO_CURR[int(s)]

    def _set_sensitivity(self, s):
        if self.input_config() in ['a', 'a-b']:
            return self._VOLT_TO_N[s]
        else:
            return self._CURR_TO_N[s]
    def __init__(
            self,
            parent: VisaInstrument,
            name: str,
            proper_function: str
    ) -> None:

        super().__init__(parent, name)

        self._proper_function = proper_function
        range_vals = self.function_modes[self._proper_function]["range_vals"]
        unit = self.function_modes[self._proper_function]["unit"]

        self.function = self.parent.digi_sense_function

        self.add_parameter(
            self._proper_function,
            get_cmd=self._measure,
            unit=unit,
            docstring="Make measurements, place them in a reading buffer, and "
                      "return the last reading."
        )

        self.add_parameter(
            "range",
            get_cmd=f":SENSe:DIGitize:{self._proper_function}:RANGe?",
            set_cmd=f":SENSe:DIGitize:{self._proper_function}:RANGe {{}}",
            vals=range_vals,
            get_parser=float,
            unit=unit,
            docstring="Determine the positive full-scale measure range."
        )

        self.add_parameter(
            "input_impedance",
            get_cmd=":SENSe:DIGitize:VOLTage:INPutimpedance?",
            set_cmd=":SENSe:DIGitize:VOLTage:INPutimpedance {}",
            vals=Enum("AUTO", "MOHM10"),
            docstring="Determine when the 10 MΩ input divider is enabled. "
                      "'MOHM10' means 10 MΩ for all ranges."
        )

        self.add_parameter(
            'acq_rate',
            get_cmd=f":SENSe:DIGitize:{self._proper_function}:SRATE?",
            set_cmd=f":SENSe:DIGitize:{self._proper_function}:SRATE {{}}",
            vals=Ints(1000, 1000000),
            docstring="Define the precise acquisition rate at which the "
                      "digitizing measurements are made."
        )

        self.add_parameter(
            "aperture",
            get_cmd=f":SENSe:DIGitize:{self._proper_function}:APERture?",
            set_cmd=f":SENSe:DIGitize:{self._proper_function}:APERture {{}}",
            unit="us",
            docstring="Determine the aperture setting."
        )

        self.add_parameter(
            "count",
            get_cmd="SENSe:DIGitize:COUNt?",
            set_cmd="SENSe:DIGitize:COUNt {}",
            vals=Ints(1, 55000000),
            docstring="Set the number of measurements to digitize when a "
                      "measurement is requested"
        )
    def __init__(
            self,
            parent: 'Keithley7510',
            name: str,
            size: Optional[int] = None,
            style: str = ''
    ) -> None:
        super().__init__(parent, name)
        self._size = size
        self.style = style

        if self.short_name not in self.default_buffer:
            # when making a new buffer, the "size" parameter is required.
            if size is None:
                raise TypeError(
                    "buffer() missing 1 required positional argument: 'size'"
                )
            self.write(
                f":TRACe:MAKE '{self.short_name}', {self._size}, {self.style}"
            )
        else:
            # when referring to default buffer, "size" parameter is not needed.
            if size is not None:
                self.log.warning(
                    f"Please use method 'size()' to resize default buffer "
                    f"{self.short_name} size to {self._size}."
                )

        self.add_parameter(
            "size",
            get_cmd=f":TRACe:POINts? '{self.short_name}'",
            set_cmd=f":TRACe:POINts {{}}, '{self.short_name}'",
            get_parser=int,
            docstring="The number of readings a buffer can store."
        )

        self.add_parameter(
            "number_of_readings",
            get_cmd=f":TRACe:ACTual? '{self.short_name}'",
            get_parser=int,
            docstring="Get the number of readings in the reading buffer."
        )

        self.add_parameter(
            "last_index",
            get_cmd=f":TRACe:ACTual:END? '{self.short_name}'",
            get_parser=int,
            docstring="Get the last index of readings in the reading buffer."
        )

        self.add_parameter(
            "first_index",
            get_cmd=f":TRACe:ACTual:STARt? '{self.short_name}'",
            get_parser=int,
            docstring="Get the starting index of readings in the reading "
                      "buffer."
        )

        self.add_parameter(
            "data_start",
            initial_value=1,
            get_cmd=None,
            set_cmd=None,
            docstring="First index of the data to be returned."
        )

        self.add_parameter(
            "data_end",
            initial_value=1,
            get_cmd=None,
            set_cmd=None,
            docstring="Last index of the data to be returned."
        )

        self.add_parameter(
            "elements",
            get_cmd=None,
            get_parser=self._from_scpi_to_name,
            set_cmd=None,
            set_parser=self._from_name_to_scpi,
            vals=Lists(Enum(*list(self.buffer_elements.keys()))),
            docstring="List of buffer elements to read."
        )

        self.add_parameter(
            "setpoints_start",
            label="start value for the setpoints",
            source=None,
            parameter_class=DelegateParameter
        )

        self.add_parameter(
            "setpoints_stop",
            label="stop value for the setpoints",
            source=None,
            parameter_class=DelegateParameter
        )

        self.add_parameter(
            "n_pts",
            label="total n for the setpoints",
            get_cmd=self._get_n_pts
        )

        self.add_parameter(
            "setpoints",
            parameter_class=GeneratedSetPoints,
            start=self.setpoints_start,
            stop=self.setpoints_stop,
            n_points=self.n_pts,
            vals=Arrays(shape=(self.n_pts.get_latest,))
        )

        self.add_parameter(
            "t_start",
            label="start time",
            unit="s",
            initial_value=0,
            get_cmd=None,
            set_cmd=None,
            set_parser=float
        )

        self.add_parameter(
            "t_stop",
            label="stop time",
            unit="s",
            initial_value=1,
            get_cmd=None,
            set_cmd=None,
            set_parser=float
        )

        self.add_parameter(
            "fill_mode",
            get_cmd=f":TRACe:FILL:MODE? '{self.short_name}'",
            set_cmd=f":TRACe:FILL:MODE {{}}, '{self.short_name}'",
            vals=Enum('CONT', 'continuous', 'ONCE', 'once'),
            docstring="if a reading buffer is filled continuously or is filled"
                      " once and stops"
        )
Exemple #4
0
    def __init__(self, name: str, address: str, **kwargs: Any):
        super().__init__(name, address, terminator='\n', **kwargs)

        self._card = 0

        self.add_parameter(name='get_status',
                           get_cmd='*ESR?',
                           get_parser=int,
                           docstring='Queries status register.')

        self.add_parameter(name='get_error',
                           get_cmd=':SYST:ERR?',
                           docstring='Queries error queue')

        self.add_parameter(name='connections',
                           get_cmd=f':CLOS:CARD? {self._card}',
                           get_parser=KeysightB220X.parse_channel_list,
                           docstring='queries currently active connections '
                           'and returns a set of tuples {(input, '
                           'output), ...}')

        self.add_parameter(
            name='connection_rule',
            get_cmd=self._get_connection_rule,
            set_cmd=self._set_connection_rule,
            val_mapping={
                'free': 'FREE',
                'single': 'SROU'
            },
            docstring=("specifies connection rule. Parameter "
                       "one of 'free' (default) or 'single'.\n\n"
                       "In 'free' mode\n"
                       " - each input port can be connected to "
                       "multiple output ports\n"
                       " - and each output port can be "
                       "connected to multiple input ports.\n"
                       " - Caution: If the Free connection rule "
                       "has been specified, ensure multiple "
                       "input ports are not connected to the "
                       "same output port. Such configurations "
                       "can cause damage\n\n"
                       "In single route mode:\n"
                       " - each input port can be connected to "
                       "only one output port\n"
                       " - and each output port can be "
                       "connected to only one input port.\n"
                       " - existing connection to a port will "
                       "be disconnected when a new connection "
                       "is made.\n"))

        self.add_parameter(name='connection_sequence',
                           get_cmd=f':CONN:SEQ? {self._card}',
                           set_cmd=f':CONN:SEQ {self._card},{{}}',
                           val_mapping={
                               'none': 'NSEQ',
                               'bbm': 'BBM',
                               'mbb': 'MBBR'
                           },
                           docstring="One of 'none', 'bbm' (Break before "
                           "make) or 'mbb' (make before break)")

        self.add_parameter(name='bias_input_port',
                           get_cmd=f':BIAS:PORT? {self._card}',
                           set_cmd=f':BIAS:PORT {self._card},{{}}',
                           vals=MultiType(KeysightB220X._available_input_ports,
                                          Enum(-1)),
                           get_parser=int,
                           docstring="Selects the input that will be used as "
                           "bias input port (default 10). The Bias "
                           "input port cannot be used on subsequent "
                           "`connect` or `disconnect` commands if "
                           "Bias mode is ON")

        self.add_parameter(name='bias_mode',
                           get_cmd=f':BIAS? {self._card}',
                           set_cmd=f':BIAS {self._card},{{}}',
                           val_mapping={
                               True: 1,
                               False: 0
                           },
                           docstring="Param: True for ON, False for OFF")

        self.add_parameter(name='gnd_input_port',
                           get_cmd=f':AGND:PORT? {self._card}',
                           set_cmd=f':AGND:PORT {self._card},{{}}',
                           vals=MultiType(KeysightB220X._available_input_ports,
                                          Enum(-1)),
                           get_parser=int,
                           docstring="Selects the input that will be used as "
                           "GND input port (default 12). The GND "
                           "input port cannot be used on subsequent "
                           "`connect` or `disconnect` commands if "
                           "GND mode is ON")

        self.add_parameter(name='gnd_mode',
                           get_cmd=f':AGND? {self._card}',
                           set_cmd=f':AGND {self._card},{{}}',
                           val_mapping={
                               True: 1,
                               False: 0
                           })

        self.add_parameter(name='unused_inputs',
                           get_cmd=f':AGND:UNUSED? {self._card}',
                           set_cmd=f":AGND:UNUSED {self._card},'{{}}'",
                           get_parser=lambda response: [
                               int(x) for x in response.strip("'").split(',')
                               if x.strip().isdigit()
                           ],
                           set_parser=lambda value: str(value).strip('[]'),
                           vals=Lists(KeysightB220X._available_input_ports))

        self.add_parameter(name='couple_ports',
                           get_cmd=f':COUP:PORT? {self._card}',
                           set_cmd=f":COUP:PORT {self._card},'{{}}'",
                           set_parser=lambda value: str(value).strip('[]()'),
                           get_parser=lambda response: [
                               int(x) for x in response.strip("'").split(',')
                               if x.strip().isdigit()
                           ],
                           vals=Lists(Enum(1, 3, 5, 7, 9, 11, 13)))

        self.add_parameter(name='couple_mode',
                           get_cmd=f':COUP? {self._card}',
                           set_cmd=f':COUP {self._card},{{}}',
                           val_mapping={
                               True: 1,
                               False: 0
                           },
                           docstring="Param: True for ON, False for OFF")

        self.connect_message()
Exemple #5
0
    def __init__(self, name, address, **kwargs):
        super().__init__(name, address, **kwargs)

        # Reference and phase
        self.add_parameter('phase',
                           label='Phase',
                           get_cmd='PHAS?',
                           get_parser=float,
                           set_cmd='PHAS {:.2f}',
                           unit='deg',
                           vals=Numbers(min_value=-360, max_value=729.99))

        self.add_parameter('reference_source',
                           label='Reference source',
                           get_cmd='FMOD?',
                           set_cmd='FMOD {}',
                           val_mapping={
                               'external': 0,
                               'internal': 1,
                           },
                           vals=Enum('external', 'internal'))

        self.add_parameter('frequency',
                           label='Frequency',
                           get_cmd='FREQ?',
                           get_parser=float,
                           set_cmd='FREQ {:.4f}',
                           unit='Hz',
                           vals=Numbers(min_value=1e-3, max_value=102e3))

        self.add_parameter('ext_trigger',
                           label='External trigger',
                           get_cmd='RSLP?',
                           set_cmd='RSLP {}',
                           val_mapping={
                               'sine': 0,
                               'TTL rising': 1,
                               'TTL falling': 2,
                           })

        self.add_parameter('harmonic',
                           label='Harmonic',
                           get_cmd='HARM?',
                           get_parser=int,
                           set_cmd='HARM {:d}',
                           vals=Ints(min_value=1, max_value=19999))

        self.add_parameter('amplitude',
                           label='Amplitude',
                           get_cmd='SLVL?',
                           get_parser=float,
                           set_cmd='SLVL {:.3f}',
                           unit='V',
                           vals=Numbers(min_value=0.004, max_value=5.000))

        # Input and filter
        self.add_parameter('input_config',
                           label='Input configuration',
                           get_cmd='ISRC?',
                           get_parser=self._get_input_config,
                           set_cmd='ISRC {}',
                           set_parser=self._set_input_config,
                           vals=Enum(*self._INPUT_CONFIG_TO_N.keys()))

        self.add_parameter('input_shield',
                           label='Input shield',
                           get_cmd='IGND?',
                           set_cmd='IGND {}',
                           val_mapping={
                               'float': 0,
                               'ground': 1,
                           })

        self.add_parameter('input_coupling',
                           label='Input coupling',
                           get_cmd='ICPL?',
                           set_cmd='ICPL {}',
                           val_mapping={
                               'AC': 0,
                               'DC': 1,
                           })

        self.add_parameter('notch_filter',
                           label='Notch filter',
                           get_cmd='ILIN?',
                           set_cmd='ILIN {}',
                           val_mapping={
                               'off': 0,
                               'line in': 1,
                               '2x line in': 2,
                               'both': 3,
                           })

        # Gain and time constant
        self.add_parameter(name='sensitivity',
                           label='Sensitivity',
                           get_cmd='SENS?',
                           set_cmd='SENS {:d}',
                           get_parser=self._get_sensitivity,
                           set_parser=self._set_sensitivity
                           )

        self.add_parameter('reserve',
                           label='Reserve',
                           get_cmd='RMOD?',
                           set_cmd='RMOD {}',
                           val_mapping={
                               'high': 0,
                               'normal': 1,
                               'low noise': 2,
                           })

        self.add_parameter('time_constant',
                           label='Time constant',
                           get_cmd='OFLT?',
                           set_cmd='OFLT {}',
                           unit='s',
                           val_mapping={
                               10e-6:  0, 30e-6:  1,
                               100e-6: 2, 300e-6: 3,
                               1e-3:   4, 3e-3:   5,
                               10e-3:  6, 30e-3:  7,
                               100e-3: 8, 300e-3: 9,
                               1:     10, 3:     11,
                               10:    12, 30:    13,
                               100:   14, 300:   15,
                               1e3:   16, 3e3:   17,
                               10e3:  18, 30e3:  19,
                           })

        self.add_parameter('filter_slope',
                           label='Filter slope',
                           get_cmd='OFSL?',
                           set_cmd='OFSL {}',
                           unit='dB/oct',
                           val_mapping={
                               6: 0,
                               12: 1,
                               18: 2,
                               24: 3,
                           })

        self.add_parameter('sync_filter',
                           label='Sync filter',
                           get_cmd='SYNC?',
                           set_cmd='SYNC {}',
                           val_mapping={
                               'off': 0,
                               'on': 1,
                           })

        def parse_offset_get(s):
            parts = s.split(',')

            return float(parts[0]), int(parts[1])

        # TODO: Parameters that can be set with multiple arguments
        # For the OEXP command for example two arguments are needed
        self.add_parameter('X_offset',
                           get_cmd='OEXP? 1',
                           get_parser=parse_offset_get)

        self.add_parameter('Y_offset',
                           get_cmd='OEXP? 2',
                           get_parser=parse_offset_get)

        self.add_parameter('R_offset',
                           get_cmd='OEXP? 3',
                           get_parser=parse_offset_get)

        # Aux input/output
        for i in [1, 2, 3, 4]:
            self.add_parameter('aux_in{}'.format(i),
                               label='Aux input {}'.format(i),
                               get_cmd='OAUX? {}'.format(i),
                               get_parser=float,
                               unit='V')

            self.add_parameter('aux_out{}'.format(i),
                               label='Aux output {}'.format(i),
                               get_cmd='AUXV? {}'.format(i),
                               get_parser=float,
                               set_cmd='AUXV {0}, {{}}'.format(i),
                               unit='V')

        # Setup
        self.add_parameter('output_interface',
                           label='Output interface',
                           get_cmd='OUTX?',
                           set_cmd='OUTX {}',
                           val_mapping={
                               'RS232': '0\n',
                               'GPIB': '1\n',
                           })

        # Channel setup
        for ch in range(1, 3):

            # detailed validation and mapping performed in set/get functions
            self.add_parameter('ch{}_ratio'.format(ch),
                               label='Channel {} ratio'.format(ch),
                               get_cmd=partial(self._get_ch_ratio, ch),
                               set_cmd=partial(self._set_ch_ratio, ch),
                               vals=Strings())
            self.add_parameter('ch{}_display'.format(ch),
                               label='Channel {} display'.format(ch),
                               get_cmd=partial(self._get_ch_display, ch),
                               set_cmd=partial(self._set_ch_display, ch),
                               vals=Strings())
            self.add_parameter('ch{}_databuffer'.format(ch),
                               channel=ch,
                               parameter_class=ChannelBuffer)

        # Data transfer
        self.add_parameter('X',
                           get_cmd='OUTP? 1',
                           get_parser=float,
                           unit='V')

        self.add_parameter('Y',
                           get_cmd='OUTP? 2',
                           get_parser=float,
                           unit='V')

        self.add_parameter('R',
                           get_cmd='OUTP? 3',
                           get_parser=float,
                           unit='V')

        self.add_parameter('P',
                           get_cmd='OUTP? 4',
                           get_parser=float,
                           unit='deg')

        # Data buffer settings
        self.add_parameter('buffer_SR',
                           label='Buffer sample rate',
                           get_cmd='SRAT ?',
                           set_cmd=self._set_buffer_SR,
                           unit='Hz',
                           val_mapping={62.5e-3: 0,
                                        0.125: 1,
                                        0.250: 2,
                                        0.5: 3,
                                        1: 4, 2: 5,
                                        4: 6, 8: 7,
                                        16: 8, 32: 9,
                                        64: 10, 128: 11,
                                        256: 12, 512: 13,
                                        'Trigger': 14},
                           get_parser=int
                           )

        self.add_parameter('buffer_acq_mode',
                           label='Buffer acquistion mode',
                           get_cmd='SEND ?',
                           set_cmd='SEND {}',
                           val_mapping={'single shot': 0,
                                        'loop': 1},
                           get_parser=int)

        self.add_parameter('buffer_trig_mode',
                           label='Buffer trigger start mode',
                           get_cmd='TSTR ?',
                           set_cmd='TSTR {}',
                           val_mapping={'ON': 1, 'OFF': 0},
                           get_parser=int)

        self.add_parameter('buffer_npts',
                           label='Buffer number of stored points',
                           get_cmd='SPTS ?',
                           get_parser=int)

        # Auto functions
        self.add_function('auto_gain', call_cmd='AGAN')
        self.add_function('auto_reserve', call_cmd='ARSV')
        self.add_function('auto_phase', call_cmd='APHS')
        self.add_function('auto_offset', call_cmd='AOFF {0}',
                          args=[Enum(1, 2, 3)])

        # Interface
        self.add_function('reset', call_cmd='*RST')

        self.add_function('disable_front_panel', call_cmd='OVRM 0')
        self.add_function('enable_front_panel', call_cmd='OVRM 1')

        self.add_function('send_trigger', call_cmd='TRIG',
                          docstring=("Send a software trigger. "
                                     "This command has the same effect as a "
                                     "trigger at the rear panel trigger"
                                     " input."))

        self.add_function('buffer_start', call_cmd='STRT',
                          docstring=("The buffer_start command starts or "
                                     "resumes data storage. buffer_start"
                                     " is ignored if storage is already in"
                                     " progress."))

        self.add_function('buffer_pause', call_cmd='PAUS',
                          docstring=("The buffer_pause command pauses data "
                                     "storage. If storage is already paused "
                                     "or reset then this command is ignored."))

        self.add_function('buffer_reset', call_cmd='REST',
                          docstring=("The buffer_reset command resets the data"
                                     " buffers. The buffer_reset command can "
                                     "be sent at any time - any storage in "
                                     "progress, paused or not, will be reset."
                                     " This command will erase the data "
                                     "buffer."))

        # Initialize the proper units of the outputs and sensitivities
        self.input_config()

        # start keeping track of buffer setpoints
        self._buffer1_ready = False
        self._buffer2_ready = False

        self.connect_message()
Exemple #6
0
    def __init__(self, name, chassis, slot, channels, triggers, **kwargs):
        """ Initialises a generic Signadyne digitizer and its parameters

            Args:
                name (str)      : the name of the digitizer card
                channels (int)  : the number of input channels the specified card has
                triggers (int)  : the number of trigger inputs the specified card has
        """
        super().__init__(name, chassis, slot, **kwargs)

        # Create instance of keysight SD_AIN class
        self.SD_AIN = keysightSD1.SD_AIN()

        # store card-specifics
        self.n_channels = channels
        self.n_triggers = triggers

        # Open the device, using the specified chassis and slot number
        dig_name = self.SD_AIN.getProductNameBySlot(chassis, slot)
        if isinstance(dig_name, str):
            result_code = self.SD_AIN.openWithSlot(dig_name, chassis, slot)
            if result_code <= 0:
                raise Exception('Could not open SD_DIG '
                                'error code {}'.format(result_code))
        else:
            raise Exception('No SD_DIG found at '
                            'chassis {}, slot {}'.format(chassis, slot))

        #
        # Create a set of internal variables to aid set/get cmds in params
        #

        # Create distinct parameters for each of the digitizer channels

        # For channelInputConfig
        self.__full_scale = [1
                             ] * self.n_channels  # By default, full scale = 1V
        self.__impedance = [0] * self.n_channels  # By default, Hi-z
        self.__coupling = [0] * self.n_channels  # By default, DC coupling
        # For channelPrescalerConfig
        self.__prescaler = [0] * self.n_channels  # By default, no prescaling
        # For channelTriggerConfig
        self.__trigger_mode = [keysightSD1.SD_AIN_TriggerMode.RISING_EDGE
                               ] * self.n_channels
        self.__trigger_threshold = [
            0
        ] * self.n_channels  # By default, threshold at 0V
        # For DAQ config
        self.__points_per_cycle = [0] * self.n_channels
        self.__n_cycles = [0] * self.n_channels
        self.__trigger_delay = [0] * self.n_channels
        self.__trigger_mode = [0] * self.n_channels
        # For DAQ trigger Config
        self.__digital_trigger_mode = [0] * self.n_channels
        self.__digital_trigger_source = [0] * self.n_channels
        self.__analog_trigger_mask = [0] * self.n_channels
        # For DAQ trigger External Config
        self.__external_source = [0] * self.n_channels
        self.__trigger_behaviour = [0] * self.n_channels
        # For DAQ read
        self.__n_points = [0] * self.n_channels
        self.__timeout = [-1] * self.n_channels

        #
        # Create internal parameters
        #

        # for triggerIOconfig
        self.add_parameter(
            'trigger_direction',
            label='Trigger direction for trigger port',
            vals=Enum(0, 1),
            set_cmd=self.SD_AIN.triggerIOconfig,
            docstring='The trigger direction for digitizer trigger port')

        # for clockSetFrequency
        self.add_parameter('sys_frequency',
                           label='CLKsys frequency',
                           vals=Ints(),
                           set_cmd=self.SD_AIN.clockSetFrequency,
                           get_cmd=self.SD_AIN.clockGetFrequency,
                           docstring='The frequency of internal CLKsys in Hz')

        # for clockGetSyncFrequency
        self.add_parameter('sync_frequency',
                           label='CLKsync frequency',
                           vals=Ints(),
                           get_cmd=self.SD_AIN.clockGetSyncFrequency,
                           docstring='The frequency of internal CLKsync in Hz')

        self.add_parameter(
            'trigger_io',
            label='trigger io',
            get_cmd=self.get_trigger_io,
            set_cmd=self.set_trigger_io,
            docstring='The trigger input value, 0 (OFF) or 1 (ON)',
            vals=Enum(0, 1))

        for n in range(self.n_channels):
            # For channelInputConfig
            self.add_parameter(
                f'full_scale_{n}',
                label=f'Full scale range for channel {n}',
                # TODO: validator must be set after device opened
                # vals=Numbers(self.SD_AIN.channelMinFullScale(), self.SD_AIN.channelMaxFullScale())
                set_cmd=partial(self.set_full_scale, channel=n),
                get_cmd=partial(self.get_full_scale, channel=n),
                docstring=f'The full scale voltage for channel {n}')

            # For channelTriggerConfig
            self.add_parameter(f'impedance_{n}',
                               label=f'Impedance for channel {n}',
                               vals=Enum(0, 1),
                               set_cmd=partial(self.set_impedance, channel=n),
                               get_cmd=partial(self.get_impedance, channel=n),
                               docstring=f'The input impedance of channel {n}')

            self.add_parameter(f'coupling_{n}',
                               label=f'Coupling for channel {n}',
                               vals=Enum(0, 1),
                               set_cmd=partial(self.set_coupling, channel=n),
                               get_cmd=partial(self.get_coupling, channel=n),
                               docstring=f'The coupling of channel {n}')

            # For channelPrescalerConfig
            self.add_parameter(
                f'prescaler_{n}',
                label=f'Prescaler for channel {n}',
                vals=Ints(0, 4095),
                set_cmd=partial(self.set_prescaler, channel=n),
                get_cmd=partial(self.get_prescaler, channel=n),
                docstring=f'The sampling frequency prescaler for channel {n}')

            # For channelTriggerConfig
            self.add_parameter(f'trigger_mode_{n}',
                               label=f'Trigger mode for channel {n}',
                               vals=Enum(0, 1, 2, 3, 4, 5, 6, 7),
                               set_cmd=partial(self.set_trigger_mode,
                                               channel=n),
                               docstring=f'The trigger mode for channel {n}')

            self.add_parameter(
                f'trigger_threshold_{n}',
                label=f'Trigger threshold for channel {n}',
                vals=Numbers(-3, 3),
                set_cmd=partial(self.set_trigger_threshold, channel=n),
                docstring=f'The trigger threshold for channel {n}')

            # For DAQ config
            self.add_parameter(
                f'points_per_cycle_{n}',
                label=f'Points per cycle for channel {n}',
                vals=Ints(),
                set_cmd=partial(self.set_points_per_cycle, channel=n),
                docstring=f'The number of points per cycle for DAQ {n}')

            self.add_parameter(
                f'n_cycles_{n}',
                label=f'n cycles for DAQ {n}',
                vals=Ints(),
                set_cmd=partial(self.set_n_cycles, channel=n),
                docstring=f'The number of cycles to collect on DAQ {n}')

            self.add_parameter(f'DAQ_trigger_delay_{n}',
                               label=f'Trigger delay for for DAQ {n}',
                               vals=Ints(),
                               set_cmd=partial(self.set_daq_trigger_delay,
                                               channel=n),
                               docstring=f'The trigger delay for DAQ {n}')

            self.add_parameter(f'DAQ_trigger_mode_{n}',
                               label=f'Trigger mode for for DAQ {n}',
                               vals=Ints(),
                               set_cmd=partial(self.set_daq_trigger_mode,
                                               channel=n),
                               docstring=f'The trigger mode for DAQ {n}')

            # For DAQ trigger Config
            self.add_parameter(
                f'digital_trigger_mode_{n}',
                label=f'Digital trigger mode for DAQ {n}',
                vals=Ints(),
                set_cmd=partial(self.set_digital_trigger_mode, channel=n),
                docstring=f'The digital trigger mode for DAQ {n}')

            self.add_parameter(
                f'digital_trigger_source_{n}',
                label=f'Digital trigger source for DAQ {n}',
                vals=Ints(),
                set_cmd=partial(self.set_digital_trigger_source, channel=n),
                docstring=f'The digital trigger source for DAQ {n}')

            self.add_parameter(
                f'analog_trigger_mask_{n}',
                label=f'Analog trigger mask for DAQ {n}',
                vals=Ints(),
                set_cmd=partial(self.set_analog_trigger_mask, channel=n),
                docstring=f'The analog trigger mask for DAQ {n}')

            # For DAQ trigger External Config
            self.add_parameter(f'ext_trigger_source_{n}',
                               label=f'External trigger source for DAQ {n}',
                               vals=Ints(),
                               set_cmd=partial(self.set_ext_trigger_source,
                                               channel=n),
                               docstring=f'The trigger source for DAQ {n}')

            self.add_parameter(f'ext_trigger_behaviour_{n}',
                               label=f'External trigger behaviour for DAQ {n}',
                               vals=Ints(),
                               set_cmd=partial(self.set_ext_trigger_behaviour,
                                               channel=n),
                               docstring=f'The trigger behaviour for DAQ {n}')

            # For DAQ read
            self.add_parameter(
                f'n_points_{n}',
                label=f'n points for DAQ {n}',
                vals=Ints(),
                set_cmd=partial(self.set_n_points, channel=n),
                docstring=
                f'The number of points to be read using daq_read on DAQ {n}')

            self.add_parameter(f'timeout_{n}',
                               label=f'timeout for DAQ {n}',
                               vals=Ints(),
                               set_cmd=partial(self.set_timeout, channel=n),
                               docstring=f'The read timeout for DAQ {n}')
Exemple #7
0
    def __init__(self, name, address, **kwargs):
        super().__init__(name, address, terminator='\n', **kwargs)

        self.add_parameter('rangev',
                           get_cmd='SENS:VOLT:RANG?',
                           get_parser=float,
                           set_cmd='SOUR:VOLT:RANG {:f}',
                           label='Voltage range')

        self.add_parameter('rangei',
                           get_cmd='SENS:CURR:RANG?',
                           get_parser=float,
                           set_cmd='SOUR:CURR:RANG {:f}',
                           label='Current range')

        self.add_parameter('compliancev',
                           get_cmd='SENS:VOLT:PROT?',
                           get_parser=float,
                           set_cmd='SENS:VOLT:PROT {:f}',
                           label='Voltage Compliance')

        self.add_parameter('compliancei',
                           get_cmd='SENS:CURR:PROT?',
                           get_parser=float,
                           set_cmd='SENS:CURR:PROT {:f}',
                           label='Current Compliance')

        self.add_parameter('volt',
                           get_cmd=':READ?',
                           get_parser=self._volt_parser,
                           set_cmd=':SOUR:VOLT:LEV {:.8f}',
                           label='Voltage',
                           unit='V')

        self.add_parameter('curr',
                           get_cmd=':READ?',
                           get_parser=self._curr_parser,
                           set_cmd=':SOUR:CURR:LEV {:.8f}',
                           label='Current',
                           unit='A')

        self.add_parameter('mode',
                           vals=Enum('VOLT', 'CURR'),
                           get_cmd=':SOUR:FUNC?',
                           set_cmd=self._set_mode_and_sense,
                           label='Mode')

        self.add_parameter('sense',
                           vals=Strings(),
                           get_cmd=':SENS:FUNC?',
                           set_cmd=':SENS:FUNC "{:s}"',
                           label='Sense mode')

        self.add_parameter('output',
                           get_parser=int,
                           set_cmd=':OUTP:STAT {:d}',
                           get_cmd=':OUTP:STAT?')

        self.add_parameter('nplcv',
                           get_cmd='SENS:VOLT:NPLC?',
                           get_parser=float,
                           set_cmd='SENS:VOLT:NPLC {:f}',
                           label='Voltage integration time')

        self.add_parameter('nplci',
                           get_cmd='SENS:CURR:NPLC?',
                           get_parser=float,
                           set_cmd='SENS:CURR:NPLC {:f}',
                           label='Current integration time')

        self.add_parameter('resistance',
                           get_cmd=':READ?',
                           get_parser=self._resistance_parser,
                           label='Resistance',
                           unit='Ohm')
    def __init__(self, name, address, reset_device=False, **kwargs):
        """ Driver for the Keithley 6500 multimeter. Based on the Keithley 2000 driver,
            commands have been adapted for the Keithley 6500. This driver does not contain
            all commands available, but only the ones most commonly used.

            Status: beta-version.

        Args:
            name (str): The name used internally by QCoDeS in the DataSet.
            address (str): The VISA device address.
            reset_device (bool): Reset the device on startup if true.
        """
        super().__init__(name, address, terminator='\n', **kwargs)

        self._trigger_sent = False

        self._mode_map = {
            'ac current': 'CURR:AC',
            'dc current': 'CURR:DC',
            'ac voltage': 'VOLT:AC',
            'dc voltage': 'VOLT:DC',
            '2w resistance': 'RES',
            '4w resistance': 'FRES',
            'temperature': 'TEMP',
            'frequency': 'FREQ'
        }

        self.add_parameter('mode',
                           get_cmd='SENS:FUNC?',
                           set_cmd="SENS:FUNC {}",
                           val_mapping=self._mode_map)

        self.add_parameter('nplc',
                           get_cmd=partial(self._get_mode_param, 'NPLC',
                                           float),
                           set_cmd=partial(self._set_mode_param, 'NPLC'),
                           vals=Numbers(min_value=0.01, max_value=10))

        #  TODO: validator, this one is more difficult since different modes
        #  require different validation ranges.
        self.add_parameter('range',
                           get_cmd=partial(self._get_mode_param, 'RANG',
                                           float),
                           set_cmd=partial(self._set_mode_param, 'RANG'),
                           vals=Numbers())

        self.add_parameter('auto_range_enabled',
                           get_cmd=partial(self._get_mode_param, 'RANG:AUTO',
                                           _parse_output_bool),
                           set_cmd=partial(self._set_mode_param, 'RANG:AUTO'),
                           vals=Bool())

        self.add_parameter('digits',
                           get_cmd='DISP:VOLT:DC:DIG?',
                           get_parser=int,
                           set_cmd='DISP:VOLT:DC:DIG? {}',
                           vals=Ints(min_value=4, max_value=7))

        self.add_parameter('averaging_type',
                           get_cmd=partial(self._get_mode_param, 'AVER:TCON',
                                           _parse_output_string),
                           set_cmd=partial(self._set_mode_param, 'AVER:TCON'),
                           vals=Enum('moving', 'repeat'))

        self.add_parameter('averaging_count',
                           get_cmd=partial(self._get_mode_param, 'AVER:COUN',
                                           int),
                           set_cmd=partial(self._set_mode_param, 'AVER:COUN'),
                           vals=Ints(min_value=1, max_value=100))

        self.add_parameter('averaging_enabled',
                           get_cmd=partial(self._get_mode_param, 'AVER:STAT',
                                           _parse_output_bool),
                           set_cmd=partial(self._set_mode_param, 'AVER:STAT'),
                           vals=Bool())

        # Global parameters
        self.add_parameter('display_enabled',
                           get_parser=_parse_output_bool,
                           get_cmd='DISP:ENAB?',
                           set_cmd='DISP:ENAB {}',
                           set_parser=int,
                           vals=Bool())

        self.add_parameter('trigger_count',
                           get_parser=int,
                           get_cmd='ROUT:SCAN:COUN:SCAN?',
                           set_cmd='ROUT:SCAN:COUN:SCAN {}',
                           vals=MultiType(
                               Ints(min_value=1, max_value=9999),
                               Enum('inf', 'default', 'minimum', 'maximum')))

        self.add_parameter('trigger_delay',
                           get_parser=float,
                           get_cmd='TRIG:DEL?',
                           set_cmd='TRIG:DEL {}',
                           unit='s',
                           vals=Numbers(min_value=0, max_value=999999.999))

        self.add_parameter('trigger_source',
                           get_cmd='TRIG:SOUR?',
                           set_cmd='TRIG:SOUR {}',
                           val_mapping={
                               'immediate': 'NONE',
                               'timer': 'TIM',
                               'manual': 'MAN',
                               'bus': 'BUS',
                               'external': 'EXT'
                           })

        self.add_parameter('trigger_timer',
                           get_parser=float,
                           get_cmd='ROUT:SCAN:INT?',
                           set_cmd='ROUT:SCAN:INT {}',
                           unit='s',
                           vals=Numbers(min_value=0.001, max_value=999999.999))

        self.add_parameter('amplitude',
                           get_cmd=self._read_next_value,
                           set_cmd=False,
                           unit='a.u.')

        if reset_device:
            self.reset()
        self.write('FORM:DATA ASCII')
        self.connect_message()
    def __init__(self,
                 name: str,
                 address: str,
                 terminator: str = "\n\r",
                 **kwargs) -> None:
        super().__init__(name, address, terminator=terminator, **kwargs)

        # self.write('DL1')

        self.add_parameter('output',
                           label='Output State',
                           get_cmd=self.state,
                           set_cmd=lambda x: self.on() if x else self.off(),
                           val_mapping={
                               'off': 0,
                               'on': 1,
                           })

        self.add_parameter('source_mode',
                           label='Source Mode',
                           get_cmd=self._get_source_mode,
                           set_cmd=self._set_source_mode,
                           vals=Enum('VOLT', 'CURR'))

        # When getting the mode internally in the driver, look up the mode as recorded by the _cached_mode property,
        # instead of calling source_mode(). This will prevent frequent VISA calls to the instrument. Calling
        # _set_source_mode will change the chased value.
        self._cached_mode = "VOLT"

        # We want to cache the range value so communication with the instrument only happens when the set the
        # range. Getting the range always returns the cached value. This value is adjusted when calling
        # self._set_range
        self._cached_range_value = None  # type: Optional[float]

        self.add_parameter('voltage_range',
                           label='Voltage Source Range',
                           unit='V',
                           get_cmd=partial(self._get_range, "VOLT"),
                           set_cmd=partial(self._set_range, "VOLT"),
                           vals=Enum(10e-3, 100e-3, 1e0, 10e0, 30e0))

        self.add_parameter('current_range',
                           label='Current Source Range',
                           unit='I',
                           get_cmd=partial(self._get_range, "CURR"),
                           set_cmd=partial(self._set_range, "CURR"),
                           vals=Enum(1e-3, 10e-3, 100e-3, 200e-3))

        # This is changed through the source_mode interface
        self.range = self.voltage_range

        self._auto_range = False
        self.add_parameter('auto_range',
                           label='Auto Range',
                           set_cmd=self._set_auto_range,
                           get_cmd=lambda: self._auto_range,
                           vals=Bool())

        self.add_parameter('voltage',
                           label='Voltage',
                           unit='V',
                           set_cmd=partial(self._get_set_output, "VOLT"),
                           get_cmd=partial(self._get_set_output, "VOLT"))

        self.add_parameter('current',
                           label='Current',
                           unit='I',
                           set_cmd=partial(self._get_set_output, "CURR"),
                           get_cmd=partial(self._get_set_output, "CURR"))

        # This is changed through the source_mode interface
        self.output_level = self.voltage

        self.add_parameter('voltage_limit',
                           label='Voltage Protection Limit',
                           unit='V',
                           vals=Ints(1, 30),
                           get_cmd=":SOUR:PROT:VOLT?",
                           set_cmd=":SOUR:PROT:VOLT {}",
                           get_parser=float_round,
                           set_parser=int)

        self.add_parameter('current_limit',
                           label='Current Protection Limit',
                           unit='I',
                           vals=Numbers(1e-3, 200e-3),
                           get_cmd=":SOUR:PROT:CURR?",
                           set_cmd=":SOUR:PROT:CURR {:.3f}",
                           get_parser=float,
                           set_parser=float)

        self.add_parameter('four_wire',
                           label='Four Wire Sensing',
                           get_cmd=':SENS:REM?',
                           set_cmd=':SENS:REM {}',
                           val_mapping={
                               'off': 0,
                               'on': 1,
                           })
        # Note: The guard feature can be used to remove common mode noise.
        # Read the manual to see if you would like to use it
        self.add_parameter('guard',
                           label='Guard Terminal',
                           get_cmd=':SENS:GUAR?',
                           set_cmd=':SENS:GUAR {}',
                           val_mapping={
                               'off': 0,
                               'on': 1,
                           })

        # Return measured line frequency
        self.add_parameter("line_freq",
                           label='Line Frequency',
                           unit="Hz",
                           get_cmd="SYST:LFR?",
                           get_parser=int)

        # Reset function
        #        self.add_function('reset', call_cmd='*RST')
        self.connect_message()
Exemple #10
0
 def test_bad(self):
     for enum in self.not_enums:
         with self.assertRaises(TypeError):
             Enum(*enum)
    def __init__(self, name, device, ai_channels=None):
        super().__init__(name)
        self._ai_task = None

        time_constant = 0.0000000001
        rate = 100e3
        self._device = device

        if ai_channels is None:
            ai_channels = {
                0: {
                    'range': 10,
                    'mode': 'diff'
                },
                1: {
                    'range': 10,
                    'mode': 'diff'
                },
                2: {
                    'range': 10,
                    'mode': 'diff'
                },
                3: {
                    'range': 10,
                    'mode': 'diff'
                }
            }

        self._make_ai_task(ai_channels, time_constant, rate)

        self.add_parameter(name='time_constant',
                           label='Time constant',
                           get_cmd=self._ai_task.time_constant,
                           set_cmd=self._ai_task.time_constant,
                           set_parser=float,
                           unit='s',
                           vals=Numbers(min_value=0.0001))

        self.add_parameter(name='sample_rate',
                           label='Sample rate',
                           get_cmd=self._ai_task.sample_rate,
                           set_cmd=self._ai_task.sample_rate,
                           set_parser=int,
                           unit='S/s',
                           vals=Ints(max_value=int(1e6)))

        self.add_parameter(
            name='input_range',
            label='Input rate',
            # get_cmd=self._ai_task.input_range,
            set_cmd=self._ai_task.input_range,
            set_parser=float,
            unit='V',
            vals=Enum(0.316, 1.00, 3.16, 10.0, 31.6, 42.4))

        self.add_parameter(
            'ai',
            get_cmd=self._ai_task.read,
            # get_parser=float,
            names=['ai%d' % ch for ch in ai_channels],
            units=['V'] * len(ai_channels),
            parameter_class=ParameterArray)

        for ch in ai_channels:
            self.add_parameter('ai%d' % ch,
                               get_cmd=partial(self._get_ai_ch, ch),
                               unit='V')

            self.add_parameter('ai%d_range' % ch,
                               label='Range ai%d' % ch,
                               set_cmd=partial(self._ai_range, ch),
                               get_cmd=partial(self._ai_range, ch),
                               set_parser=float,
                               unit='V',
                               vals=Enum(0.316, 1.00, 3.16, 10.0, 31.6, 42.4))

            self.add_parameter('ai%d_mode' % ch,
                               label='Mode ai%d' % ch,
                               set_cmd=partial(self._ai_mode, ch),
                               get_cmd=partial(self._ai_mode, ch),
                               vals=Enum('diff', 'pseudo_diff', 'nrse', 'rse'))
Exemple #12
0
    def __init__(
        self,
        parent: "PNABase",
        name: str,
        trace_name: str,
        trace_num: int,
        **kwargs: Any,
    ) -> None:
        super().__init__(parent, name, **kwargs)
        self.trace_name = trace_name
        self.trace_num = trace_num

        # Name of parameter (i.e. S11, S21 ...)
        self.add_parameter('trace',
                           label='Trace',
                           get_cmd=self._Sparam,
                           set_cmd=self._set_Sparam)
        # Format
        # Note: Currently parameters that return complex values are not
        # supported as there isn't really a good way of saving them into the
        # dataset
        self.add_parameter('format',
                           label='Format',
                           get_cmd='CALC:FORM?',
                           set_cmd='CALC:FORM {}',
                           vals=Enum('MLIN', 'MLOG', 'PHAS',
                                     'UPH', 'IMAG', 'REAL'))

        # And a list of individual formats
        self.add_parameter('magnitude',
                           sweep_format='MLOG',
                           label='Magnitude',
                           unit='dB',
                           parameter_class=FormattedSweep,
                           vals=Arrays(shape=(self.parent.points,)))
        self.add_parameter('linear_magnitude',
                           sweep_format='MLIN',
                           label='Magnitude',
                           unit='ratio',
                           parameter_class=FormattedSweep,
                           vals=Arrays(shape=(self.parent.points,)))
        self.add_parameter('phase',
                           sweep_format='PHAS',
                           label='Phase',
                           unit='deg',
                           parameter_class=FormattedSweep,
                           vals=Arrays(shape=(self.parent.points,)))
        self.add_parameter('unwrapped_phase',
                           sweep_format='UPH',
                           label='Phase',
                           unit='deg',
                           parameter_class=FormattedSweep,
                           vals=Arrays(shape=(self.parent.points,)))
        self.add_parameter("group_delay",
                           sweep_format='GDEL',
                           label='Group Delay',
                           unit='s',
                           parameter_class=FormattedSweep,
                           vals=Arrays(shape=(self.parent.points,)))
        self.add_parameter('real',
                           sweep_format='REAL',
                           label='Real',
                           unit='LinMag',
                           parameter_class=FormattedSweep,
                           vals=Arrays(shape=(self.parent.points,)))
        self.add_parameter('imaginary',
                           sweep_format='IMAG',
                           label='Imaginary',
                           unit='LinMag',
                           parameter_class=FormattedSweep,
                           vals=Arrays(shape=(self.parent.points,)))
Exemple #13
0
    def __init__(self, name, address, reset_device=False, **kwargs):
        """ Driver for the Keithley 6500 multimeter. Based on the Keithley 2000 driver,
            commands have been adapted for the Keithley 6500. This driver does not contain
            all commands available, but only the ones most commonly used.

            Status: beta-version.

        Args:
            name (str): The name used internally by QCoDeS in the DataSet.
            address (str): The VISA device address.
            reset_device (bool): Reset the device on startup if true.
        """
        super().__init__(name, address, terminator='\n', **kwargs)

        command_set = self.ask('*LANG?')
        if command_set != 'SCPI':
            error_msg = "This driver only compatible with the 'SCPI' command " \
                        "set, not '{}' set".format(command_set)
            raise CommandSetError(error_msg)

        self._trigger_sent = False

        self._mode_map = {
            'ac current': 'CURR:AC',
            'dc current': 'CURR:DC',
            'ac voltage': 'VOLT:AC',
            'dc voltage': 'VOLT:DC',
            '2w resistance': 'RES',
            '4w resistance': 'FRES',
            'temperature': 'TEMP',
            'frequency': 'FREQ'
        }

        self.add_parameter('mode',
                           get_cmd='SENS:FUNC?',
                           set_cmd="SENS:FUNC {}",
                           val_mapping=self._mode_map)

        self.add_parameter('nplc',
                           get_cmd=partial(self._get_mode_param, 'NPLC',
                                           float),
                           set_cmd=partial(self._set_mode_param, 'NPLC'),
                           vals=Numbers(min_value=0.01, max_value=10))

        #  TODO: validator, this one is more difficult since different modes
        #  require different validation ranges.
        self.add_parameter('range',
                           get_cmd=partial(self._get_mode_param, 'RANG',
                                           float),
                           set_cmd=partial(self._set_mode_param, 'RANG'),
                           vals=Numbers())

        self.add_parameter('auto_range_enabled',
                           get_cmd=partial(self._get_mode_param, 'RANG:AUTO',
                                           _parse_output_bool),
                           set_cmd=partial(self._set_mode_param, 'RANG:AUTO'),
                           vals=Bool())

        self.add_parameter('digits',
                           get_cmd='DISP:VOLT:DC:DIG?',
                           get_parser=int,
                           set_cmd='DISP:VOLT:DC:DIG? {}',
                           vals=Ints(min_value=4, max_value=7))

        self.add_parameter('averaging_type',
                           get_cmd=partial(self._get_mode_param, 'AVER:TCON',
                                           _parse_output_string),
                           set_cmd=partial(self._set_mode_param, 'AVER:TCON'),
                           vals=Enum('moving', 'repeat'))

        self.add_parameter('averaging_count',
                           get_cmd=partial(self._get_mode_param, 'AVER:COUN',
                                           int),
                           set_cmd=partial(self._set_mode_param, 'AVER:COUN'),
                           vals=Ints(min_value=1, max_value=100))

        self.add_parameter('averaging_enabled',
                           get_cmd=partial(self._get_mode_param, 'AVER:STAT',
                                           _parse_output_bool),
                           set_cmd=partial(self._set_mode_param, 'AVER:STAT'),
                           vals=Bool())

        # Global parameters
        self.add_parameter('display_backlight',
                           docstring='Control the brightness of the display '
                           'backligt. Off turns the display off and'
                           'Blackout also turns off indicators and '
                           'key lights on the device.',
                           get_cmd='DISP:LIGH:STAT?',
                           set_cmd='DISP:LIGH:STAT {}',
                           val_mapping={
                               'On 100': 'ON100',
                               'On 75': 'ON75',
                               'On 50': 'ON50',
                               'On 25': 'ON25',
                               'Off': 'OFF',
                               'Blackout': 'BLACkout'
                           })

        self.add_parameter('trigger_count',
                           get_parser=int,
                           get_cmd='ROUT:SCAN:COUN:SCAN?',
                           set_cmd='ROUT:SCAN:COUN:SCAN {}',
                           vals=MultiType(
                               Ints(min_value=1, max_value=9999),
                               Enum('inf', 'default', 'minimum', 'maximum')))

        for trigger in range(1, 5):
            self.add_parameter('trigger%i_delay' % trigger,
                               docstring='Set and read trigger delay for '
                               'timer %i.' % trigger,
                               get_parser=float,
                               get_cmd='TRIG:TIM%i:DEL?' % trigger,
                               set_cmd='TRIG:TIM%i:DEL {}' % trigger,
                               unit='s',
                               vals=Numbers(min_value=0, max_value=999999.999))

            self.add_parameter('trigger%i_source' % trigger,
                               docstring='Set the trigger source for '
                               'timer %i.' % trigger,
                               get_cmd='TRIG:TIM%i:STAR:STIM?' % trigger,
                               set_cmd='TRIG:TIM%i:STAR:STIM {}' % trigger,
                               val_mapping={
                                   'immediate': 'NONE',
                                   'timer1': 'TIM1',
                                   'timer2': 'TIM2',
                                   'timer3': 'TIM3',
                                   'timer4': 'TIM4',
                                   'notify1': 'NOT1',
                                   'notify2': 'NOT2',
                                   'notify3': 'NOT3',
                                   'front-panel': 'DISP',
                                   'bus': 'COMM',
                                   'external': 'EXT'
                               })

        self.add_parameter('trigger_timer',
                           get_parser=float,
                           get_cmd='ROUT:SCAN:INT?',
                           set_cmd='ROUT:SCAN:INT {}',
                           unit='s',
                           vals=Numbers(min_value=0.001, max_value=999999.999))

        self.add_parameter('amplitude',
                           get_cmd=self._read_next_value,
                           set_cmd=False,
                           unit='a.u.')

        if reset_device:
            self.reset()
        self.write('FORM:DATA ASCII')
        self.connect_message()
Exemple #14
0
    def __init__(self, name, cardid='spcm0', **kwargs):
        """Driver for the Spectrum M4i.44xx-x8 cards.

        For more information see: http://spectrum-instrumentation.com/en/m4i-platform-overview

        Example:

            Example usage for acquisition with channel 2 using an external trigger
            that triggers multiple times with trigger mode HIGH::

                m4 = M4i(name='M4i', server_name=None)
                m4.enable_channels(pyspcm.CHANNEL2)
                m4.set_channel_settings(2,mV_range, input_path, termination, coupling, compensation)
                m4.set_ext0_OR_trigger_settings(pyspcm.SPC_TM_HIGH,termination,coupling,level0)
                calc = m4.multiple_trigger_acquisition(mV_range,memsize,seg_size,posttrigger_size)

        Todo:
          Whenever an error occurs (including validation errors) the python
          console needs to be restarted


        """
        super().__init__(name, **kwargs)

        self.hCard = pyspcm.spcm_hOpen(cardid)
        if self.hCard is None:
            logging.warning("M4i: no card found\n")

        # add parameters for getting
        self.add_parameter('card_id',
                           label='card id',
                           parameter_class=ManualParameter,
                           initial_value=cardid,
                           vals=Anything(),
                           docstring='The card ID')
        self.add_parameter('max_sample_rate',
                           label='max sample rate',
                           unit='Hz',
                           get_cmd=self.get_max_sample_rate,
                           docstring='The maximumum sample rate')
        self.add_parameter('memory',
                           label='memory',
                           unit='bytes',
                           get_cmd=self.get_card_memory,
                           docstring='Amount of memory on card')
        self.add_parameter('resolution',
                           label='resolution',
                           unit='bits',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_MIINST_BITSPERSAMPLE),
                           docstring='Resolution of the card')
        self.add_parameter('pcidate',
                           label='pcidate',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_PCIDATE),
                           docstring='The PCI date')
        self.add_parameter('serial_number',
                           label='serial number',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_PCISERIALNO),
                           docstring='The serial number of the board')
        self.add_parameter('channel_count',
                           label='channel count',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_CHCOUNT),
                           docstring='Return number of enabled channels')
        self.add_parameter('input_path_count',
                           label='input path count',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_READAIPATHCOUNT),
                           docstring='Return number of analog input paths')
        self.add_parameter('input_ranges_count',
                           label='input ranges count',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_READIRCOUNT),
                           docstring='Return number of input ranges for the current input path')
        self.add_parameter('input_path_features',
                           label='input path features',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_READAIFEATURES),
                           docstring='Return a bitmap of features for current input path')
        self.add_parameter('available_card_modes',
                           label='available card modes',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_AVAILCARDMODES),
                           docstring='Return a bitmap of available card modes')
        self.add_parameter('card_status',
                           label='card status',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_M2STATUS),
                           docstring='Return a bitmap for the status information')
        self.add_parameter('read_range_min_0',
                           label='read range min 0', unit='mV',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_READRANGEMIN0),
                           docstring='Return the lower border of input range 0')

        # buffer handling
        self.add_parameter('user_available_length',
                           label='user available length',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_DATA_AVAIL_USER_LEN),
                           docstring='returns the number of currently to the user available bytes inside a sample data transfer')
        self.add_parameter('user_available_position',
                           label='user available position',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_DATA_AVAIL_USER_POS),
                           docstring='returns the position as byte index where the currently available data samles start')
        self.add_parameter('buffer_fill_size',
                           label='buffer fill size',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_FILLSIZEPROMILLE),
                           docstring='returns the current fill size of the on-board memory (FIFO buffer) in promille (1/1000)')

        # triggering
        self.add_parameter('available_trigger_or_mask',
                           label='available trigger or mask',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_TRIG_AVAILORMASK),
                           docstring='bitmask, in which all bits of sources for the OR mask are set, if available')
        self.add_parameter('available_channel_or_mask',
                           label='available channel or mask',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_TRIG_CH_AVAILORMASK0),
                           docstring='bitmask, in which all bits of sources/channels (0-31) for the OR mask are set, if available')
        self.add_parameter('available_trigger_and_mask',
                           label='available trigger and mask',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_TRIG_AVAILANDMASK),
                           docstring='bitmask, in which all bits of sources for the AND mask are set, if available')
        self.add_parameter('available_channel_and_mask',
                           label='available channel and mask',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_TRIG_CH_AVAILANDMASK0),
                           docstring='bitmask, in which all bits of sources/channels (0-31) for the AND mask are set, if available')
        self.add_parameter('available_trigger_delay',
                           label='available trigger delay',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_TRIG_AVAILDELAY),
                           docstring='contains the maximum available delay as decimal integer value')
        self.add_parameter('available_external_trigger_modes',
                           label='available external trigger modes',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_TRIG_EXT0_AVAILMODES),
                           docstring='bitmask showing all available trigger modes for external 0 (main analog trigger input)')
        self.add_parameter('external_trigger_min_level',
                           label='external trigger min level',
                           unit='mV',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_TRIG_EXT_AVAIL0_MIN),
                           docstring='returns the minimum trigger level')
        self.add_parameter('external_trigger_max_level',
                           label='external trigger max level',
                           unit='mV',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_TRIG_EXT_AVAIL0_MAX),
                           docstring='returns the maximum trigger level')
        self.add_parameter('external_trigger_level_step_size',
                           label='external trigger level step size',
                           unit='mV',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_TRIG_EXT_AVAIL0_STEP),
                           docstring='returns the step size of the trigger level')
        self.add_parameter('available_channel_trigger_modes',
                           label='available channel trigger modes',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_TRIG_CH_AVAILMODES),
                           docstring='bitmask, in which all bits of the modes for the channel trigger are set')
        self.add_parameter('trigger_counter',
                           label='trigger counter',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_TRIGGERCOUNTER),
                           docstring='returns the number of triger events since acquisition start')
        # data per sample
        self.add_parameter('bytes_per_sample',
                           label='bytes per sample',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_MIINST_BYTESPERSAMPLE),
                           docstring='returns the number of bytes per sample')
        self.add_parameter('bits_per_sample',
                           label='bits per sample',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_MIINST_BITSPERSAMPLE),
                           docstring='returns the number of bits per sample')

        # available clock modes
        self.add_parameter('available_clock_modes',
                           label='available clock modes',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_AVAILCLOCKMODES),
                           docstring='returns a bitmask in which the bits of the clock modes are set, if available')

        # converting ADC samples to voltage values
        self.add_parameter('ADC_to_voltage',
                           label='ADC to voltage',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_MIINST_MAXADCVALUE),
                           docstring='contains the decimal code (in LSB) of the ADC full scale value')

        self.add_parameter('oversampling_factor',
                           label='oversampling factor',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_OVERSAMPLINGFACTOR),
                           docstring='Reads the oversampling factor')

        # add parameters for setting and getting (read/write direction
        # registers)

        self.add_parameter('enable_channels',
                           label='Channels enabled',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_CHENABLE),
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_CHENABLE),
                           vals=Enum(1, 2, 4, 8, 3, 5, 9, 6, 10, 12, 15),
                           docstring='Set and get enabled channels')

        # analog input path functions
        # TODO: change Enum validator to set_parser for the numbered functions
        # if we want string inputs

        self.add_parameter('read_input_path',
                           label='read input path',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_READAIPATH),
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_READAIPATH),
                           vals=Enum(0, 1, 2, 3),
                           docstring='Select the input path which is used to read out the features')

        for i in [0, 1, 2, 3]:
            self.add_parameter('input_path_{}'.format(i),
                               label='input path {}'.format(i),
                               get_cmd=partial(self._param32bit, getattr(
                                   pyspcm, 'SPC_PATH{}'.format(i))),
                               set_cmd=partial(self._set_param32bit, getattr(
                                   pyspcm, 'SPC_PATH{}'.format(i))),
                               vals=Enum(0, 1),
                               docstring='Set and get analog input path for channel {}'.format(i))

            # channel range functions
            # TODO: check the input path to set the right validator (either by
            # directly calling input_path_x() or by storing a variable)
            self.add_parameter('range_channel_{}'.format(i),
                               label='range channel {}'.format(i),
                               get_cmd=partial(self._param32bit, getattr(
                                   pyspcm, 'SPC_AMP{}'.format(i))),
                               set_cmd=partial(self._set_param32bit, getattr(
                                   pyspcm, 'SPC_AMP{}'.format(i))),
                               vals=Enum(200, 500, 1000, 2000,
                                         2500, 5000, 10000),
                               docstring='Set and get input range of channel {}'.format(i))

            # input termination functions
            self.add_parameter('termination_{}'.format(i),
                               label='termination {}'.format(i),
                               get_cmd=partial(self._param32bit, getattr(
                                   pyspcm, 'SPC_50OHM{}'.format(i))),
                               set_cmd=partial(self._set_param32bit, getattr(
                                   pyspcm, 'SPC_50OHM{}'.format(i))),
                               vals=Enum(0, 1),
                               docstring='if 1 sets termination to 50 Ohm, otherwise 1 MOhm for channel {}'.format(i))

            # input coupling
            self.add_parameter('ACDC_coupling_{}'.format(i),
                               label='ACDC coupling {}'.format(i),
                               get_cmd=partial(self._param32bit, getattr(
                                   pyspcm, 'SPC_ACDC{}'.format(i))),
                               set_cmd=partial(self._set_param32bit, getattr(
                                   pyspcm, 'SPC_ACDC{}'.format(i))),
                               vals=Enum(0, 1),
                               docstring='if 1 sets the AC coupling, otherwise sets the DC coupling for channel {}'.format(i))

            # AC/DC offset compensation
            self.add_parameter('ACDC_offs_compensation_{}'.format(i),
                               label='ACDC offs compensation {}'.format(i),
                               get_cmd=partial(self._get_compensation, i),
                               set_cmd=partial(self._set_compensation, i),
                               vals=Enum(0, 1),
                               docstring='if 1 enables compensation, if 0 disables compensation for channel {}'.format(i))

            # anti aliasing filter (Bandwidth limit)
            self.add_parameter('anti_aliasing_filter_{}'.format(i),
                               label='anti aliasing filter {}'.format(i),
                               get_cmd=partial(self._param32bit, getattr(
                                   pyspcm, 'SPC_FILTER{}'.format(i))),
                               set_cmd=partial(self._set_param32bit, getattr(
                                   pyspcm, 'SPC_FILTER{}'.format(i))),
                               vals=Enum(0, 1),
                               docstring='if 1 selects bandwidth limit, if 0 sets to full bandwidth for channel {}'.format(i))

            self.add_parameter('channel_{}'.format(i),
                               label='channel {}'.format(i),
                               unit='a.u.',
                               get_cmd=partial(self._read_channel, i))

        # acquisition modes
        # TODO: If required, the other acquisition modes can be added to the
        # validator
        self.add_parameter('card_mode',
                           label='card mode',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_CARDMODE),
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_CARDMODE),
                           vals=Enum(pyspcm.SPC_REC_STD_SINGLE, pyspcm.SPC_REC_STD_MULTI, pyspcm.SPC_REC_STD_GATE, pyspcm.SPC_REC_STD_ABA,
                                     pyspcm.SPC_REC_FIFO_SINGLE, pyspcm.SPC_REC_FIFO_MULTI, pyspcm.SPC_REC_FIFO_GATE, pyspcm.SPC_REC_FIFO_ABA, pyspcm.SPC_REC_STD_AVERAGE),
                           docstring='defines the used operating mode')

        # wait command
        self.add_parameter('timeout',
                           label='timeout',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_TIMEOUT),
                           unit='ms',
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_TIMEOUT),
                           docstring='defines the timeout for wait commands')

        # Single acquisition mode memory, pre- and posttrigger (pretrigger = memory size - posttrigger)
        # TODO: improve the validators to make them take into account the
        # current state of the instrument
        self.add_parameter('data_memory_size',
                           label='data memory size',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_MEMSIZE),
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_MEMSIZE),
                           vals=Numbers(min_value=16),
                           docstring='sets the memory size in samples per channel')
        self.add_parameter('posttrigger_memory_size',
                           label='posttrigger memory size',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_POSTTRIGGER),
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_POSTTRIGGER),
                           docstring='sets the number of samples to be recorded after trigger event')

        # FIFO single acquisition length and pretrigger
        self.add_parameter('pretrigger_memory_size',
                           label='pretrigger memory size',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_PRETRIGGER),
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_PRETRIGGER),
                           docstring='sets the number of samples to be recorded before trigger event')
        self.add_parameter('segment_size',
                           label='segment size',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_SEGMENTSIZE),
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_SEGMENTSIZE),
                           docstring='length of segments to acquire')
        self.add_parameter('total_segments',
                           label='total segments',
                           get_cmd=partial(self._param32bit, pyspcm.SPC_LOOPS),
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_LOOPS),
                           docstring='number of segments to acquire in total. Setting 0 makes it run until stopped by user')

        # clock generation
        self.add_parameter('clock_mode',
                           label='clock mode',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_CLOCKMODE),
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_CLOCKMODE),
                           vals=Enum(pyspcm.SPC_CM_INTPLL, pyspcm.SPC_CM_QUARTZ2,
                                     pyspcm.SPC_CM_EXTREFCLOCK, pyspcm.SPC_CM_PXIREFCLOCK),
                           docstring='defines the used clock mode or reads out the actual selected one')
        self.add_parameter('sample_rate',
                           label='sample rate',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_SAMPLERATE),
                           unit='Hz',
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_SAMPLERATE),
                           docstring='write the sample rate for internal sample generation or read rate nearest to desired')
        self.add_parameter('special_clock',
                           label='special clock',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_SPECIALCLOCK),
                           unit='Hz',
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_SPECIALCLOCK),
                           docstring='Activate/Deactivate the special clock mode (lower and more sampling clock rates)')

        # triggering
        self.add_parameter('trigger_or_mask',
                           label='trigger or mask',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_TRIG_ORMASK),
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_TRIG_ORMASK),
                           vals=Enum(pyspcm.SPC_TMASK_NONE, pyspcm.SPC_TMASK_SOFTWARE,
                                     pyspcm.SPC_TMASK_EXT0, pyspcm.SPC_TMASK_EXT1),
                           docstring='defines the events included within the  trigger OR mask card')
        self.add_parameter('channel_or_mask',
                           label='channel or mask',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_TRIG_CH_ORMASK0),
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_TRIG_CH_ORMASK0),
                           docstring='includes the channels (0-31) within the channel trigger OR mask of the card')
        self.add_parameter('trigger_and_mask',
                           label='trigger and mask',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_TRIG_ANDMASK),
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_TRIG_ANDMASK),
                           vals=Enum(pyspcm.SPC_TMASK_NONE,
                                     pyspcm.SPC_TMASK_EXT0, pyspcm.SPC_TMASK_EXT1),
                           docstring='defines the events included within the  trigger AND mask card')
        self.add_parameter('channel_and_mask',
                           label='channel and mask',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_TRIG_CH_ANDMASK0),
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_TRIG_CH_ANDMASK0),
                           docstring='includes the channels (0-31) within the channel trigger AND mask of the card')
        self.add_parameter('trigger_delay',
                           label='trigger delay',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_TRIG_DELAY),
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_TRIG_DELAY),
                           docstring='defines the delay for the detected trigger events')
        self.add_parameter('external_trigger_mode',
                           label='external trigger mode',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_TRIG_EXT0_MODE),
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_TRIG_EXT0_MODE),
                           docstring='defines the external trigger mode for the external SMA connector trigger input')
        self.add_parameter('external_trigger_termination',
                           label='external trigger termination',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_TRIG_TERM),
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_TRIG_TERM),
                           vals=Enum(0, 1),
                           docstring='A 1 sets the 50 Ohm termination, a 0 sets high impedance termination')
        self.add_parameter('external_trigger_input_coupling',
                           label='external trigger input coupling',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_TRIG_EXT0_ACDC),
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_TRIG_EXT0_ACDC),
                           vals=Enum(0, 1),
                           docstring='A 1 sets the AC coupling for the external trigger, a 0 sets DC')

        for l in [0, 1]:
            self.add_parameter('external_trigger_level_{}'.format(l),
                               label='external trigger level {}'.format(l),
                               get_cmd=partial(self._param32bit, getattr(
                                   pyspcm, 'SPC_TRIG_EXT0_LEVEL{}'.format(l))),
                               set_cmd=partial(self._set_param32bit, getattr(
                                   pyspcm, 'SPC_TRIG_EXT0_LEVEL{}'.format(l))),
                               docstring='trigger level {} for external trigger'.format(l))

        for i in [0, 1, 2, 3]:
            self.add_parameter('trigger_mode_channel_{}'.format(i),
                               label='trigger mode channel {}'.format(i),
                               get_cmd=partial(self._param32bit, getattr(
                                   pyspcm, 'SPC_TRIG_CH{}_MODE'.format(i))),
                               set_cmd=partial(self._set_param32bit, getattr(
                                   pyspcm, 'SPC_TRIG_CH{}_MODE'.format(i))),
                               docstring='sets the trigger mode for channel {}'.format(i))
            for l in [0, 1]:
                self.add_parameter('trigger_channel_{}_level_{}'.format(i, l),
                                   label='trigger channel {} level {}'.format(
                                       i, l),
                                   get_cmd=partial(self._param32bit, getattr(
                                       pyspcm, 'SPC_TRIG_CH{}_LEVEL{}'.format(i, l))),
                                   set_cmd=partial(self._set_param32bit, getattr(
                                       pyspcm, 'SPC_TRIG_CH{}_LEVEL{}'.format(i, l))),
                                   docstring='trigger level {} channel {}'.format(l, i))

        # add parameters for setting (write only registers)

        # Buffer handling
        self.add_parameter('card_available_length',
                           label='card available length',
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_DATA_AVAIL_CARD_LEN),
                           docstring='writes the number of bytes that the card can now use for sample data transfer again')

        # General
        self.add_parameter('general_command',
                           label='general command',
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_M2CMD),
                           docstring='executes a command for the card or data transfer')

        # memsize used for simple channel read-out
        self._channel_memsize = 2**12
Exemple #15
0
class SR86x(VisaInstrument):
    """
    This is the code for Stanford_SR865 Lock-in Amplifier
    """
    _VOLT_TO_N = {
        1: 0,
        500e-3: 1,
        200e-3: 2,
        100e-3: 3,
        50e-3: 4,
        20e-3: 5,
        10e-3: 6,
        5e-3: 7,
        2e-3: 8,
        1e-3: 9,
        500e-6: 10,
        200e-6: 11,
        100e-6: 12,
        50e-6: 13,
        20e-6: 14,
        10e-6: 15,
        5e-6: 16,
        2e-6: 17,
        1e-6: 18,
        500e-9: 19,
        200e-9: 20,
        100e-9: 21,
        50e-9: 22,
        20e-9: 23,
        10e-9: 24,
        5e-9: 25,
        2e-9: 26,
        1e-9: 27
    }
    _N_TO_VOLT = {v: k for k, v in _VOLT_TO_N.items()}

    _CURR_TO_N = {
        1e-6: 0,
        500e-9: 1,
        200e-9: 2,
        100e-9: 3,
        50e-9: 4,
        20e-9: 5,
        10e-9: 6,
        5e-9: 7,
        2e-9: 8,
        1e-9: 9,
        500e-12: 10,
        200e-12: 11,
        100e-12: 12,
        50e-12: 13,
        20e-12: 14,
        10e-12: 15,
        5e-12: 16,
        2e-12: 17,
        1e-12: 18,
        500e-15: 19,
        200e-15: 20,
        100e-15: 21,
        50e-15: 22,
        20e-15: 23,
        10e-15: 24,
        5e-15: 25,
        2e-15: 26,
        1e-15: 27
    }
    _N_TO_CURR = {v: k for k, v in _CURR_TO_N.items()}

    _VOLT_ENUM = Enum(*_VOLT_TO_N.keys())
    _CURR_ENUM = Enum(*_CURR_TO_N.keys())

    _INPUT_SIGNAL_TO_N = {
        'voltage': 0,
        'current': 1,
    }
    _N_TO_INPUT_SIGNAL = {v: k for k, v in _INPUT_SIGNAL_TO_N.items()}

    PARAMETER_NAMES = {
        'X': '0',  # X output, 'X'
        'Y': '1',  # Y output, 'Y'
        'R': '2',  # R output, 'R'
        'P': '3',  # theta output, 'THeta'
        'aux_in1': '4',  # Aux In 1, 'IN1'
        'aux_in2': '5',  # Aux In 2, 'IN2'
        'aux_in3': '6',  # Aux In 3, 'IN3'
        'aux_in4': '7',  # Aux In 4, 'IN4'
        'Xnoise': '8',  # X noise, 'XNOise'
        'Ynoise': '9',  # Y noise, 'YNOise'
        'aux_out1': '10',  # Aux Out 1, 'OUT1'
        'aux_out2': '11',  # Aux Out 2, 'OUT2'
        'phase': '12',  # Reference Phase, 'PHAse'
        'amplitude': '13',  # Sine Out Amplitude, 'SAMp'
        'sine_outdc': '14',  # DC Level, 'LEVel'
        'frequency': '15',  # Int. Ref. Frequency, 'FInt'
        'frequency_ext': '16',  # Ext. Ref. Frequency, 'FExt'
    }

    _N_DATA_CHANNELS = 4

    def __init__(self,
                 name: str,
                 address: str,
                 max_frequency: float,
                 reset: bool = False,
                 **kwargs: Any):
        super().__init__(name, address, terminator='\n', **kwargs)
        self._max_frequency = max_frequency
        # Reference commands
        self.add_parameter(name='frequency',
                           label='Frequency',
                           unit='Hz',
                           get_cmd='FREQ?',
                           set_cmd='FREQ {}',
                           get_parser=float,
                           vals=Numbers(min_value=1e-3,
                                        max_value=self._max_frequency))
        self.add_parameter(name='sine_outdc',
                           label='Sine out dc level',
                           unit='V',
                           get_cmd='SOFF?',
                           set_cmd='SOFF {}',
                           get_parser=float,
                           vals=Numbers(min_value=-5, max_value=5))
        self.add_parameter(name='amplitude',
                           label='Amplitude',
                           unit='V',
                           get_cmd='SLVL?',
                           set_cmd='SLVL {}',
                           get_parser=float,
                           vals=Numbers(min_value=0, max_value=2))
        self.add_parameter(name='harmonic',
                           label='Harmonic',
                           get_cmd='HARM?',
                           get_parser=int,
                           set_cmd='HARM {:d}',
                           vals=Ints(min_value=1, max_value=99))
        self.add_parameter(name='phase',
                           label='Phase',
                           unit='deg',
                           get_cmd='PHAS?',
                           set_cmd='PHAS {}',
                           get_parser=float,
                           vals=Numbers(min_value=-3.6e5, max_value=3.6e5))
        # Signal commands
        self.add_parameter(name='sensitivity',
                           label='Sensitivity',
                           get_cmd='SCAL?',
                           set_cmd='SCAL {:d}',
                           get_parser=self._get_sensitivity,
                           set_parser=self._set_sensitivity)
        self.add_parameter(name='filter_slope',
                           label='Filter slope',
                           unit='dB/oct',
                           get_cmd='OFSL?',
                           set_cmd='OFSL {}',
                           val_mapping={
                               6: 0,
                               12: 1,
                               18: 2,
                               24: 3
                           })
        self.add_parameter(name='sync_filter',
                           label='Sync filter',
                           get_cmd='SYNC?',
                           set_cmd='SYNC {}',
                           val_mapping={
                               'OFF': 0,
                               'ON': 1
                           })
        self.add_parameter(name='noise_bandwidth',
                           label='Noise bandwidth',
                           unit='Hz',
                           get_cmd='ENBW?',
                           get_parser=float)
        self.add_parameter(name='signal_strength',
                           label='Signal strength indicator',
                           get_cmd='ILVL?',
                           get_parser=int)
        self.add_parameter(name='signal_input',
                           label='Signal input',
                           get_cmd='IVMD?',
                           get_parser=self._get_input_config,
                           set_cmd='IVMD {}',
                           set_parser=self._set_input_config,
                           vals=Enum(*self._INPUT_SIGNAL_TO_N.keys()))
        self.add_parameter(name='input_range',
                           label='Input range',
                           unit='V',
                           get_cmd='IRNG?',
                           set_cmd='IRNG {}',
                           val_mapping={
                               1: 0,
                               300e-3: 1,
                               100e-3: 2,
                               30e-3: 3,
                               10e-3: 4
                           })
        self.add_parameter(name='input_config',
                           label='Input configuration',
                           get_cmd='ISRC?',
                           set_cmd='ISRC {}',
                           val_mapping={
                               'a': 0,
                               'a-b': 1
                           })
        self.add_parameter(name='input_shield',
                           label='Input shield',
                           get_cmd='IGND?',
                           set_cmd='IGND {}',
                           val_mapping={
                               'float': 0,
                               'ground': 1
                           })
        self.add_parameter(name='input_gain',
                           label='Input gain',
                           unit='ohm',
                           get_cmd='ICUR?',
                           set_cmd='ICUR {}',
                           val_mapping={
                               1e6: 0,
                               100e6: 1
                           })
        self.add_parameter(name='adv_filter',
                           label='Advanced filter',
                           get_cmd='ADVFILT?',
                           set_cmd='ADVFILT {}',
                           val_mapping={
                               'OFF': 0,
                               'ON': 1
                           })
        self.add_parameter(name='input_coupling',
                           label='Input coupling',
                           get_cmd='ICPL?',
                           set_cmd='ICPL {}',
                           val_mapping={
                               'ac': 0,
                               'dc': 1
                           })
        self.add_parameter(name='time_constant',
                           label='Time constant',
                           unit='s',
                           get_cmd='OFLT?',
                           set_cmd='OFLT {}',
                           val_mapping={
                               1e-6: 0,
                               3e-6: 1,
                               10e-6: 2,
                               30e-6: 3,
                               100e-6: 4,
                               300e-6: 5,
                               1e-3: 6,
                               3e-3: 7,
                               10e-3: 8,
                               30e-3: 9,
                               100e-3: 10,
                               300e-3: 11,
                               1: 12,
                               3: 13,
                               10: 14,
                               30: 15,
                               100: 16,
                               300: 17,
                               1e3: 18,
                               3e3: 19,
                               10e3: 20,
                               30e3: 21
                           })

        self.add_parameter(
            name="external_reference_trigger",
            label="External reference trigger mode",
            get_cmd="RTRG?",
            set_cmd="RTRG {}",
            val_mapping={
                "SIN": 0,
                "POS": 1,
                "POSTTL": 1,
                "NEG": 2,
                "NEGTTL": 2,
            },
            docstring="The triggering mode for synchronization of the "
            "internal reference signal with the externally provided "
            "one")

        self.add_parameter(name="reference_source",
                           label="Reference source",
                           get_cmd="RSRC?",
                           set_cmd="RSRC {}",
                           val_mapping={
                               "INT": 0,
                               "EXT": 1,
                               "DUAL": 2,
                               "CHOP": 3
                           },
                           docstring="The source of the reference signal")

        self.add_parameter(
            name="external_reference_trigger_input_resistance",
            label="External reference trigger input resistance",
            get_cmd="REFZ?",
            set_cmd="REFZ {}",
            val_mapping={
                "50": 0,
                "50OHMS": 0,
                0: 0,
                "1M": 1,
                "1MEG": 1,
                1: 1,
            },
            docstring="Input resistance of the input for the external "
            "reference signal")

        # Auto functions
        self.add_function('auto_range', call_cmd='ARNG')
        self.add_function('auto_scale', call_cmd='ASCL')
        self.add_function('auto_phase', call_cmd='APHS')

        # Data transfer
        # first 4 parameters from a list of 16 below.
        self.add_parameter('X',
                           label='In-phase Magnitude',
                           get_cmd='OUTP? 0',
                           get_parser=float,
                           unit='V')
        self.add_parameter('Y',
                           label='Out-phase Magnitude',
                           get_cmd='OUTP? 1',
                           get_parser=float,
                           unit='V')
        self.add_parameter('R',
                           label='Magnitude',
                           get_cmd='OUTP? 2',
                           get_parser=float,
                           unit='V')
        self.add_parameter('P',
                           label='Phase',
                           get_cmd='OUTP? 3',
                           get_parser=float,
                           unit='deg')

        # CH1/CH2 Output Commands
        self.add_parameter('X_offset',
                           label='X offset ',
                           unit='%',
                           get_cmd='COFP? 0',
                           set_cmd='COFP 0, {}',
                           get_parser=float,
                           vals=Numbers(min_value=-999.99, max_value=999.99))
        self.add_parameter('Y_offset',
                           label='Y offset',
                           unit='%',
                           get_cmd='COFP? 1',
                           set_cmd='COFP 1, {}',
                           get_parser=float,
                           vals=Numbers(min_value=-999.99, max_value=999.99))
        self.add_parameter('R_offset',
                           label='R offset',
                           unit='%',
                           get_cmd='COFP? 2',
                           set_cmd='COFP 2, {}',
                           get_parser=float,
                           vals=Numbers(min_value=-999.99, max_value=999.99))
        self.add_parameter('X_expand',
                           label='X expand multiplier',
                           get_cmd='CEXP? 0',
                           set_cmd='CEXP 0, {}',
                           val_mapping={
                               'OFF': '0',
                               'X10': '1',
                               'X100': '2'
                           })
        self.add_parameter('Y_expand',
                           label='Y expand multiplier',
                           get_cmd='CEXP? 1',
                           set_cmd='CEXP 1, {}',
                           val_mapping={
                               'OFF': 0,
                               'X10': 1,
                               'X100': 2
                           })
        self.add_parameter('R_expand',
                           label='R expand multiplier',
                           get_cmd='CEXP? 2',
                           set_cmd='CEXP 2, {}',
                           val_mapping={
                               'OFF': 0,
                               'X10': 1,
                               'X100': 2
                           })

        # Aux input/output
        for i in [0, 1, 2, 3]:
            self.add_parameter(f'aux_in{i}',
                               label=f'Aux input {i}',
                               get_cmd=f'OAUX? {i}',
                               get_parser=float,
                               unit='V')
            self.add_parameter(f'aux_out{i}',
                               label=f'Aux output {i}',
                               get_cmd=f'AUXV? {i}',
                               get_parser=float,
                               set_cmd=f'AUXV {i}, {{}}',
                               unit='V')

        # Data channels:
        # 'DAT1' (green), 'DAT2' (blue), 'DAT3' (yellow), 'DAT4' (orange)
        data_channels = ChannelList(self,
                                    "data_channels",
                                    SR86xDataChannel,
                                    snapshotable=False)
        for num, color in zip(range(self._N_DATA_CHANNELS),
                              ('green', 'blue', 'yellow', 'orange')):
            cmd_id = f"{num}"
            cmd_id_name = f"DAT{num + 1}"
            ch_name = f"data_channel_{num + 1}"

            data_channel = SR86xDataChannel(self, ch_name, cmd_id, cmd_id_name,
                                            color)

            data_channels.append(data_channel)
            self.add_submodule(ch_name, data_channel)

        data_channels.lock()
        self.add_submodule("data_channels", data_channels)

        # Interface
        self.add_function('reset', call_cmd='*RST')

        self.add_function('disable_front_panel', call_cmd='OVRM 0')
        self.add_function('enable_front_panel', call_cmd='OVRM 1')

        buffer = SR86xBuffer(self, f"{self.name}_buffer")
        self.add_submodule("buffer", buffer)

        self.input_config()
        self.connect_message()

    def _set_units(self, unit: str) -> None:
        for param in [self.X, self.Y, self.R, self.sensitivity]:
            param.unit = unit

    def _get_input_config(self, s: int) -> str:
        mode = self._N_TO_INPUT_SIGNAL[int(s)]

        if mode == 'voltage':
            self.sensitivity.vals = self._VOLT_ENUM
            self._set_units('V')
        else:
            self.sensitivity.vals = self._CURR_ENUM
            self._set_units('A')

        return mode

    def _set_input_config(self, s: str) -> int:
        if s == 'voltage':
            self.sensitivity.vals = self._VOLT_ENUM
            self._set_units('V')
        else:
            self.sensitivity.vals = self._CURR_ENUM
            self._set_units('A')

        return self._INPUT_SIGNAL_TO_N[s]

    def _get_sensitivity(self, s: int) -> float:
        if self.signal_input() == 'voltage':
            return self._N_TO_VOLT[int(s)]
        else:
            return self._N_TO_CURR[int(s)]

    def _set_sensitivity(self, s: float) -> int:
        if self.signal_input() == 'voltage':
            return self._VOLT_TO_N[s]
        else:
            return self._CURR_TO_N[s]

    def get_values(self, *parameter_names: str) -> Tuple[float, ...]:
        """
        Get values of 2 or 3 parameters that are measured by the lock-in
        amplifier. These values are guaranteed to come from the same
        measurement cycle as opposed to getting values of parameters one by
        one (for example, by calling `sr.X()`, and then `sr.Y()`.

        Args:
            *parameter_names: 2 or 3 names of parameters for which the values
                are requested; valid names can be found in `PARAMETER_NAMES`
                attribute of the driver class

        Returns:
            a tuple of 2 or 3 floating point values

        """
        if not 2 <= len(parameter_names) <= 3:
            raise KeyError(
                'It is only possible to request values of 2 or 3 parameters '
                'at a time.')

        for name in parameter_names:
            if name not in self.PARAMETER_NAMES:
                raise KeyError(f'{name} is not a valid parameter name. Refer '
                               f'to `PARAMETER_NAMES` for a list of valid '
                               f'parameter names')

        p_ids = [self.PARAMETER_NAMES[name] for name in parameter_names]
        output = self.ask(f'SNAP? {",".join(p_ids)}')
        return tuple(float(val) for val in output.split(','))

    def get_data_channels_values(self) -> Tuple[float, ...]:
        """
        Queries the current values of the data channels

        Returns:
            tuple of 4 values of the data channels
        """
        output = self.ask('SNAPD?')
        return tuple(float(val) for val in output.split(','))

    def get_data_channels_parameters(self,
                                     query_instrument: bool = True
                                     ) -> Tuple[str, ...]:
        """
        Convenience method to query a list of parameters which the data
        channels are currently assigned to.

        Args:
            query_instrument: If set to False, the internally cashed names of
                the parameters will be returned; if True, then the names will
                be queried through the instrument

        Returns:
            a tuple of 4 strings of parameter names
        """
        if query_instrument:
            method_name = 'get'
        else:
            method_name = 'get_latest'

        return tuple(
            getattr(getattr(self.data_channels[i], 'assigned_parameter'),
                    method_name)() for i in range(self._N_DATA_CHANNELS))

    def get_data_channels_dict(self,
                               requery_names: bool = False
                               ) -> Dict[str, float]:
        """
        Returns a dictionary where the keys are parameter names currently
        assigned to the data channels, and values are the values of those
        parameters.

        Args:
            requery_names: if False, the currently assigned parameter names
                will not be queries from the instrument in order to save time
                on communication, in this case the cached assigned parameter
                names will be used for the keys of the dicitonary; if True,
                the assigned parameter names will be queried from the
                instrument

        Returns:
            a dictionary where keys are names of parameters assigned to the
            data channels, and values are the values of those parameters
        """
        parameter_names = self.get_data_channels_parameters(requery_names)
        parameter_values = self.get_data_channels_values()
        return dict(zip(parameter_names, parameter_values))
Exemple #16
0
def test_bad():
    for enum in not_enums:
        with pytest.raises(TypeError):
            Enum(*enum)
Exemple #17
0
    def __init__(self,
                 name: str,
                 address: str,
                 max_frequency: float,
                 reset: bool = False,
                 **kwargs: Any):
        super().__init__(name, address, terminator='\n', **kwargs)
        self._max_frequency = max_frequency
        # Reference commands
        self.add_parameter(name='frequency',
                           label='Frequency',
                           unit='Hz',
                           get_cmd='FREQ?',
                           set_cmd='FREQ {}',
                           get_parser=float,
                           vals=Numbers(min_value=1e-3,
                                        max_value=self._max_frequency))
        self.add_parameter(name='sine_outdc',
                           label='Sine out dc level',
                           unit='V',
                           get_cmd='SOFF?',
                           set_cmd='SOFF {}',
                           get_parser=float,
                           vals=Numbers(min_value=-5, max_value=5))
        self.add_parameter(name='amplitude',
                           label='Amplitude',
                           unit='V',
                           get_cmd='SLVL?',
                           set_cmd='SLVL {}',
                           get_parser=float,
                           vals=Numbers(min_value=0, max_value=2))
        self.add_parameter(name='harmonic',
                           label='Harmonic',
                           get_cmd='HARM?',
                           get_parser=int,
                           set_cmd='HARM {:d}',
                           vals=Ints(min_value=1, max_value=99))
        self.add_parameter(name='phase',
                           label='Phase',
                           unit='deg',
                           get_cmd='PHAS?',
                           set_cmd='PHAS {}',
                           get_parser=float,
                           vals=Numbers(min_value=-3.6e5, max_value=3.6e5))
        # Signal commands
        self.add_parameter(name='sensitivity',
                           label='Sensitivity',
                           get_cmd='SCAL?',
                           set_cmd='SCAL {:d}',
                           get_parser=self._get_sensitivity,
                           set_parser=self._set_sensitivity)
        self.add_parameter(name='filter_slope',
                           label='Filter slope',
                           unit='dB/oct',
                           get_cmd='OFSL?',
                           set_cmd='OFSL {}',
                           val_mapping={
                               6: 0,
                               12: 1,
                               18: 2,
                               24: 3
                           })
        self.add_parameter(name='sync_filter',
                           label='Sync filter',
                           get_cmd='SYNC?',
                           set_cmd='SYNC {}',
                           val_mapping={
                               'OFF': 0,
                               'ON': 1
                           })
        self.add_parameter(name='noise_bandwidth',
                           label='Noise bandwidth',
                           unit='Hz',
                           get_cmd='ENBW?',
                           get_parser=float)
        self.add_parameter(name='signal_strength',
                           label='Signal strength indicator',
                           get_cmd='ILVL?',
                           get_parser=int)
        self.add_parameter(name='signal_input',
                           label='Signal input',
                           get_cmd='IVMD?',
                           get_parser=self._get_input_config,
                           set_cmd='IVMD {}',
                           set_parser=self._set_input_config,
                           vals=Enum(*self._INPUT_SIGNAL_TO_N.keys()))
        self.add_parameter(name='input_range',
                           label='Input range',
                           unit='V',
                           get_cmd='IRNG?',
                           set_cmd='IRNG {}',
                           val_mapping={
                               1: 0,
                               300e-3: 1,
                               100e-3: 2,
                               30e-3: 3,
                               10e-3: 4
                           })
        self.add_parameter(name='input_config',
                           label='Input configuration',
                           get_cmd='ISRC?',
                           set_cmd='ISRC {}',
                           val_mapping={
                               'a': 0,
                               'a-b': 1
                           })
        self.add_parameter(name='input_shield',
                           label='Input shield',
                           get_cmd='IGND?',
                           set_cmd='IGND {}',
                           val_mapping={
                               'float': 0,
                               'ground': 1
                           })
        self.add_parameter(name='input_gain',
                           label='Input gain',
                           unit='ohm',
                           get_cmd='ICUR?',
                           set_cmd='ICUR {}',
                           val_mapping={
                               1e6: 0,
                               100e6: 1
                           })
        self.add_parameter(name='adv_filter',
                           label='Advanced filter',
                           get_cmd='ADVFILT?',
                           set_cmd='ADVFILT {}',
                           val_mapping={
                               'OFF': 0,
                               'ON': 1
                           })
        self.add_parameter(name='input_coupling',
                           label='Input coupling',
                           get_cmd='ICPL?',
                           set_cmd='ICPL {}',
                           val_mapping={
                               'ac': 0,
                               'dc': 1
                           })
        self.add_parameter(name='time_constant',
                           label='Time constant',
                           unit='s',
                           get_cmd='OFLT?',
                           set_cmd='OFLT {}',
                           val_mapping={
                               1e-6: 0,
                               3e-6: 1,
                               10e-6: 2,
                               30e-6: 3,
                               100e-6: 4,
                               300e-6: 5,
                               1e-3: 6,
                               3e-3: 7,
                               10e-3: 8,
                               30e-3: 9,
                               100e-3: 10,
                               300e-3: 11,
                               1: 12,
                               3: 13,
                               10: 14,
                               30: 15,
                               100: 16,
                               300: 17,
                               1e3: 18,
                               3e3: 19,
                               10e3: 20,
                               30e3: 21
                           })

        self.add_parameter(
            name="external_reference_trigger",
            label="External reference trigger mode",
            get_cmd="RTRG?",
            set_cmd="RTRG {}",
            val_mapping={
                "SIN": 0,
                "POS": 1,
                "POSTTL": 1,
                "NEG": 2,
                "NEGTTL": 2,
            },
            docstring="The triggering mode for synchronization of the "
            "internal reference signal with the externally provided "
            "one")

        self.add_parameter(name="reference_source",
                           label="Reference source",
                           get_cmd="RSRC?",
                           set_cmd="RSRC {}",
                           val_mapping={
                               "INT": 0,
                               "EXT": 1,
                               "DUAL": 2,
                               "CHOP": 3
                           },
                           docstring="The source of the reference signal")

        self.add_parameter(
            name="external_reference_trigger_input_resistance",
            label="External reference trigger input resistance",
            get_cmd="REFZ?",
            set_cmd="REFZ {}",
            val_mapping={
                "50": 0,
                "50OHMS": 0,
                0: 0,
                "1M": 1,
                "1MEG": 1,
                1: 1,
            },
            docstring="Input resistance of the input for the external "
            "reference signal")

        # Auto functions
        self.add_function('auto_range', call_cmd='ARNG')
        self.add_function('auto_scale', call_cmd='ASCL')
        self.add_function('auto_phase', call_cmd='APHS')

        # Data transfer
        # first 4 parameters from a list of 16 below.
        self.add_parameter('X',
                           label='In-phase Magnitude',
                           get_cmd='OUTP? 0',
                           get_parser=float,
                           unit='V')
        self.add_parameter('Y',
                           label='Out-phase Magnitude',
                           get_cmd='OUTP? 1',
                           get_parser=float,
                           unit='V')
        self.add_parameter('R',
                           label='Magnitude',
                           get_cmd='OUTP? 2',
                           get_parser=float,
                           unit='V')
        self.add_parameter('P',
                           label='Phase',
                           get_cmd='OUTP? 3',
                           get_parser=float,
                           unit='deg')

        # CH1/CH2 Output Commands
        self.add_parameter('X_offset',
                           label='X offset ',
                           unit='%',
                           get_cmd='COFP? 0',
                           set_cmd='COFP 0, {}',
                           get_parser=float,
                           vals=Numbers(min_value=-999.99, max_value=999.99))
        self.add_parameter('Y_offset',
                           label='Y offset',
                           unit='%',
                           get_cmd='COFP? 1',
                           set_cmd='COFP 1, {}',
                           get_parser=float,
                           vals=Numbers(min_value=-999.99, max_value=999.99))
        self.add_parameter('R_offset',
                           label='R offset',
                           unit='%',
                           get_cmd='COFP? 2',
                           set_cmd='COFP 2, {}',
                           get_parser=float,
                           vals=Numbers(min_value=-999.99, max_value=999.99))
        self.add_parameter('X_expand',
                           label='X expand multiplier',
                           get_cmd='CEXP? 0',
                           set_cmd='CEXP 0, {}',
                           val_mapping={
                               'OFF': '0',
                               'X10': '1',
                               'X100': '2'
                           })
        self.add_parameter('Y_expand',
                           label='Y expand multiplier',
                           get_cmd='CEXP? 1',
                           set_cmd='CEXP 1, {}',
                           val_mapping={
                               'OFF': 0,
                               'X10': 1,
                               'X100': 2
                           })
        self.add_parameter('R_expand',
                           label='R expand multiplier',
                           get_cmd='CEXP? 2',
                           set_cmd='CEXP 2, {}',
                           val_mapping={
                               'OFF': 0,
                               'X10': 1,
                               'X100': 2
                           })

        # Aux input/output
        for i in [0, 1, 2, 3]:
            self.add_parameter(f'aux_in{i}',
                               label=f'Aux input {i}',
                               get_cmd=f'OAUX? {i}',
                               get_parser=float,
                               unit='V')
            self.add_parameter(f'aux_out{i}',
                               label=f'Aux output {i}',
                               get_cmd=f'AUXV? {i}',
                               get_parser=float,
                               set_cmd=f'AUXV {i}, {{}}',
                               unit='V')

        # Data channels:
        # 'DAT1' (green), 'DAT2' (blue), 'DAT3' (yellow), 'DAT4' (orange)
        data_channels = ChannelList(self,
                                    "data_channels",
                                    SR86xDataChannel,
                                    snapshotable=False)
        for num, color in zip(range(self._N_DATA_CHANNELS),
                              ('green', 'blue', 'yellow', 'orange')):
            cmd_id = f"{num}"
            cmd_id_name = f"DAT{num + 1}"
            ch_name = f"data_channel_{num + 1}"

            data_channel = SR86xDataChannel(self, ch_name, cmd_id, cmd_id_name,
                                            color)

            data_channels.append(data_channel)
            self.add_submodule(ch_name, data_channel)

        data_channels.lock()
        self.add_submodule("data_channels", data_channels)

        # Interface
        self.add_function('reset', call_cmd='*RST')

        self.add_function('disable_front_panel', call_cmd='OVRM 0')
        self.add_function('enable_front_panel', call_cmd='OVRM 1')

        buffer = SR86xBuffer(self, f"{self.name}_buffer")
        self.add_submodule("buffer", buffer)

        self.input_config()
        self.connect_message()
Exemple #18
0
def test_valid_values():
    for enum in enums:
        e = Enum(*enum)
        for val in e._valid_values:
            e.validate(val)
Exemple #19
0
    def __init__(
            self,
            name: str,
            address: str,
            # Set frequency ranges
            min_freq: Union[int, float],
            max_freq: Union[int, float],
            # Set power ranges
            min_power: Union[int, float],
            max_power: Union[int, float],
            nports: int,  # Number of ports on the PNA
            **kwargs: Any) -> None:
        super().__init__(name, address, terminator='\n', **kwargs)
        self.min_freq = min_freq
        self.max_freq = max_freq

        #Ports
        ports = ChannelList(self, "PNAPorts", PNAPort)
        for port_num in range(1, nports + 1):
            port = PNAPort(self, f"port{port_num}", port_num, min_power,
                           max_power)
            ports.append(port)
            self.add_submodule(f"port{port_num}", port)
        ports.lock()
        self.add_submodule("ports", ports)

        # Drive power
        self.add_parameter('power',
                           label='Power',
                           get_cmd='SOUR:POW?',
                           get_parser=float,
                           set_cmd='SOUR:POW {:.2f}',
                           unit='dBm',
                           vals=Numbers(min_value=min_power,
                                        max_value=max_power))

        # IF bandwidth
        self.add_parameter('if_bandwidth',
                           label='IF Bandwidth',
                           get_cmd='SENS:BAND?',
                           get_parser=float,
                           set_cmd='SENS:BAND {:.2f}',
                           unit='Hz',
                           vals=Numbers(min_value=1, max_value=15e6))

        # Number of averages (also resets averages)
        self.add_parameter('averages_enabled',
                           label='Averages Enabled',
                           get_cmd="SENS:AVER?",
                           set_cmd="SENS:AVER {}",
                           val_mapping={
                               True: '1',
                               False: '0'
                           })
        self.add_parameter('averages',
                           label='Averages',
                           get_cmd='SENS:AVER:COUN?',
                           get_parser=int,
                           set_cmd='SENS:AVER:COUN {:d}',
                           unit='',
                           vals=Numbers(min_value=1, max_value=65536))

        # Setting frequency range
        self.add_parameter('start',
                           label='Start Frequency',
                           get_cmd='SENS:FREQ:STAR?',
                           get_parser=float,
                           set_cmd='SENS:FREQ:STAR {}',
                           unit='Hz',
                           vals=Numbers(min_value=min_freq,
                                        max_value=max_freq))
        self.add_parameter('stop',
                           label='Stop Frequency',
                           get_cmd='SENS:FREQ:STOP?',
                           get_parser=float,
                           set_cmd='SENS:FREQ:STOP {}',
                           unit='Hz',
                           vals=Numbers(min_value=min_freq,
                                        max_value=max_freq))
        self.add_parameter('center',
                           label='Center Frequency',
                           get_cmd='SENS:FREQ:CENT?',
                           get_parser=float,
                           set_cmd='SENS:FREQ:CENT {}',
                           unit='Hz',
                           vals=Numbers(min_value=min_freq,
                                        max_value=max_freq))
        self.add_parameter('span',
                           label='Frequency Span',
                           get_cmd='SENS:FREQ:SPAN?',
                           get_parser=float,
                           set_cmd='SENS:FREQ:SPAN {}',
                           unit='Hz',
                           vals=Numbers(min_value=min_freq,
                                        max_value=max_freq))

        # Number of points in a sweep
        self.add_parameter('points',
                           label='Points',
                           get_cmd='SENS:SWE:POIN?',
                           get_parser=int,
                           set_cmd='SENS:SWE:POIN {}',
                           unit='',
                           vals=Numbers(min_value=1, max_value=100001))

        # Electrical delay
        self.add_parameter('electrical_delay',
                           label='Electrical Delay',
                           get_cmd='CALC:CORR:EDEL:TIME?',
                           get_parser=float,
                           set_cmd='CALC:CORR:EDEL:TIME {:.6e}',
                           unit='s',
                           vals=Numbers(min_value=0, max_value=100000))

        # Sweep Time
        self.add_parameter('sweep_time',
                           label='Time',
                           get_cmd='SENS:SWE:TIME?',
                           get_parser=float,
                           unit='s',
                           vals=Numbers(0, 1e6))
        # Sweep Mode
        self.add_parameter('sweep_mode',
                           label='Mode',
                           get_cmd='SENS:SWE:MODE?',
                           set_cmd='SENS:SWE:MODE {}',
                           vals=Enum("HOLD", "CONT", "GRO", "SING"))
        # Group trigger count
        self.add_parameter('group_trigger_count',
                           get_cmd="SENS:SWE:GRO:COUN?",
                           get_parser=int,
                           set_cmd="SENS:SWE:GRO:COUN {}",
                           vals=Ints(1, 2000000))
        # Trigger Source
        self.add_parameter('trigger_source',
                           get_cmd="TRIG:SOUR?",
                           set_cmd="TRIG:SOUR {}",
                           vals=Enum("EXT", "IMM", "MAN"))

        # Traces
        self.add_parameter('active_trace',
                           label='Active Trace',
                           get_cmd="CALC:PAR:MNUM?",
                           get_parser=int,
                           set_cmd="CALC:PAR:MNUM {}",
                           vals=Numbers(min_value=1, max_value=24))
        # Note: Traces will be accessed through the traces property which
        # updates the channellist to include only active trace numbers
        self._traces = ChannelList(self, "PNATraces", PNATrace)
        self.add_submodule("traces", self._traces)
        # Add shortcuts to first trace
        trace1 = self.traces[0]
        params = trace1.parameters
        if not isinstance(params, dict):
            raise RuntimeError(f"Expected trace.parameters to be a dict got "
                               f"{type(params)}")
        for param in params.values():
            self.parameters[param.name] = param
        # And also add a link to run sweep
        self.run_sweep = trace1.run_sweep
        # Set this trace to be the default (it's possible to end up in a
        # situation where no traces are selected, causing parameter snapshots
        # to fail)
        self.active_trace(trace1.trace_num)

        # Set auto_sweep parameter
        # If we want to return multiple traces per setpoint without sweeping
        # multiple times, we should set this to false
        self.add_parameter('auto_sweep',
                           label='Auto Sweep',
                           set_cmd=None,
                           get_cmd=None,
                           vals=Bool(),
                           initial_value=True)

        # A default output format on initialisation
        self.write('FORM REAL,32')
        self.write('FORM:BORD NORM')

        self.connect_message()
Exemple #20
0
    def __init__(self, name, address=None, port=None, axes=None, **kwargs):
        super().__init__(name,
                         address=address,
                         port=port,
                         terminator='\n',
                         **kwargs)
        self.axes = axes
        self._ATOB = []
        self._latest_response = ''
        # for some reason the first call is always invalid?!
        # need some kind of init?
        self.ask('*IDN?')

        if axes is None:
            self._determine_magnet_axes()
        self._determine_current_to_field()

        self.add_parameter(
            'setpoint',
            names=['B' + ax.lower() + '_setpoint' for ax in self.axes],
            get_cmd=partial(self._get_fld, self.axes, 'FSET'),
            set_cmd=partial(self._ramp_to_setpoint, self.axes, 'FSET'),
            units=['T' for ax in self.axes],
            vals=Anything())

        self.add_parameter('rate',
                           names=['rate_B' + ax.lower() for ax in self.axes],
                           get_cmd=partial(self._get_fld, self.axes, 'RFST'),
                           set_cmd=partial(self._ramp_to_setpoint, self.axes,
                                           'RFST'),
                           units=['T/m' for ax in self.axes],
                           vals=Anything())

        self.add_parameter('fld',
                           names=['B' + ax.lower() for ax in self.axes],
                           get_cmd=partial(self._get_fld, self.axes, 'FLD'),
                           set_cmd=partial(self._ramp_to_setpoint, self.axes,
                                           'FSET'),
                           units=['T' for ax in self.axes],
                           vals=Anything())

        self.add_parameter('fldC',
                           names=['B' + ax.lower() for ax in self.axes],
                           get_cmd=partial(self._get_fld, self.axes, 'CURR'),
                           set_cmd=partial(self._ramp_to_setpoint, self.axes,
                                           'CSET'),
                           units=['T' for ax in self.axes],
                           vals=Anything())

        self.add_parameter('rtp',
                           names=['radius', 'theta', 'phi'],
                           get_cmd=partial(self._get_rtp, self.axes, 'FLD'),
                           set_cmd=partial(self._set_rtp, self.axes, 'FSET'),
                           units=['|B|', 'rad', 'rad'],
                           vals=Anything())

        self.add_parameter('rtpC',
                           names=['radius', 'theta', 'phi'],
                           get_cmd=partial(self._get_rtp, self.axes, 'CURR'),
                           set_cmd=partial(self._set_rtp, self.axes, 'CSET'),
                           units=['|B|', 'rad', 'rad'],
                           vals=Anything())

        # so we have radius, theta and phi in buffer
        self.rtp.get()

        self.add_parameter('radius',
                           get_cmd=self._get_r,
                           set_cmd=self._set_r,
                           units='|B|')
        self.add_parameter('theta',
                           get_cmd=self._get_theta,
                           set_cmd=self._set_theta,
                           units='rad')
        self.add_parameter('phi',
                           get_cmd=self._get_phi,
                           set_cmd=self._set_phi,
                           units='rad')

        for ax in self.axes:
            self.add_parameter(ax.lower() + '_fld',
                               get_cmd=partial(self._get_fld, ax, 'FLD'),
                               set_cmd=partial(self._ramp_to_setpoint, ax,
                                               'FSET'),
                               label='B' + ax.lower(),
                               units='T')
            self.add_parameter(ax.lower() + '_fldC',
                               get_cmd=partial(self._get_fld, ax, 'CURR'),
                               set_cmd=partial(self._ramp_to_setpoint, ax,
                                               'CSET'),
                               label='B' + ax.lower(),
                               units='T')
            self.add_parameter(ax.lower() + '_fld_wait',
                               get_cmd=partial(self._get_fld, ax, 'CURR'),
                               set_cmd=partial(self._ramp_to_setpoint_and_wait,
                                               ax, 'CSET'),
                               label='B' + ax.lower(),
                               units='T')
            self.add_parameter(ax.lower() + '_ACTN',
                               get_cmd=partial(
                                   self._get_cmd,
                                   'READ:DEV:GRP' + ax + ':PSU:ACTN?'),
                               set_cmd='SET:DEV:GRP' + ax + ':PSU:ACTN:{}',
                               vals=Enum('HOLD', 'RTOS', 'RTOZ', 'CLMP'))
            self.add_parameter(ax.lower() + '_setpoint',
                               get_cmd=partial(self._get_fld, ax, 'FSET'),
                               set_cmd=partial(self._set_fld, ax, 'FSET'),
                               units='T')
            self.add_parameter(ax.lower() + '_setpointC',
                               get_cmd=partial(self._get_fld, ax, 'CSET'),
                               set_cmd=partial(self._set_fld, ax, 'CSET'),
                               units='T')
            self.add_parameter(ax.lower() + '_rate',
                               get_cmd=partial(self._get_fld, ax, 'RFST'),
                               set_cmd=partial(self._set_fld, ax, 'RFST'),
                               units='T/m')
            self.add_parameter(ax.lower() + '_rateC',
                               get_cmd=partial(self._get_fld, ax, 'RCST'),
                               set_cmd=partial(self._set_fld, ax, 'RCST'),
                               units='T/m')

            self.connect_message()
Exemple #21
0
    def __init__(self, parent: Union[Instrument, InstrumentChannel],
                 name: str) -> None:

        super().__init__(parent, name)

        self.add_parameter("mode",
                           get_cmd="HORizontal:MODE?",
                           set_cmd="HORizontal:MODE {}",
                           vals=Enum("auto", "constant", "manual"),
                           get_parser=str.lower,
                           docstring="""
            Auto mode attempts to keep record length
            constant as you change the time per division
            setting. Record length is read only.

            Constant mode attempts to keep sample rate
            constant as you change the time per division
            setting. Record length is read only.

            Manual mode lets you change sample mode and
            record length. Time per division or Horizontal
            scale is read only.
            """)

        self.add_parameter("unit",
                           get_cmd="HORizontal:MAIn:UNIts?",
                           get_parser=strip_quotes)

        self.add_parameter("record_length",
                           get_cmd="HORizontal:MODE:RECOrdlength?",
                           set_cmd=self._set_record_length,
                           get_parser=float)

        self.add_parameter("sample_rate",
                           get_cmd="HORizontal:MODE:SAMPLERate?",
                           set_cmd="HORizontal:MODE:SAMPLERate {}",
                           get_parser=float,
                           unit=f"sample/{self.unit()}")

        self.add_parameter("scale",
                           get_cmd="HORizontal:MODE:SCAle?",
                           set_cmd=self._set_scale,
                           get_parser=float,
                           unit=f"{self.unit()}/div")

        self.add_parameter("position",
                           get_cmd="HORizontal:POSition?",
                           set_cmd="HORizontal:POSition {}",
                           get_parser=float,
                           unit="%",
                           docstring=textwrap.dedent("""
            The horizontal position relative to a
            received trigger. E.g. a value of '10'
            sets the trigger position of the waveform
            such that 10% of the display is to the
            left of the trigger position.
            """))

        self.add_parameter("roll",
                           get_cmd="HORizontal:ROLL?",
                           set_cmd="HORizontal:ROLL {}",
                           vals=Enum("Auto", "On", "Off"),
                           docstring=textwrap.dedent("""
            Use Roll Mode when you want to view data at
            very slow sweep speeds.
            """))
Exemple #22
0
    def __init__(self, name: str, address: str, **kwargs) -> None:

        super().__init__(name, address, terminator='\n', **kwargs)

        if not self._has_correct_language_mode():
            self.log.warning(
                f"The instrument is in an unsupported language mode. "
                f"Please run `instrument.set_correct_language()` and try to "
                f"initialize the driver again after an instrument power cycle. "
                f"No parameters/sub modules will be available on this driver "
                f"instance"
            )
            return

        self.add_parameter(
            "source_function",
            set_cmd=self._set_source_function,
            get_cmd=":SOUR:FUNC?",
            val_mapping={
                key: value["name"]
                for key, value in Source2450.function_modes.items()
            }
        )

        self.add_parameter(
            "sense_function",
            set_cmd=self._set_sense_function,
            get_cmd=":SENS:FUNC?",
            val_mapping={
                key: value["name"]
                for key, value in Sense2450.function_modes.items()
            }
        )

        self.add_parameter(
            "terminals",
            set_cmd="ROUTe:TERMinals {}",
            get_cmd="ROUTe:TERMinals?",
            vals=Enum("rear", "front")
        )

        self.add_parameter(
            "output_enabled",
            initial_value="0",
            set_cmd=":OUTP {}",
            get_cmd=":OUTP?",
            val_mapping=create_on_off_val_mapping(on_val="1", off_val="0")
        )

        # Make a source module for every source function ('current' and 'voltage')
        for proper_source_function in Source2450.function_modes:
            self.add_submodule(
                f"_source_{proper_source_function}",
                Source2450(self, "source", proper_source_function)
            )

        # Make a sense module for every sense function ('current', voltage' and 'resistance')
        for proper_sense_function in Sense2450.function_modes:
            self.add_submodule(
                f"_sense_{proper_sense_function}",
                Sense2450(self, "sense", proper_sense_function)
            )

        self.connect_message()
Exemple #23
0
class SR830(VisaInstrument):
    """
    This is the qcodes driver for the Stanford Research Systems SR830
    Lock-in Amplifier
    """

    _VOLT_TO_N = {2e-9:    0, 5e-9:    1, 10e-9:  2,
                  20e-9:   3, 50e-9:   4, 100e-9: 5,
                  200e-9:  6, 500e-9:  7, 1e-6:   8,
                  2e-6:    9, 5e-6:   10, 10e-6:  11,
                  20e-6:  12, 50e-6:  13, 100e-6: 14,
                  200e-6: 15, 500e-6: 16, 1e-3:   17,
                  2e-3:   18, 5e-3:   19, 10e-3:  20,
                  20e-3:  21, 50e-3:  22, 100e-3: 23,
                  200e-3: 24, 500e-3: 25, 1:      26}
    _N_TO_VOLT = {v: k for k, v in _VOLT_TO_N.items()}

    _CURR_TO_N = {2e-15:    0, 5e-15:    1, 10e-15:  2,
                  20e-15:   3, 50e-15:   4, 100e-15: 5,
                  200e-15:  6, 500e-15:  7, 1e-12:   8,
                  2e-12:    9, 5e-12:   10, 10e-12:  11,
                  20e-12:  12, 50e-12:  13, 100e-12: 14,
                  200e-12: 15, 500e-12: 16, 1e-9:    17,
                  2e-9:    18, 5e-9:    19, 10e-9:   20,
                  20e-9:   21, 50e-9:   22, 100e-9:  23,
                  200e-9:  24, 500e-9:  25, 1e-6:    26}
    _N_TO_CURR = {v: k for k, v in _CURR_TO_N.items()}

    _VOLT_ENUM = Enum(*_VOLT_TO_N.keys())
    _CURR_ENUM = Enum(*_CURR_TO_N.keys())

    _INPUT_CONFIG_TO_N = {
        'a': 0,
        'a-b': 1,
        'I 1M': 2,
        'I 100M': 3,
    }

    _N_TO_INPUT_CONFIG = {v: k for k, v in _INPUT_CONFIG_TO_N.items()}

    def __init__(self, name, address, **kwargs):
        super().__init__(name, address, **kwargs)

        # Reference and phase
        self.add_parameter('phase',
                           label='Phase',
                           get_cmd='PHAS?',
                           get_parser=float,
                           set_cmd='PHAS {:.2f}',
                           unit='deg',
                           vals=Numbers(min_value=-360, max_value=729.99))

        self.add_parameter('reference_source',
                           label='Reference source',
                           get_cmd='FMOD?',
                           set_cmd='FMOD {}',
                           val_mapping={
                               'external': 0,
                               'internal': 1,
                           },
                           vals=Enum('external', 'internal'))

        self.add_parameter('frequency',
                           label='Frequency',
                           get_cmd='FREQ?',
                           get_parser=float,
                           set_cmd='FREQ {:.4f}',
                           unit='Hz',
                           vals=Numbers(min_value=1e-3, max_value=102e3))

        self.add_parameter('ext_trigger',
                           label='External trigger',
                           get_cmd='RSLP?',
                           set_cmd='RSLP {}',
                           val_mapping={
                               'sine': 0,
                               'TTL rising': 1,
                               'TTL falling': 2,
                           })

        self.add_parameter('harmonic',
                           label='Harmonic',
                           get_cmd='HARM?',
                           get_parser=int,
                           set_cmd='HARM {:d}',
                           vals=Ints(min_value=1, max_value=19999))

        self.add_parameter('amplitude',
                           label='Amplitude',
                           get_cmd='SLVL?',
                           get_parser=float,
                           set_cmd='SLVL {:.3f}',
                           unit='V',
                           vals=Numbers(min_value=0.004, max_value=5.000))

        # Input and filter
        self.add_parameter('input_config',
                           label='Input configuration',
                           get_cmd='ISRC?',
                           get_parser=self._get_input_config,
                           set_cmd='ISRC {}',
                           set_parser=self._set_input_config,
                           vals=Enum(*self._INPUT_CONFIG_TO_N.keys()))

        self.add_parameter('input_shield',
                           label='Input shield',
                           get_cmd='IGND?',
                           set_cmd='IGND {}',
                           val_mapping={
                               'float': 0,
                               'ground': 1,
                           })

        self.add_parameter('input_coupling',
                           label='Input coupling',
                           get_cmd='ICPL?',
                           set_cmd='ICPL {}',
                           val_mapping={
                               'AC': 0,
                               'DC': 1,
                           })

        self.add_parameter('notch_filter',
                           label='Notch filter',
                           get_cmd='ILIN?',
                           set_cmd='ILIN {}',
                           val_mapping={
                               'off': 0,
                               'line in': 1,
                               '2x line in': 2,
                               'both': 3,
                           })

        # Gain and time constant
        self.add_parameter(name='sensitivity',
                           label='Sensitivity',
                           get_cmd='SENS?',
                           set_cmd='SENS {:d}',
                           get_parser=self._get_sensitivity,
                           set_parser=self._set_sensitivity
                           )

        self.add_parameter('reserve',
                           label='Reserve',
                           get_cmd='RMOD?',
                           set_cmd='RMOD {}',
                           val_mapping={
                               'high': 0,
                               'normal': 1,
                               'low noise': 2,
                           })

        self.add_parameter('time_constant',
                           label='Time constant',
                           get_cmd='OFLT?',
                           set_cmd='OFLT {}',
                           unit='s',
                           val_mapping={
                               10e-6:  0, 30e-6:  1,
                               100e-6: 2, 300e-6: 3,
                               1e-3:   4, 3e-3:   5,
                               10e-3:  6, 30e-3:  7,
                               100e-3: 8, 300e-3: 9,
                               1:     10, 3:     11,
                               10:    12, 30:    13,
                               100:   14, 300:   15,
                               1e3:   16, 3e3:   17,
                               10e3:  18, 30e3:  19,
                           })

        self.add_parameter('filter_slope',
                           label='Filter slope',
                           get_cmd='OFSL?',
                           set_cmd='OFSL {}',
                           unit='dB/oct',
                           val_mapping={
                               6: 0,
                               12: 1,
                               18: 2,
                               24: 3,
                           })

        self.add_parameter('sync_filter',
                           label='Sync filter',
                           get_cmd='SYNC?',
                           set_cmd='SYNC {}',
                           val_mapping={
                               'off': 0,
                               'on': 1,
                           })

        def parse_offset_get(s):
            parts = s.split(',')

            return float(parts[0]), int(parts[1])

        # TODO: Parameters that can be set with multiple arguments
        # For the OEXP command for example two arguments are needed
        self.add_parameter('X_offset',
                           get_cmd='OEXP? 1',
                           get_parser=parse_offset_get)

        self.add_parameter('Y_offset',
                           get_cmd='OEXP? 2',
                           get_parser=parse_offset_get)

        self.add_parameter('R_offset',
                           get_cmd='OEXP? 3',
                           get_parser=parse_offset_get)

        # Aux input/output
        for i in [1, 2, 3, 4]:
            self.add_parameter('aux_in{}'.format(i),
                               label='Aux input {}'.format(i),
                               get_cmd='OAUX? {}'.format(i),
                               get_parser=float,
                               unit='V')

            self.add_parameter('aux_out{}'.format(i),
                               label='Aux output {}'.format(i),
                               get_cmd='AUXV? {}'.format(i),
                               get_parser=float,
                               set_cmd='AUXV {0}, {{}}'.format(i),
                               unit='V')

        # Setup
        self.add_parameter('output_interface',
                           label='Output interface',
                           get_cmd='OUTX?',
                           set_cmd='OUTX {}',
                           val_mapping={
                               'RS232': '0\n',
                               'GPIB': '1\n',
                           })

        # Channel setup
        for ch in range(1, 3):

            # detailed validation and mapping performed in set/get functions
            self.add_parameter('ch{}_ratio'.format(ch),
                               label='Channel {} ratio'.format(ch),
                               get_cmd=partial(self._get_ch_ratio, ch),
                               set_cmd=partial(self._set_ch_ratio, ch),
                               vals=Strings())
            self.add_parameter('ch{}_display'.format(ch),
                               label='Channel {} display'.format(ch),
                               get_cmd=partial(self._get_ch_display, ch),
                               set_cmd=partial(self._set_ch_display, ch),
                               vals=Strings())
            self.add_parameter('ch{}_databuffer'.format(ch),
                               channel=ch,
                               parameter_class=ChannelBuffer)

        # Data transfer
        self.add_parameter('X',
                           get_cmd='OUTP? 1',
                           get_parser=float,
                           unit='V')

        self.add_parameter('Y',
                           get_cmd='OUTP? 2',
                           get_parser=float,
                           unit='V')

        self.add_parameter('R',
                           get_cmd='OUTP? 3',
                           get_parser=float,
                           unit='V')

        self.add_parameter('P',
                           get_cmd='OUTP? 4',
                           get_parser=float,
                           unit='deg')

        # Data buffer settings
        self.add_parameter('buffer_SR',
                           label='Buffer sample rate',
                           get_cmd='SRAT ?',
                           set_cmd=self._set_buffer_SR,
                           unit='Hz',
                           val_mapping={62.5e-3: 0,
                                        0.125: 1,
                                        0.250: 2,
                                        0.5: 3,
                                        1: 4, 2: 5,
                                        4: 6, 8: 7,
                                        16: 8, 32: 9,
                                        64: 10, 128: 11,
                                        256: 12, 512: 13,
                                        'Trigger': 14},
                           get_parser=int
                           )

        self.add_parameter('buffer_acq_mode',
                           label='Buffer acquistion mode',
                           get_cmd='SEND ?',
                           set_cmd='SEND {}',
                           val_mapping={'single shot': 0,
                                        'loop': 1},
                           get_parser=int)

        self.add_parameter('buffer_trig_mode',
                           label='Buffer trigger start mode',
                           get_cmd='TSTR ?',
                           set_cmd='TSTR {}',
                           val_mapping={'ON': 1, 'OFF': 0},
                           get_parser=int)

        self.add_parameter('buffer_npts',
                           label='Buffer number of stored points',
                           get_cmd='SPTS ?',
                           get_parser=int)

        # Auto functions
        self.add_function('auto_gain', call_cmd='AGAN')
        self.add_function('auto_reserve', call_cmd='ARSV')
        self.add_function('auto_phase', call_cmd='APHS')
        self.add_function('auto_offset', call_cmd='AOFF {0}',
                          args=[Enum(1, 2, 3)])

        # Interface
        self.add_function('reset', call_cmd='*RST')

        self.add_function('disable_front_panel', call_cmd='OVRM 0')
        self.add_function('enable_front_panel', call_cmd='OVRM 1')

        self.add_function('send_trigger', call_cmd='TRIG',
                          docstring=("Send a software trigger. "
                                     "This command has the same effect as a "
                                     "trigger at the rear panel trigger"
                                     " input."))

        self.add_function('buffer_start', call_cmd='STRT',
                          docstring=("The buffer_start command starts or "
                                     "resumes data storage. buffer_start"
                                     " is ignored if storage is already in"
                                     " progress."))

        self.add_function('buffer_pause', call_cmd='PAUS',
                          docstring=("The buffer_pause command pauses data "
                                     "storage. If storage is already paused "
                                     "or reset then this command is ignored."))

        self.add_function('buffer_reset', call_cmd='REST',
                          docstring=("The buffer_reset command resets the data"
                                     " buffers. The buffer_reset command can "
                                     "be sent at any time - any storage in "
                                     "progress, paused or not, will be reset."
                                     " This command will erase the data "
                                     "buffer."))

        # Initialize the proper units of the outputs and sensitivities
        self.input_config()

        # start keeping track of buffer setpoints
        self._buffer1_ready = False
        self._buffer2_ready = False

        self.connect_message()

    def _set_buffer_SR(self, SR):
        self.write('SRAT {}'.format(SR))
        self._buffer1_ready = False
        self._buffer2_ready = False

    def _get_ch_ratio(self, channel):
        val_mapping = {1: {0: 'none',
                           1: 'Aux In 1',
                           2: 'Aux In 2'},
                       2: {0: 'none',
                           1: 'Aux In 3',
                           2: 'Aux In 4'}}
        resp = int(self.ask('DDEF ? {}'.format(channel)).split(',')[1])

        return val_mapping[channel][resp]

    def _set_ch_ratio(self, channel, ratio):
        val_mapping = {1: {'none': 0,
                           'Aux In 1': 1,
                           'Aux In 2': 2},
                       2: {'none': 0,
                           'Aux In 3': 1,
                           'Aux In 4': 2}}
        vals = val_mapping[channel].keys()
        if ratio not in vals:
            raise ValueError('{} not in {}'.format(ratio, vals))
        ratio = val_mapping[channel][ratio]
        disp_val = int(self.ask('DDEF ? {}'.format(channel)).split(',')[0])
        self.write('DDEF {}, {}, {}'.format(channel, disp_val, ratio))
        self._buffer_ready = False

    def _get_ch_display(self, channel):
        val_mapping = {1: {0: 'X',
                           1: 'R',
                           2: 'X Noise',
                           3: 'Aux In 1',
                           4: 'Aux In 2'},
                       2: {0: 'Y',
                           1: 'Phase',
                           2: 'Y Noise',
                           3: 'Aux In 3',
                           4: 'Aux In 4'}}
        resp = int(self.ask('DDEF ? {}'.format(channel)).split(',')[0])

        return val_mapping[channel][resp]

    def _set_ch_display(self, channel, disp):
        val_mapping = {1: {'X': 0,
                           'R': 1,
                           'X Noise': 2,
                           'Aux In 1': 3,
                           'Aux In 2': 4},
                       2: {'Y': 0,
                           'Phase': 1,
                           'Y Noise': 2,
                           'Aux In 3': 3,
                           'Aux In 4': 4}}
        vals = val_mapping[channel].keys()
        if disp not in vals:
            raise ValueError('{} not in {}'.format(disp, vals))
        disp = val_mapping[channel][disp]
        # Since ratio AND display are set simultaneously,
        # we get and then re-set the current ratio value
        ratio_val = int(self.ask('DDEF ? {}'.format(channel)).split(',')[1])
        self.write('DDEF {}, {}, {}'.format(channel, disp, ratio_val))
        self._buffer_ready = False

    def _set_units(self, unit):
        # TODO:
        # make a public parameter function that allows to change the units
        for param in [self.X, self.Y, self.R, self.sensitivity]:
            param.unit = unit

    def _get_input_config(self, s):
        mode = self._N_TO_INPUT_CONFIG[int(s)]

        if mode in ['a', 'a-b']:
            self.sensitivity.set_validator(self._VOLT_ENUM)
            self._set_units('V')
        else:
            self.sensitivity.set_validator(self._CURR_ENUM)
            self._set_units('A')

        return mode

    def _set_input_config(self, s):
        if s in ['a', 'a-b']:
            self.sensitivity.set_validator(self._VOLT_ENUM)
            self._set_units('V')
        else:
            self.sensitivity.set_validator(self._CURR_ENUM)
            self._set_units('A')

        return self._INPUT_CONFIG_TO_N[s]

    def _get_sensitivity(self, s):
        if self.input_config() in ['a', 'a-b']:
            return self._N_TO_VOLT[int(s)]
        else:
            return self._N_TO_CURR[int(s)]

    def _set_sensitivity(self, s):
        if self.input_config() in ['a', 'a-b']:
            return self._VOLT_TO_N[s]
        else:
            return self._CURR_TO_N[s]
Exemple #24
0
    def __init__(self, name, address=None, **kwargs):

        super().__init__(name, **kwargs)

        self.add_parameter(name='frequency',
                           label='Frequency',
                           unit='Hz',
                           get_cmd=None,
                           set_cmd=None,
                           get_parser=float,
                           set_parser=float,
                           vals=Numbers(min_value=1e-6,
                                        max_value=80e6),
                           docstring=('Command for setting the pulse frequency. Min value: 1 uHz, Max value: 80 MHz'))
        self.add_parameter(name='pulse_shape',
                           label='Pulse shape',
                           get_cmd=None,
                           set_cmd=None,
                           vals=Enum('SIN','SQU'),
                           docstring=('Command for setting the desired pulse shape. Currently supported: SIN, SQU.'))
        self.add_parameter(name='pulse_width',
                           label='Pulse width',
                           get_cmd=None,
                           set_cmd=None,
                           get_parser=float,
                           set_parser=float,
                           unit='s',
                           vals=Numbers(min_value=8e-9, max_value=2e3),
                           docstring=('Command for setting the desired pulse width. Min value: 8 ns, Max value: 2000 s.'))
        self.add_parameter('pulse_period',
                           label='Pulse period',
                           get_cmd=None,
                           set_cmd=None,
                           get_parser=float,
                           set_parser=float,
                           unit='s',
                           vals=Numbers(min_value=20e-9, max_value=2e3),
                           docstring=('Command for setting the desired pulse period. Min value: 20 ns, Max value: 2000 s.'))
        self.add_parameter(name='amplitude',
                           label='Amplitude',
                           unit='Vpp',
                           get_cmd=None,
                           set_cmd=None,
                           get_parser=float,
                           set_parser=float,
                           vals=Numbers(min_value=1e-3, max_value=20),
                           docstring=('Command for setting the desired pulse amplitude. Min value for 50 Ohm load: 1 mVpp, Max value for 50 Ohm load: 10 Vpp. Min value for high impedance load: 2 mVpp, Max value for high impedance load: 20 Vpp.'))
        self.add_parameter('offset',
                           label='Offset',
                           unit='V',
                           get_cmd=None,
                           set_cmd=None,
                           get_parser=float,
                           set_parser=float,
                           vals=Numbers(min_value=-10, max_value=10),
                           docstring=('Command for setting the desired dc offset. Min value for 50 Ohm load: -10 V, Max value for 50 Ohm load: 10 V. Min value for high impedance load: -10 V, Max value for high impedance load: 10 Vpp.'))
        self.add_parameter(name='output',
                           get_cmd=None,
                           set_cmd=None,
                           val_mapping={'OFF': 0,
                                        'ON': 1},
                           docstring=('Command for switching on/off the device output.'))
        self.add_parameter(name='output_sync',
                           get_cmd=None,
                           set_cmd=None,
                           val_mapping={'OFF': 0,
                                        'ON': 1},
                           docstring='Command for switching on/off the device output synchronization.')
        self.add_parameter(name='load_impedance',
						   label='Load impedance',
						   unit='Ohm',
                           get_cmd=None,
                           set_cmd=None,	
                           get_parser=float,
                           set_parser=float,
                           vals=MultiType(Numbers(min_value=1, max_value=10e3), Enum('INF')),
                           docstring=("Command for setting the load impedance in Ohms. Min value: 1 Ohm, Max value: 10 kOhm or 'INF'"))						   
        
        self.connect_message()
Exemple #25
0
    def __init__(self, name: str, address: str, **kwargs: Any) -> None:
        super().__init__(name, address, terminator='\n', **kwargs)

        idn = self.IDN.get()
        self.model = idn['model']

        NPLC_list = {
            '34401A': [0.02, 0.2, 1, 10, 100],
            '34410A': [0.006, 0.02, 0.06, 0.2, 1, 2, 10, 100],
            '34411A': [0.001, 0.002, 0.006, 0.02, 0.06, 0.2, 1, 2, 10, 100]
        }[self.model]

        self._resolution_factor = {
            '34401A': [1e-4, 1e-5, 3e-6, 1e-6, 3e-7],
            '34410A': [6e-06, 3e-06, 1.5e-06, 7e-07, 3e-07, 2e-07, 1e-07],
            '34411A': [
                3e-05, 1.5e-05, 6e-06, 3e-06, 1.5e-06, 7e-07, 3e-07, 2e-07,
                1e-07, 3e-08
            ]
        }[self.model]

        self.add_parameter('resolution',
                           get_cmd='VOLT:DC:RES?',
                           get_parser=float,
                           set_cmd=self._set_resolution,
                           label='Resolution',
                           unit='V')

        self.add_parameter('volt',
                           get_cmd='READ?',
                           label='Voltage',
                           get_parser=float,
                           unit='V')

        self.add_parameter('fetch',
                           get_cmd='FETCH?',
                           label='Voltage',
                           get_parser=float,
                           unit='V',
                           snapshot_get=False,
                           docstring=('Reads the data you asked for, i.e. '
                                      'after an `init_measurement()` you can '
                                      'read the data with fetch.\n'
                                      'Do not call this when you did not ask '
                                      'for data in the first place!'))

        self.add_parameter('NPLC',
                           get_cmd='VOLT:NPLC?',
                           get_parser=float,
                           set_cmd=self._set_nplc,
                           vals=Enum(*NPLC_list),
                           label='Integration time',
                           unit='NPLC')

        self.add_parameter('terminals', get_cmd='ROUT:TERM?')

        self.add_parameter('range_auto',
                           get_cmd='VOLT:RANG:AUTO?',
                           set_cmd='VOLT:RANG:AUTO {:d}',
                           val_mapping={
                               'on': 1,
                               'off': 0
                           })

        self.add_parameter('range',
                           get_cmd='SENS:VOLT:DC:RANG?',
                           get_parser=float,
                           set_cmd='SENS:VOLT:DC:RANG {:f}',
                           vals=Enum(0.1, 1.0, 10.0, 100.0, 1000.0))

        if self.model in ['34401A']:
            self.add_parameter('display_text',
                               get_cmd='DISP:TEXT?',
                               set_cmd='DISP:TEXT "{}"',
                               vals=Strings())

        elif self.model in ['34410A', '34411A']:
            self.add_parameter('display_text',
                               get_cmd='DISP:WIND1:TEXT?',
                               set_cmd='DISP:WIND1:TEXT "{}"',
                               vals=Strings())

            self.add_parameter('display_text_2',
                               get_cmd='DISP:WIND2:TEXT?',
                               set_cmd='DISP:WIND2:TEXT "{}"',
                               vals=Strings())

        self.connect_message()
    def __init__(self,
                 name: str,
                 address: Optional[str] = None,
                 port: Optional[int] = None,
                 terminator: str = '\r\n',
                 tmpfile: Optional[str] = None,
                 timeout: float = 20,
                 pid=None,
                 condense_tlim=1.2,
                 tlim_safety=True,
                 **kwargs: Any):
        super().__init__(name,
                         address=address,
                         port=port,
                         terminator=terminator,
                         timeout=timeout,
                         **kwargs)

        self._heater_range_auto = False
        self._heater_range_temp = [0.0, 0.015, 0.025, 0.07, 0.2, 1.5, 40., 300]
        self._heater_range_curr = [0.0, 0.316, 1, 3.16, 10., 31.6, 100., 100.]
        self._heaterdict = dict(
            zip(self._heater_range_temp, self._heater_range_curr))
        #self._control_channel = 5

        self.add_parameter(name='turbo_status',
                           label='turbo_status',
                           get_cmd=partial(self._get_turbo_status),
                           set_cmd=partial(self._set_turbo_status),
                           val_mapping={
                               'on': 'ON',
                               'off': 'OFF'
                           })

        self.add_parameter(name='turbo_speed',
                           label='turbo_speed',
                           unit='Hz',
                           get_cmd=partial(self._get_turbo_speed))

        self.add_parameter(name='autotemperature',
                           label='autotemperature',
                           unit='K',
                           get_cmd=partial(self._get_autotempcontrol),
                           set_cmd=partial(self._set_autotempcontrol))

        self.add_parameter(name='time',
                           label='System Time',
                           get_cmd='READ:SYS:TIME',
                           get_parser=self._parse_time)

        self.add_parameter(name='action',
                           label='Current action',
                           get_cmd='READ:SYS:DR:ACTN',
                           get_parser=self._parse_action)

        self.add_parameter(name='status',
                           label='Status',
                           get_cmd='READ:SYS:DR:STATUS',
                           get_parser=self._parse_status)

        self.add_parameter(name='pid_control_channel',
                           label='PID control channel',
                           get_cmd=self._get_control_channel,
                           set_cmd=self._set_control_channel,
                           vals=Ints(1, 16))

        self.add_parameter(name='pid_mode',
                           label='PID Mode',
                           get_cmd=partial(self._get_control_param, 'MODE'),
                           set_cmd=partial(self._set_control_param, 'MODE'),
                           val_mapping={
                               'on': 'ON',
                               'off': 'OFF'
                           })

        self.add_parameter(name='pid_ramp',
                           label='PID ramp enabled',
                           get_cmd=partial(self._get_control_param,
                                           'RAMP:ENAB'),
                           set_cmd=partial(self._set_control_param,
                                           'RAMP:ENAB'),
                           val_mapping={
                               'on': 'ON',
                               'off': 'OFF'
                           })

        self.add_parameter(name='pid_setpoint',
                           label='PID temperature setpoint',
                           unit='K',
                           get_cmd=partial(self._get_control_param, 'TSET'),
                           set_cmd=partial(self._set_control_param, 'TSET'),
                           snapshot_exclude=True)

        self.add_parameter(name='pid_rate',
                           label='PID ramp rate',
                           unit='K/min',
                           get_cmd=partial(self._get_control_param,
                                           'RAMP:RATE'),
                           set_cmd=partial(self._set_control_param,
                                           'RAMP:RATE'),
                           snapshot_exclude=True)

        self.add_parameter(
            name='pid_range',
            label='PID heater range',
            # TODO: The units in the software are mA, how to
            # do this correctly?
            unit='mA',
            get_cmd=partial(self._get_control_param, 'RANGE'),
            set_cmd=partial(self._set_control_param, 'RANGE'),
            vals=Enum(*self._heater_range_curr),
            snapshot_exclude=True)

        self.add_parameter(name='magnet_status',
                           label='Magnet status',
                           unit='',
                           get_cmd=partial(self._get_control_B_param, 'ACTN'))

        self.add_parameter(
            name='magnet_sweeprate',
            label='Magnet sweep rate',
            unit='T/min',
            get_cmd=partial(self._get_control_B_param, 'RVST:RATE'),
            set_cmd=partial(self._set_control_magnet_sweeprate_param))

        self.add_parameter(name='magnet_sweeprate_insta',
                           label='Instantaneous magnet sweep rate',
                           unit='T/min',
                           get_cmd=partial(self._get_control_B_param, 'RFST'))

        self.add_parameter(name='B',
                           label='Magnetic field',
                           unit='T',
                           get_cmd=partial(self._get_control_B_param, 'VECT'))

        self.add_parameter(name='Bx',
                           label='Magnetic field x-component',
                           unit='T',
                           get_cmd=partial(self._get_control_Bcomp_param,
                                           'VECTBx'),
                           set_cmd=partial(self._set_control_Bx_param))

        self.add_parameter(name='By',
                           label='Magnetic field y-component',
                           unit='T',
                           get_cmd=partial(self._get_control_Bcomp_param,
                                           'VECTBy'),
                           set_cmd=partial(self._set_control_By_param))

        self.add_parameter(name='Bz',
                           label='Magnetic field z-component',
                           unit='T',
                           get_cmd=partial(self._get_control_Bcomp_param,
                                           'VECTBz'),
                           set_cmd=partial(self._set_control_Bz_param))

        self.add_parameter(name='magnet_sweep_time',
                           label='Magnet sweep time',
                           unit='T/min',
                           get_cmd=partial(self._get_control_B_param,
                                           'RVST:TIME'))

        self.chan_alias: Dict[str, str] = {}
        self.chan_temp_names: Dict[str, Dict[str, Optional[str]]] = {}
        if tmpfile is not None:
            self._get_temp_channel_names(tmpfile)
        self._get_temp_channels()
        self._get_pressure_channels()
        self._get_valve_channels()
        self._control_channel = None
        self._control_channel = self._get_control_channel()
        self._get_pid_channels()
        if pid is not None:
            self.pid_P.set(pid[0])
            self.pid_I.set(pid[1])
            self.pid_D.set(pid[2])
        try:
            self._get_named_channels()
        except:
            logging.warning('Ignored an error in _get_named_channels\n' +
                            format_exc())

        self.condense_tlim = condense_tlim
        self.tlim_safety = tlim_safety
        self.connect_message()
    def __init__(self, name: str, address: str, terminator='\n', **kwargs: Any):
        """
        Create an instance of the instrument.

        Args:
            name: Name of the instrument instance
            address: Visa-resolvable instrument address
        """
        super().__init__(name, address, terminator=terminator, **kwargs)

        self.add_parameter(
            "sense_function",
            set_cmd=":SENSe:FUNCtion {}",
            get_cmd=":SENSe:FUNCtion?",
            val_mapping={
                key: value["name"]
                for key, value in Sense7510.function_modes.items()
            },
            docstring="Add sense functions listed in the function modes."
        )

        self.add_parameter(
            "digi_sense_function",
            set_cmd=":DIGitize:FUNCtion {}",
            get_cmd=":DIGitize:FUNCtion?",
            val_mapping={
                key: value["name"]
                for key, value in DigitizeSense7510.function_modes.items()
            },
            docstring="Make readings using the active digitize function."
        )

        self.add_parameter(
            "buffer_name",
            get_cmd=None,
            set_cmd=None,
            docstring="Name of the reading buffer in use."
        )

        self.add_parameter(
            "trigger_block_list",
            get_cmd=":TRIGger:BLOCk:LIST?",
            docstring="Return the settings for all trigger model blocks."
        )

        self.add_parameter(
            "trigger_in_ext_clear",
            set_cmd=":TRIGger:EXTernal:IN:CLEar",
            docstring="Clear the trigger event on the external in line."
        )

        self.add_parameter(
            "trigger_in_ext_edge",
            get_cmd=":TRIGger:EXTernal:IN:EDGE?",
            set_cmd=":TRIGger:EXTernal:IN:EDGE {}",
            vals=Enum("FALL", "RIS", "falling", "rising", "EITH", "either"),
            docstring="Type of edge that is detected as an input on the "
                      "external trigger in line"
        )

        self.add_parameter(
            "overrun_status",
            get_cmd=":TRIGger:EXTernal:IN:OVERrun?",
            docstring="Return the event detector overrun status."
        )

        self.add_parameter(
            "digitize_trigger",
            get_cmd=":TRIGger:DIGitize:STIMulus?",
            set_cmd=":TRIGger:DIGitize:STIMulus {}",
            vals=Enum("EXT", "external", "NONE"),
            docstring="Set the instrument to digitize a measurement the next "
                      "time it detects the specified trigger event."
        )

        self.add_parameter(
            "system_errors",
            get_cmd=":SYSTem:ERRor?",
            docstring="Return the oldest unread error message from the event "
                      "log and removes it from the log."
        )

        for proper_sense_function in Sense7510.function_modes:
            self.add_submodule(
                f"_sense_{proper_sense_function}",
                Sense7510(self, "sense", proper_sense_function)
            )

        for proper_sense_function in DigitizeSense7510.function_modes:
            self.add_submodule(
                f"_digi_sense_{proper_sense_function}",
                DigitizeSense7510(self, "digi_sense", proper_sense_function)
            )

        self.buffer_name('defbuffer1')
        self.buffer(name=self.buffer_name())
        self.connect_message()
Exemple #28
0
    def __init__(self, name, address=None, port=7020, axes=None, **kwargs):
        super().__init__(name,
                         address=address,
                         port=port,
                         terminator='\n',
                         **kwargs)
        self.axes = axes
        self._ATOB = []
        self._latest_response = ''
        # for some reason the first call is always invalid?!
        # need some kind of init?
        self.ask('*IDN?')

        if axes is None:
            self._determine_magnet_axes()
        self._determine_current_to_field()

        self.add_parameter(
            'hold_after_set',
            get_cmd=None,
            set_cmd=None,
            vals=Bool(),
            initial_value=True,
            docstring=
            'Should the driver block while waiting for the Magnet power supply '
            'to go into hold mode.')

        self.add_parameter('setpoint',
                           names=tuple('B' + ax.lower() + '_setpoint'
                                       for ax in self.axes),
                           units=tuple('T' for ax in self.axes),
                           get_cmd=partial(self._get_fld, self.axes, 'FSET'),
                           set_cmd=partial(self._ramp_to_setpoint, self.axes,
                                           'FSET'),
                           parameter_class=MercuryiPSArray)

        self.add_parameter('rate',
                           names=tuple('rate_B' + ax.lower()
                                       for ax in self.axes),
                           units=tuple('T/m' for ax in self.axes),
                           get_cmd=partial(self._get_fld, self.axes, 'RFST'),
                           set_cmd=partial(self._ramp_to_setpoint, self.axes,
                                           'RFST'),
                           parameter_class=MercuryiPSArray)

        self.add_parameter('fld',
                           names=tuple('B' + ax.lower() for ax in self.axes),
                           units=tuple('T' for ax in self.axes),
                           get_cmd=partial(self._get_fld, self.axes, 'FLD'),
                           set_cmd=partial(self._ramp_to_setpoint, self.axes,
                                           'FSET'),
                           parameter_class=MercuryiPSArray)

        self.add_parameter('fldC',
                           names=['B' + ax.lower() for ax in self.axes],
                           units=['T' for ax in self.axes],
                           get_cmd=partial(self._get_fld, self.axes, 'CURR'),
                           set_cmd=partial(self._ramp_to_setpoint, self.axes,
                                           'CSET'),
                           parameter_class=MercuryiPSArray)

        self.add_parameter('rtp',
                           names=['radius', 'theta', 'phi'],
                           units=['|B|', 'rad', 'rad'],
                           get_cmd=partial(self._get_rtp, self.axes, 'FLD'),
                           set_cmd=partial(self._set_rtp, self.axes, 'FSET'),
                           parameter_class=MercuryiPSArray)

        self.add_parameter('rtpC',
                           names=['radius', 'theta', 'phi'],
                           units=['|B|', 'rad', 'rad'],
                           get_cmd=partial(self._get_rtp, self.axes, 'CURR'),
                           set_cmd=partial(self._set_rtp, self.axes, 'CSET'),
                           parameter_class=MercuryiPSArray)

        # so we have radius, theta and phi in buffer
        self.rtp.get()

        self.add_parameter('radius',
                           get_cmd=self._get_r,
                           set_cmd=self._set_r,
                           unit='|B|')
        self.add_parameter('theta',
                           get_cmd=self._get_theta,
                           set_cmd=self._set_theta,
                           unit='rad')
        self.add_parameter('phi',
                           get_cmd=self._get_phi,
                           set_cmd=self._set_phi,
                           unit='rad')

        for ax in self.axes:
            self.add_parameter(ax.lower() + '_fld',
                               get_cmd=partial(self._get_fld, ax, 'FLD'),
                               set_cmd=partial(self._ramp_to_setpoint, ax,
                                               'FSET'),
                               label='B' + ax.lower(),
                               unit='T')
            self.add_parameter(ax.lower() + '_fldC',
                               get_cmd=partial(self._get_fld, ax, 'CURR'),
                               set_cmd=partial(self._ramp_to_setpoint, ax,
                                               'CSET'),
                               label='B' + ax.lower(),
                               unit='T')
            self.add_parameter(ax.lower() + '_fld_wait',
                               get_cmd=partial(self._get_fld, ax, 'CURR'),
                               set_cmd=partial(self._ramp_to_setpoint_and_wait,
                                               ax, 'CSET'),
                               label='B' + ax.lower(),
                               unit='T')
            self.add_parameter(ax.lower() + '_ACTN',
                               get_cmd=partial(
                                   self._get_cmd,
                                   'READ:DEV:GRP' + ax + ':PSU:ACTN?'),
                               set_cmd='SET:DEV:GRP' + ax + ':PSU:ACTN:{}',
                               vals=Enum('HOLD', 'RTOS', 'RTOZ', 'CLMP'))
            self.add_parameter(ax.lower() + '_setpoint',
                               get_cmd=partial(self._get_fld, ax, 'FSET'),
                               set_cmd=partial(self._set_fld, ax, 'FSET'),
                               unit='T')
            self.add_parameter(ax.lower() + '_setpointC',
                               get_cmd=partial(self._get_fld, ax, 'CSET'),
                               set_cmd=partial(self._set_fld, ax, 'CSET'),
                               unit='T')
            self.add_parameter(ax.lower() + '_rate',
                               get_cmd=partial(self._get_fld, ax, 'RFST'),
                               set_cmd=partial(self._set_fld, ax, 'RFST'),
                               unit='T/m')
            self.add_parameter(ax.lower() + '_rateC',
                               get_cmd=partial(self._get_fld, ax, 'RCST'),
                               set_cmd=partial(self._set_fld, ax, 'RCST'),
                               unit='T/m')

            self.connect_message()
Exemple #29
0
    def __init__(self, parent: VisaInstrument, name: str,
                 proper_function: str) -> None:

        super().__init__(parent, name)

        self._proper_function = proper_function
        range_vals = self.function_modes[self._proper_function]["range_vals"]
        unit = self.function_modes[self._proper_function]["unit"]

        self.function = self.parent.sense_function

        self.add_parameter(
            self._proper_function,
            get_cmd=self._measure,
            get_parser=float,
            unit=unit,
            docstring="Make measurements, place them in a reading buffer, and "
            "return the last reading.")

        self.add_parameter(
            "auto_range",
            get_cmd=f":SENSe:{self._proper_function}:RANGe:AUTO?",
            set_cmd=f":SENSe:{self._proper_function}:RANGe:AUTO {{}}",
            val_mapping=create_on_off_val_mapping(on_val="1", off_val="0"),
            docstring="Determine if the measurement range is set manually or "
            "automatically for the selected measure function.")

        self.add_parameter(
            "range",
            get_cmd=f":SENSe:{self._proper_function}:RANGe?",
            set_cmd=f":SENSe:{self._proper_function}:RANGe {{}}",
            vals=range_vals,
            get_parser=float,
            unit=unit,
            docstring="Determine the positive full-scale measure range.")

        self.add_parameter(
            "nplc",
            get_cmd=f":SENSe:{self._proper_function}:NPLCycles?",
            set_cmd=f":SENSe:{self._proper_function}:NPLCycles {{}}",
            vals=Numbers(0.01, 10),
            get_parser=float,
            docstring="Set the time that the input signal is measured for the "
            "selected function.(NPLC = number of power line cycles)")

        self.add_parameter(
            "auto_delay",
            get_cmd=f":SENSe:{self._proper_function}:DELay:AUTO?",
            set_cmd=f":SENSe:{self._proper_function}:DELay:AUTO {{}}",
            val_mapping=create_on_off_val_mapping(on_val="ON", off_val="OFF"),
            docstring="Enable or disable the automatic delay that occurs "
            "before each measurement.")

        self.add_parameter(
            'user_number',
            get_cmd=None,
            set_cmd=None,
            vals=Ints(1, 5),
            docstring="Set the user number for user-defined delay.")

        self.add_parameter(
            "user_delay",
            get_cmd=self._get_user_delay,
            set_cmd=self._set_user_delay,
            vals=Numbers(0, 1e4),
            unit='second',
            docstring="Set a user-defined delay that you can use in the "
            "trigger model.")

        self.add_parameter(
            "auto_zero",
            get_cmd=f":SENSe:{self._proper_function}:AZERo?",
            set_cmd=f":SENSe:{self._proper_function}:AZERo {{}}",
            val_mapping=create_on_off_val_mapping(on_val="1", off_val="0"),
            docstring="Enable or disable automatic updates to the internal "
            "reference measurements (autozero) of the instrument.")

        self.add_parameter(
            "auto_zero_once",
            set_cmd=f":SENSe:AZERo:ONCE",
            docstring="Cause the instrument to refresh the reference and "
            "zero measurements once")

        self.add_parameter(
            "average",
            get_cmd=f":SENSe:{self._proper_function}:AVERage?",
            set_cmd=f":SENSe:{self._proper_function}:AVERage {{}}",
            val_mapping=create_on_off_val_mapping(on_val="1", off_val="0"),
            docstring="Enable or disable the averaging filter for measurements "
            "of the selected function.")

        self.add_parameter(
            "average_count",
            get_cmd=f":SENSe:{self._proper_function}:AVERage:COUNt?",
            set_cmd=f":SENSe:{self._proper_function}:AVERage:COUNt {{}}",
            vals=Numbers(1, 100),
            docstring="Set the number of measurements that are averaged when "
            "filtering is enabled.")

        self.add_parameter(
            "average_type",
            get_cmd=f":SENSe:{self._proper_function}:AVERage:TCONtrol?",
            set_cmd=f":SENSe:{self._proper_function}:AVERage:TCONtrol {{}}",
            vals=Enum('REP', 'rep', 'MOV', 'mov'),
            docstring="Set the type of averaging filter that is used for the "
            "selected measure function when the measurement filter "
            "is enabled.")
    def __init__(self,
                 name,
                 spi_rack,
                 module,
                 inter_delay=0.1,
                 dac_step=10e-3,
                 reset_voltages=False,
                 mV=False,
                 number_dacs=16,
                 **kwargs):
        """ Create instrument for the D5a module.

        The D5a module works with volts as units. For backward compatibility
        there is the option to allow mV for the dacX parameters.

        The output span of the DAC module can be changed with the spanX
        command. Be carefull when executing this command with a sample
        connected as voltage jumps can occur.

        Args:
            name (str): name of the instrument.

            spi_rack (SPI_rack): instance of the SPI_rack class as defined in
                the spirack package. This class manages communication with the
                individual modules.

            module (int): module number as set on the hardware.
            inter_delay (float): time in seconds, passed to dac parameters of the object
            dac_step (float): max step size (V or mV), passed to dac parameters of the object
            reset_voltages (bool): passed to D5a_module constructor
            mV (bool): if True, then use mV as units in the dac parameters
            number_dacs (int): number of DACs available. This is 8 for the D5mux
        """
        super().__init__(name, **kwargs)

        self.d5a = D5a_module(spi_rack, module, reset_voltages=reset_voltages)
        self._mV = mV
        self._number_dacs = number_dacs

        self._span_set_map = {
            '4v uni': 0,
            '4v bi': 2,
            '2v bi': 4,
        }

        self._span_get_map = {v: k for k, v in self._span_set_map.items()}

        self.add_function('set_dacs_zero', call_cmd=self._set_dacs_zero)

        if self._mV:
            self._gain = 1e3
            unit = 'mV'
        else:
            self._gain = 1
            unit = 'V'

        for i in range(self._number_dacs):
            validator = self._get_validator(i)

            self.add_parameter('dac{}'.format(i + 1),
                               label='DAC {}'.format(i + 1),
                               get_cmd=partial(self._get_dac, i),
                               set_cmd=partial(self._set_dac, i),
                               unit=unit,
                               vals=validator,
                               step=dac_step,
                               inter_delay=inter_delay)

            self.add_parameter('stepsize{}'.format(i + 1),
                               get_cmd=partial(self.d5a.get_stepsize, i),
                               unit='V')

            self.add_parameter(
                'span{}'.format(i + 1),
                get_cmd=partial(self._get_span, i),
                set_cmd=partial(self._set_span, i),
                vals=Enum(*self._span_set_map.keys()),
                docstring=
                'Change the output span of the DAC. This command also updates the validator.'
            )