Example #1
0
def test_convert_legacy_version_to_supported_version():
    legacy_verstr = "a.1.4"
    assert ii.convert_legacy_version_to_supported_version(legacy_verstr) == "65.1.4"

    legacy_verstr = "10.4.7"
    assert ii.convert_legacy_version_to_supported_version(legacy_verstr) == "10.4.7"

    legacy_verstr = "C.2.1"
    assert ii.convert_legacy_version_to_supported_version(legacy_verstr) == "67.2.1"
Example #2
0
    def __init__(self,
                 name: str,
                 address: str,
                 terminator: str = '\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)

        idn = self.IDN.get()

        self.has_firmware_a_02_10_or_above = version.parse(
            convert_legacy_version_to_supported_version(
                idn["firmware"])) >= version.parse(
                    convert_legacy_version_to_supported_version("A.02.10"))

        self.has_option_001 = '001' in self._options()
        self._dc_bias_v_level_range: Union[Numbers, Enum]
        if self.has_option_001:
            self._v_level_range = Numbers(0, 20)
            self._i_level_range = Numbers(0, 0.1)
            self._imp_range = Enum(0.1, 1, 10, 100, 300, 1000, 3000, 10000,
                                   30000, 100000)
            self._dc_bias_v_level_range = Numbers(-40, 40)
        else:
            self._v_level_range = Numbers(0, 2)
            self._i_level_range = Numbers(0, 0.02)
            self._imp_range = Enum(1, 10, 100, 300, 1000, 3000, 10000, 30000,
                                   100000)
            self._dc_bias_v_level_range = Enum(0, 1.5, 2)

        self._measurement_pair = MeasurementPair(
            "CPD", ("capacitance", "dissipation_factor"), ("F", ""))

        self.add_parameter(
            "frequency",
            get_cmd=":FREQuency?",
            set_cmd=":FREQuency {}",
            get_parser=float,
            unit="Hz",
            vals=Numbers(20, 2E6),
            docstring="Gets and sets the frequency for normal measurement.")

        self.add_parameter(
            "current_level",
            get_cmd=self._get_current_level,
            set_cmd=self._set_current_level,
            unit="A",
            vals=self._i_level_range,
            docstring="Gets and sets the current level for measurement signal."
        )

        self.add_parameter(
            "voltage_level",
            get_cmd=self._get_voltage_level,
            set_cmd=self._set_voltage_level,
            unit="V",
            vals=self._v_level_range,
            docstring="Gets and sets the AC bias voltage level for measurement "
            "signal.")

        self.add_parameter("measurement_function",
                           get_cmd=":FUNCtion:IMPedance?",
                           set_cmd=self._set_measurement)

        self.add_parameter(
            "range",
            get_cmd=":FUNCtion:IMPedance:RANGe?",
            set_cmd=self._set_range,
            unit='Ohm',
            vals=self._imp_range,
            docstring="Selects the impedance measurement range, also turns "
            "the auto range function OFF.")

        self.add_parameter(
            "imp_autorange_enabled",
            get_cmd=":FUNCtion:IMPedance:RANGe:AUTO?",
            set_cmd=":FUNCtion:IMPedance:RANGe:AUTO {}",
            val_mapping=create_on_off_val_mapping(on_val="1", off_val="0"),
            docstring="Enables the auto-range for impedance measurement.")

        self.add_parameter(
            "dc_bias_enabled",
            get_cmd=":BIAS:STATe?",
            set_cmd=":BIAS:STATe {}",
            vals=Bool(),
            val_mapping=create_on_off_val_mapping(on_val="1", off_val="0"),
            docstring="Enables DC bias. DC bias is automatically turned "
            "off after recalling the state from memory.")

        self.add_parameter(
            "dc_bias_voltage_level",
            get_cmd=":BIAS:VOLTage:LEVel?",
            set_cmd=":BIAS:VOLTage:LEVel {}",
            get_parser=float,
            unit="V",
            vals=self._dc_bias_v_level_range,
            docstring="Sets the DC bias voltage. Setting does not "
            "implicitly turn the DC bias ON.")

        self.add_parameter("meas_time_mode",
                           val_mapping={
                               "short": "SHOR",
                               "medium": "MED",
                               "long": "LONG"
                           },
                           parameter_class=GroupParameter)

        self.add_parameter("averaging_rate",
                           vals=Ints(1, 256),
                           parameter_class=GroupParameter,
                           get_parser=int,
                           docstring="Averaging rate for the measurement.")

        self._aperture_group = Group(
            [self.meas_time_mode, self.averaging_rate],
            set_cmd=":APERture {meas_time_mode},{averaging_rate}",
            get_cmd=":APERture?")

        if self.has_firmware_a_02_10_or_above:
            self.add_parameter(
                "dc_bias_autorange_enabled",
                get_cmd=":BIAS:RANGe:AUTO?",
                set_cmd=":BIAS:RANGe:AUTO {}",
                vals=Bool(),
                val_mapping=create_on_off_val_mapping(on_val="1", off_val="0"),
                docstring="Enables DC Bias range AUTO setting. When DC bias "
                "range is fixed (not AUTO), '#' is displayed in "
                "the BIAS field of the display.")

        self.add_parameter(
            "signal_mode",
            initial_value=None,
            vals=Enum("Voltage", "Current", None),
            parameter_class=ManualParameter,
            docstring="This parameter tracks the signal mode which is being "
            "set.")

        self.add_submodule("_correction", Correction4980A(self, "correction"))
        self._set_signal_mode_on_driver_initialization()
        self.connect_message()
    def __init__(self,
                 name: str,
                 address: str,
                 silent: bool = False,
                 **kwargs: Any):
        """
        Create an instance of the instrument.

        Args:
            name: Name used by QCoDeS. Appears in the DataSet
            address: Visa-resolvable instrument address.
            silent: If True, the connect_message of the instrument
                is supressed. Default: False
        """

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

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

        self.is_34465A_34470A = self.model in ['34465A', '34470A']
        self.is_34410A_34411A = self.model in ['34410A', '34411A']

        ####################################
        # Instrument specifications

        options = self._options()
        self.has_DIG = self.is_34465A_34470A and (
            "DIG" in options or
            version.parse(convert_legacy_version_to_supported_version("A.03"))
            <= version.parse(
                convert_legacy_version_to_supported_version(idn["firmware"])))
        # Note that the firmware version check is still needed because
        # ``_options`` (the ``*OPT?`` command) returns 'DIG' option for
        # firmware 3.0 only if it has been purchased before
        self.has_MEM = self.is_34465A_34470A and 'MEM' in options

        PLCs = {
            '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],
            '34460A': [0.02, 0.2, 1, 10, 100],
            '34461A': [0.02, 0.2, 1, 10, 100],
            '34465A': [0.02, 0.06, 0.2, 1, 10, 100],
            '34470A': [0.02, 0.06, 0.2, 1, 10, 100]
        }
        if self.has_DIG:
            PLCs['34465A'] = [0.001, 0.002, 0.006] + PLCs['34465A']
            PLCs['34470A'] = [0.001, 0.002, 0.006] + PLCs['34470A']

        # The resolution factor order matches the order of PLCs
        res_factors = {
            '34410A':
            [6e-6, 3e-6, 1.5e-6, 0.7e-6, 0.3e-6, 0.2e-6, 0.1e-6, 0.03e-6],
            '34411A': [
                30e-6, 15e-5, 6e-6, 3e-6, 1.5e-6, 0.7e-6, 0.3e-6, 0.2e-6,
                0.1e-6, 0.03e-6
            ],
            '34460A': [300e-6, 100e-6, 30e-6, 10e-6, 3e-6],
            '34461A': [100e-6, 10e-6, 3e-6, 1e-6, 0.3e-6],
            '34465A': [3e-6, 1.5e-6, 0.7e-6, 0.3e-6, 0.1e-6, 0.03e-6],
            '34470A': [1e-6, 0.5e-6, 0.3e-6, 0.1e-6, 0.03e-6, 0.01e-6]
        }
        if self.has_DIG:
            res_factors['34465A'] = [30e-6, 15e-6, 6e-6
                                     ] + res_factors['34465A']
            res_factors['34470A'] = [30e-6, 10e-6, 3e-6
                                     ] + res_factors['34470A']

        self._resolution_factors = res_factors[self.model]
        self.ranges = [10**n for n in range(-1, 4)]  # 100 m to 1 k
        self.NPLC_list = PLCs[self.model]

        ####################################
        # PARAMETERS

        # this is the "master" parameter that determines whether the DMM is
        # a voltmeter, an ampmeter, etc.
        self.add_parameter('sense_function',
                           label="Instrument sense function",
                           get_cmd="SENSe:FUNCtion?",
                           set_cmd="SENSe:FUNCtion {}",
                           val_mapping={
                               "DC Voltage": '"VOLT"',
                               "AC Voltage": '"VOLT:AC"',
                               "DC Current": '"CURR"',
                               "AC Current": '"CURR:AC"',
                               "2 Wire Resistance": '"RES"',
                               "4 Wire Resistance": '"FRES"'
                           })

        self.add_parameter('line_frequency',
                           get_cmd='SYSTem:LFRequency?',
                           get_parser=int,
                           set_cmd=False,
                           label='Line Frequency',
                           unit='Hz',
                           docstring=('The frequency of the power line where '
                                      'the instrument is plugged'))

        self.add_parameter('NPLC',
                           get_cmd='SENSe:VOLTage:DC:NPLC?',
                           get_parser=float,
                           set_cmd=self._set_NPLC,
                           vals=vals.Enum(*self.NPLC_list),
                           label='Integration time',
                           unit='NPLC',
                           docstring=textwrap.dedent("""\
            Sets the integration time in number of power line cycles (PLC)
            for DC voltage and ratio measurements. Integration time is the
            period that the instrument's analog-to-digital (A/D) converter
            samples the input signal for a measurement. A longer integration
            time gives better measurement resolution but slower measurement
            speed.

            Only integration times of 1, 10, or 100 PLC provide normal mode
            (line frequency noise) rejection.

            Setting the integration time also sets the measurement
            resolution."""))

        self.add_parameter('range',
                           get_cmd='SENSe:VOLTage:DC:RANGe?',
                           get_parser=float,
                           set_cmd='SENSe:VOLTage:DC:RANGe {:f}',
                           vals=vals.Enum(*self.ranges))

        self.add_parameter('resolution',
                           get_cmd='SENSe:VOLTage:DC:RESolution?',
                           get_parser=float,
                           set_cmd=self._set_resolution,
                           label='Resolution',
                           unit='V',
                           vals=vals.MultiType(vals.Numbers(0),
                                               vals.Enum('MIN', 'MAX', 'DEF')),
                           docstring=textwrap.dedent("""\
            Selects the measurement resolution for DC voltage and ratio
            measurements. The resolution is specified in the same units as the
            selected measurement function, not in number of digits.

            You can also specify MIN (best resolution) or MAX (worst
            resolution).

            To achieve normal mode (line frequency noise) rejection,
            use a resolution that corresponds to an integration time that is
            an integral number of power line cycles.

            Refer to "Resolution Table" or "Range, Resolution and NPLC"
            sections of the instrument's manual for the available ranges for
            the resolution values."""))

        self.add_parameter('autorange',
                           label='Autorange',
                           set_cmd='SENSe:VOLTage:DC:RANGe:AUTO {}',
                           get_cmd='SENSe:VOLTage:DC:RANGe:AUTO?',
                           val_mapping={
                               'ON': 1,
                               'OFF': 0
                           },
                           vals=vals.Enum('ON', 'OFF'))

        self.add_parameter('autozero',
                           label='Autozero',
                           set_cmd='SENSe:VOLTage:DC:ZERO:AUTO {}',
                           get_cmd='SENSe:VOLTage:DC:ZERO:AUTO?',
                           val_mapping={
                               'ON': 1,
                               'OFF': 0,
                               'ONCE': 'ONCE'
                           },
                           vals=vals.Enum('ON', 'OFF', 'ONCE'),
                           docstring=textwrap.dedent("""\
            Disables or enables the autozero mode for DC voltage and ratio
            measurements.

            ON:   the DMM internally measures the offset following each
                  measurement. It then subtracts that measurement from the
                  preceding reading. This prevents offset voltages present on
                  the DMM’s input circuitry from affecting measurement
                  accuracy.
            OFF:  the instrument uses the last measured zero measurement and
                  subtracts it from each measurement. It takes a new zero
                  measurement each time you change the function, range or
                  integration time.
            ONCE: the instrument takes one zero measurement and sets
                  autozero OFF. The zero measurement taken is used for all
                  subsequent measurements until the next change to the
                  function, range or integration time. If the specified
                  integration time is less than 1 PLC, the zero measurement
                  is taken at 1 PLC to optimize noise rejection. Subsequent
                  measurements are taken at the specified fast (< 1 PLC)
                  integration time."""))

        ####################################
        # Aperture parameters

        if self.is_34465A_34470A or self.is_34410A_34411A:
            # Define the extreme aperture time values for the 34410A, 34411A,
            # 34465A and 34470A. The upper limits for 34410A and 34411A in the
            # case of a 60Hz line frequency are just calculated by multiplying
            # the respective limit with 50/60.
            utility_freq = self.line_frequency()
            if utility_freq == 50:
                apt_times = {
                    '34410A': [100e-6, 1],
                    '34411A': [20e-6, 1],
                    '34465A': [0.3e-3, 2],
                    '34470A': [0.3e-3, 2]
                }
            elif utility_freq == 60:
                apt_times = {
                    '34410A': [100e-6, 0.83],
                    '34411A': [20e-6, 0.83],
                    '34465A': [0.3e-3, 1.67],
                    '34470A': [0.3e-3, 1.67]
                }
            if self.has_DIG:
                apt_times['34465A'][0] = 20e-6
                apt_times['34470A'][0] = 20e-6

            self.add_parameter('aperture_mode',
                               label='Aperture mode',
                               set_cmd='SENSe:VOLTage:DC:APERture:ENABled {}',
                               get_cmd='SENSe:VOLTage:DC:APERture:ENABled?',
                               val_mapping={
                                   'ON': 1,
                                   'OFF': 0
                               },
                               vals=vals.Enum('ON', 'OFF'),
                               docstring=textwrap.dedent("""\
                Enables the setting of integration time in seconds (called
                aperture time) for DC voltage measurements. If aperture time
                mode is disabled (default), the integration time is set in PLC
                (power-line cycles)."""))

            self.add_parameter('aperture_time',
                               label='Aperture time',
                               set_cmd=self._set_apt_time,
                               get_cmd='SENSe:VOLTage:DC:APERture?',
                               get_parser=float,
                               vals=vals.Numbers(*apt_times[self.model]),
                               docstring=textwrap.dedent("""\
                Specifies the integration time in seconds (called aperture
                time) with 2 µs resolution for DC voltage measurements.

                Use this command for precise control of the DMM's
                integration time. Use `NPLC` for better power-line noise
                rejection characteristics (NPLC > 1).

                Setting the aperture time automatically enables the aperture
                mode."""))

        ####################################
        # Submodules

        self.add_submodule('display', Display(self, 'display'))
        self.add_submodule('trigger', Trigger(self, 'trigger'))
        self.add_submodule('sample', Sample(self, 'sample'))

        ####################################
        # Measurement Parameters
        # snapshot_get is disabled for each of these to prevent rapid mode
        # changes on initialization or snapshot update, however the cached
        # (last read) value will still be stored in the snapshot.

        self.add_parameter('volt',
                           get_cmd=partial(self._get_parameter, "DC Voltage"),
                           label='Voltage',
                           unit='V',
                           snapshot_get=False)

        self.add_parameter('curr',
                           get_cmd=partial(self._get_parameter, "DC Current"),
                           label='Current',
                           unit='A',
                           snapshot_get=False)

        self.add_parameter('ac_volt',
                           get_cmd=partial(self._get_parameter, "AC Voltage"),
                           label='AC Voltage',
                           unit='V',
                           snapshot_get=False)

        self.add_parameter('ac_curr',
                           get_cmd=partial(self._get_parameter, "AC Current"),
                           label='AC Current',
                           unit='A',
                           snapshot_get=False)

        self.add_parameter('res',
                           get_cmd=partial(self._get_parameter,
                                           "2 Wire Resistance"),
                           label='Resistance',
                           unit='Ohms',
                           snapshot_get=False)

        self.add_parameter('four_wire_res',
                           get_cmd=partial(self._get_parameter,
                                           "4 Wire Resistance"),
                           label='Resistance',
                           unit='Ohms',
                           snapshot_get=False)

        #####################################
        # Time trace parameters

        self.add_parameter('timetrace_npts',
                           label='Time trace number of points',
                           initial_value=500,
                           get_cmd=None,
                           set_cmd=None,
                           vals=vals.Ints(1))

        self.add_parameter('timetrace_dt',
                           label='Time trace time interval',
                           unit='s',
                           initial_value=1e-1,
                           get_cmd=None,
                           set_cmd=None,
                           vals=vals.Numbers(0))

        self.add_parameter('time_axis',
                           label='Time',
                           unit='s',
                           snapshot_value=False,
                           vals=vals.Arrays(shape=(self.timetrace_npts, )),
                           parameter_class=TimeAxis)

        self.add_parameter('timetrace',
                           vals=vals.Arrays(shape=(self.timetrace_npts, )),
                           setpoints=(self.time_axis, ),
                           parameter_class=TimeTrace)

        ####################################
        # Connect message

        if not silent:
            self.connect_message()