Пример #1
0
    def __init__(self,
                 name,
                 address,
                 port,
                 visalib,
                 metadata=None,
                 device_clear=False,
                 terminator='\n',
                 timeout=3,
                 **kwargs):

        # remove IPInstrument-specific kwargs
        ipkwargs = ['write_confirmation']
        newkwargs = {
            kw: val
            for (kw, val) in kwargs.items() if kw not in ipkwargs
        }

        Instrument.__init__(self, name, metadata=metadata, **newkwargs)
        self.visa_log = get_instrument_logger(self, VISA_LOGGER)

        ##################################################
        # __init__ of VisaInstrument

        self.add_parameter('timeout',
                           get_cmd=self._get_visa_timeout,
                           set_cmd=self._set_visa_timeout,
                           unit='s',
                           vals=vals.MultiType(vals.Numbers(min_value=0),
                                               vals.Enum(None)))

        # auxiliary VISA library to use for mocking
        self.visalib = visalib
        self.visabackend = None

        self.set_address(address)
        if device_clear:
            self.device_clear()

        self.set_terminator(terminator)
        self.timeout.set(timeout)
Пример #2
0
    def __init__(self,
                 name,
                 address=None,
                 timeout=5,
                 terminator='',
                 device_clear=True,
                 **kwargs):
        super().__init__(name, **kwargs)

        self.add_parameter('timeout',
                           get_cmd=self._get_visa_timeout,
                           set_cmd=self._set_visa_timeout,
                           unit='s',
                           vals=vals.MultiType(vals.Numbers(min_value=0),
                                               vals.Enum(None)))

        self.set_address(address)
        if device_clear:
            self.device_clear()
        self.set_terminator(terminator)
        self.timeout.set(timeout)
Пример #3
0
def test_val_mapping_with_parsers():
    # We store value external to cache
    # to allow testing of interaction with cache
    mem = ParameterMemory()

    # # set_parser with val_mapping
    # Parameter('p', set_cmd=mem.set, get_cmd=mem.get,
    #           val_mapping={'off': 0, 'on': 1},
    #           set_parser=mem.parse_set_p)

    # get_parser with val_mapping
    p = Parameter('p',
                  set_cmd=mem.set_p_prefixed,
                  get_cmd=mem.get,
                  get_parser=mem.strip_prefix,
                  val_mapping={
                      'off': 0,
                      'on': 1
                  },
                  vals=vals.Enum('off', 'on'))

    p('off')
    assert mem.get() == 'PVAL: 0'
    # this is slight strange. Since it uses a custom set_cmd
    # rather than a set_parser the raw_value does not match
    # what is actually sent to the instrument
    assert p.cache.raw_value == 0
    assert p() == 'off'

    mem.set('PVAL: 1')
    assert p() == 'on'

    p.cache.set('off')
    assert p.get_latest() == 'off'
    # Nothing has been passed to the "instrument" at ``cache.set``
    # call, hence the following assertions should hold
    assert mem.get() == 'PVAL: 1'
    assert p() == 'on'
    assert p.get_latest() == 'on'
    assert p.cache.get() == 'on'
Пример #4
0
def test_val_mapping_basic():
    # We store value external to cache
    # to allow testing of interaction with cache
    mem = ParameterMemory()

    p = Parameter('p',
                  set_cmd=mem.set,
                  get_cmd=mem.get,
                  val_mapping={
                      'off': 0,
                      'on': 1
                  },
                  vals=vals.Enum('off', 'on'))

    p('off')
    assert p.cache.raw_value == 0
    assert mem.get() == 0
    assert p() == 'off'

    mem.set(1)
    assert p() == 'on'

    # implicit mapping to ints
    mem.set('0')
    assert p() == 'off'

    # unrecognized response
    mem.set(2)
    with pytest.raises(KeyError):
        p()

    mem.set(1)

    p.cache.set('off')
    assert p.get_latest() == 'off'
    # Nothing has been passed to the "instrument" at ``cache.set``
    # call, hence the following assertions should hold
    assert mem.get() == 1
    assert p() == 'on'
    assert p.get_latest() == 'on'
Пример #5
0
    def create_parameters_from_node_tree(self, parameters: dict) -> None:
        """
        Create QuCoDeS parameters from the device node tree.

        Args:
            parameters: A device node tree.
        """
        for parameter in parameters.values():
            getter = partial(self._getter, parameter['Node'], parameter['Type']
                             ) if 'Read' in parameter['Properties'] else None
            setter = partial(self._setter, parameter['Node'], parameter['Type']
                             ) if 'Write' in parameter['Properties'] else False
            options = validators.Enum(
                *[int(val) for val in parameter['Options'].keys()]) \
                if parameter['Type'] == 'Integer (enumerated)' else None
            parameter_name = self._generate_parameter_name(parameter['Node'])
            self.add_parameter(name=parameter_name,
                               set_cmd=setter,
                               get_cmd=getter,
                               vals=options,
                               docstring=parameter['Description'],
                               unit=parameter['Unit'])
Пример #6
0
    def __init__(self,
                 name=None,
                 label=None,
                 unit=None,
                 instrument=None,
                 value=None,
                 byte_to_value_dict=None,
                 vals=None):
        warnings.warn("AlazarParamater is deprecated. Please replace with "
                      "Regular parameter or TraceParameter")
        if vals is None:
            if byte_to_value_dict is None:
                vals = validators.Anything()
            else:
                # TODO(damazter) (S) test this validator
                vals = validators.Enum(*byte_to_value_dict.values())

        super().__init__(name=name,
                         label=label,
                         unit=unit,
                         vals=vals,
                         instrument=instrument)
        self.instrument = instrument
        self._byte = None
        self._uptodate_flag = False

        # TODO(damazter) (M) check this block
        if byte_to_value_dict is None:
            self._byte_to_value_dict = TrivialDictionary()
            self._value_to_byte_dict = TrivialDictionary()
        else:
            self._byte_to_value_dict = byte_to_value_dict
            self._value_to_byte_dict = {
                v: k
                for k, v in self._byte_to_value_dict.items()
            }

        self._set(value)
Пример #7
0
    def _add_extra_parameters(self):
        """
        We add a few additional custom parameters on top of the ones defined in the device files. These are:
        timeout - A specific timeout value in seconds used for the various timeconsuming operations on the device
          such as waiting for an upload to complete.
        cfg_num_codewords - determines the maximum number of codewords to be supported by the program that will
          be uploaded using the "upload_codeword_program" method.
        cfg_codeword_protocol - determines the specific codeword protocol to use, for example 'microwave' or 'flux'.
          It determines which bits transmitted over the 32-bit DIO interface are used as actual codeword bits.
        awgs_[0-3]_sequencer_program_crc32_hash - CRC-32 hash of the currently uploaded sequencer program to enable
          changes in program to be detected.
        dio_calibration_delay - the delay that is programmed on the DIO lines as part of the DIO calibration
            process in order for the instrument to reliably sample data from the CC. Can be used to detect
            unexpected changes in timing of the entire system. The parameter can also be used to force a specific
            delay to be used on the DIO although that is not generally recommended.
        """
        super()._add_extra_parameters()

        self.add_parameter(
            'cfg_codeword_protocol',
            initial_value='identical',
            vals=validators.Enum('identical', 'microwave', 'new_microwave',
                                 'new_novsm_microwave', 'flux'),
            docstring=(
                'Used in the configure codeword method to determine what DIO'
                ' pins are used in for which AWG numbers.'),
            parameter_class=ManualParameter)

        self.add_parameter(
            'dio_calibration_delay',
            set_cmd=self._set_dio_calibration_delay,
            get_cmd=self._get_dio_calibration_delay,
            unit='',
            label='DIO Calibration delay',
            docstring='Configures the internal delay in 300 MHz cycles (3.3 ns) '
            'to be applied on the DIO interface in order to achieve reliable sampling'
            ' of the codewords. The valid range is 0 to 15.',
            vals=validators.Ints())
    def __init__(self, name, QWG, **kw):
        logging.warning('The QWG_LookuptableManager is deprecated.')
        logging.info(__name__ + ' : Initializing instrument')
        super().__init__(name, **kw)
        self.add_parameter('QWG', parameter_class=InstrumentParameter)

        self.add_parameter('Q_amp180',
                           unit='V',
                           vals=vals.Numbers(-1, 1),
                           parameter_class=ManualParameter,
                           initial_value=0.1)
        self.add_parameter('Q_amp90_scale',
                           vals=vals.Numbers(-1, 1),
                           parameter_class=ManualParameter,
                           initial_value=0.5)
        self.add_parameter('Q_motzoi', vals=vals.Numbers(-2, 2),
                           parameter_class=ManualParameter,
                           initial_value=0.0)
        self.add_parameter('Q_gauss_width',
                           vals=vals.Numbers(min_value=1e-9), unit='s',
                           parameter_class=ManualParameter,
                           initial_value=4e-9)

        self.add_parameter('spec_pulse_type',
                           vals=vals.Enum('block', 'gauss'),
                           parameter_class=ManualParameter,
                           initial_value='block')
        self.add_parameter('spec_amp',
                           unit='V',
                           vals=vals.Numbers(0, 1),
                           parameter_class=ManualParameter,
                           initial_value=0.4)
        self.add_parameter(
            'spec_length', vals=vals.Numbers(min_value=1e-9), unit='s',
            parameter_class=ManualParameter,
            docstring=('length of the block pulse if spec_pulse_type' +
                       'is "block", gauss_width if spec_pulse_type is gauss.'),
            initial_value=100e-9)
Пример #9
0
    def __init__(self, name, address=None, timeout=5,
                 terminator='', device_clear=True, visalib=None, **kwargs):

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

        self.add_parameter('timeout',
                           get_cmd=self._get_visa_timeout,
                           set_cmd=self._set_visa_timeout,
                           unit='s',
                           vals=vals.MultiType(vals.Numbers(min_value=0),
                                               vals.Enum(None)))

        # backwards-compatibility
        if address and '@' in address:
            address, visa_library = address.split('@')
            if visalib:
                warnings.warn('You have specified the VISA library in two '
                              'different ways. Please do not include "@" in '
                              'the address kwarg and only use the visalib '
                              'kwarg for that.')
                self.visalib = visalib
            else:
                warnings.warn('You have specified the VISA library using '
                              'an "@" in the address kwarg. Please use the '
                              'visalib kwarg instead.')
                self.visalib = '@' + visa_library
        else:
            self.visalib = visalib

        self.visabackend = None

        self.set_address(address)
        if device_clear:
            self.device_clear()

        self.set_terminator(terminator)
        self.timeout.set(timeout)
Пример #10
0
    def __init__(self,
                 name=None,
                 label=None,
                 unit=None,
                 instrument=None,
                 value=None,
                 byte_to_value_dict=None,
                 vals=None):
        if vals is None:
            if byte_to_value_dict is None:
                vals = validators.Anything()
            else:
                # TODO(damazter) (S) test this validator
                vals = validators.Enum(*byte_to_value_dict.values())

        super().__init__(name=name,
                         label=label,
                         units=unit,
                         vals=vals,
                         instrument=instrument)
        self.instrument = instrument
        self._byte = None
        self._uptodate_flag = False

        # TODO(damazter) (M) check this block
        if byte_to_value_dict is None:
            self._byte_to_value_dict = TrivialDictionary()
            self._value_to_byte_dict = TrivialDictionary()
        else:
            self._byte_to_value_dict = byte_to_value_dict
            self._value_to_byte_dict = {
                v: k
                for k, v in self._byte_to_value_dict.items()
            }

        self._set(value)
Пример #11
0
    def __init__(
        self,
        name: str,
        address: str,
        timeout: Union[int, float] = 5,
        terminator: Optional[str] = None,
        device_clear: bool = True,
        visalib: Optional[str] = None,
        **kwargs: Any,
    ):

        super().__init__(name, **kwargs)
        self.visa_log = get_instrument_logger(self, VISA_LOGGER)
        self.visabackend: str
        self.visa_handle: visa.resources.MessageBasedResource
        self.visalib: Optional[str] = visalib

        self.add_parameter('timeout',
                           get_cmd=self._get_visa_timeout,
                           set_cmd=self._set_visa_timeout,
                           unit='s',
                           vals=vals.MultiType(vals.Numbers(min_value=0),
                                               vals.Enum(None)))

        try:
            self.set_address(address)
        except Exception as e:
            self.visa_log.exception(f"Could not connect at {address}")
            self.close()
            raise e

        if device_clear:
            self.device_clear()

        self.set_terminator(terminator)
        self.timeout.set(timeout)
Пример #12
0
    def __init__(self, parent: InstrumentChannel, name):
        super().__init__(parent, name)

        trigger = self.parent._task.triggers.start_trigger

        self.add_parameter(name='trig_type',
                           label=' type',
                           set_cmd=lambda x: setattr(trigger, "trig_type", x),
                           get_cmd=lambda: getattr(trigger, "trig_type"),
                           vals=vals.Enum(*constants.TriggerType))

        self.add_parameter(
            name='dig_edge_src',
            label='start trigger digital edge source',
            set_cmd=lambda x: setattr(trigger, "dig_edge_src", x),
            get_cmd=lambda: getattr(trigger, "dig_edge_src"),
            vals=vals.Strings())

        self.add_parameter(
            name='retriggerable',
            label='start trigger retrigerable',
            set_cmd=lambda x: setattr(trigger, "retriggerable", x),
            get_cmd=lambda: getattr(trigger, "retriggerable"),
            vals=vals.Bool())
Пример #13
0
    def __init__(self, name, address, **kwargs):

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

        self.add_parameter(name='power',
                           label='Power',
                           unit='dBm',
                           get_cmd='SOUR:POW?',
                           set_cmd='SOUR:POW {:.4f}',
                           get_parser=float,
                           vals=vals.Numbers(-150, 10))

        self.add_parameter(name='bandwidth',
                           label='Bandwidth',
                           unit='Hz',
                           get_cmd='SENS:BAND?',
                           set_cmd='SENS:BAND {:.4f}',
                           get_parser=int,
                           vals=vals.Numbers(1, 1e6))

        self.add_parameter(name='avg',
                           label='Averages',
                           unit='',
                           get_cmd='SENS:AVER:COUN?',
                           set_cmd='SENS:AVER:COUN {:.4f}',
                           get_parser=int,
                           vals=vals.Numbers(1, 999))

        self.add_parameter(name='start',
                           get_cmd='SENS:FREQ:START?',
                           set_cmd=self._set_start,
                           get_parser=float)

        self.add_parameter(name='stop',
                           get_cmd='SENS:FREQ:STOP?',
                           set_cmd=self._set_stop,
                           get_parser=float)
        
        self.add_parameter(name='center',
                           get_cmd='SENS:FREQ:CENTER?',
                           set_cmd=self._set_center,
                           get_parser=float)
    
        self.add_parameter(name='span',
                           get_cmd='SENS:FREQ:SPAN?',
                           set_cmd=self._set_span,
                           get_parser=float)

        self.add_parameter(name='npts',
                           get_cmd='SENS:SWE:POIN?',
                           set_cmd=self._set_npts,
                           get_parser=int)

        self.add_parameter(name='trace',
                           start=self.start(),
                           stop=self.stop(),
                           npts=self.npts(),
                           parameter_class=FrequencySweep)
                           
        self.add_parameter('measure',
                           get_cmd='CALC:PAR:DEF?',
                           vals=vals.Enum('S11','S12','S21','S22'),
                           set_cmd=self._set_measure,
                           label='Sxy measurement parameter')
                           
        #self.add_parameter('format1',
        #                    get_cmd='CALC:FORM',
        #                    vals=vals.Enum( 'MLOG','PHAS','GDEL','MLIN','SWR','REAL','IMAG','UPH'),
        #                    set_cmd=self._set_format1,
        #                    label='Trace ch1 format')
                            
        #self.add_parameter('format2',
        #                    get_cmd='CALC:FORM',
        #                    vals=vals.Enum( 'MLOG','PHAS','GDEL','MLIN','SWR','REAL','IMAG','UPH'),
        #                    set_cmd=self._set_format2,
        #                    label='Trace ch2  format')

        self.add_function('reset', call_cmd='*RST')
        #self.add_function('tooltip_on', call_cmd='SYST:ERR:DISP ON')
        #self.add_function('tooltip_off', call_cmd='SYST:ERR:DISP OFF')
        self.add_function('cont_meas_on', call_cmd='TRIG:SOUR INT')
        self.add_function('cont_meas_off', call_cmd='TRIG:SOUR BUS')
        #self.add_function('update_display_once', call_cmd='SYST:DISP:UPD ONCE')
        #self.add_function('update_display_on', call_cmd='SYST:DISP:UPD ON')
        #self.add_function('update_display_off', call_cmd='SYST:DISP:UPD OFF')
        self.add_function('rf_off', call_cmd='OUTP OFF')
        self.add_function('rf_on', call_cmd='OUTP ON')

        self.initialise()
        self.connect_message()
Пример #14
0
    def __init__(self,
                 parent: 'ZNB',
                 name: str,
                 channel: int,
                 vna_parameter: Optional[str] = None,
                 existing_trace_to_bind_to: Optional[str] = None) -> None:
        """
        Args:
            parent: Instrument that this channel is bound to.
            name: Name to use for this channel.
            channel: channel on the VNA to use
            vna_parameter: Name of parameter on the vna that this should
                measure such as S12. If left empty this will fall back to
                `name`.
            existing_trace_to_bind_to: Name of an existing trace on the VNA.
                If supplied try to bind to an existing trace with this name
                rather than creating a new trace.

        """
        n = channel
        self._instrument_channel = channel
        # Additional wait when adjusting instrument timeout to sweep time.
        self._additional_wait = 1

        if vna_parameter is None:
            vna_parameter = name
        self._vna_parameter = vna_parameter
        super().__init__(parent, name)

        if existing_trace_to_bind_to is None:
            self._tracename = f"Trc{channel}"
        else:
            traces = self._parent.ask("CONFigure:TRACe:CATalog?")
            if existing_trace_to_bind_to not in traces:
                raise RuntimeError(f"Trying to bind to"
                                   f" {existing_trace_to_bind_to} "
                                   f"which is not in {traces}")
            self._tracename = existing_trace_to_bind_to

        # map hardware channel to measurement
        # hardware channels are mapped one to one to QCoDeS channels
        # we are not using sub traces within channels.
        if existing_trace_to_bind_to is None:
            self.write(f"CALC{self._instrument_channel}:PAR:SDEF"
                       f" '{self._tracename}', '{self._vna_parameter}'")

        # Source power is dependent on model, but not well documented.
        # Here we assume -60 dBm for ZNB20, the others are set,
        # due to lack of knowledge, to -80 dBm as of before the edit.
        full_modelname = self._parent.get_idn()['model']
        if full_modelname is not None:
            model = full_modelname.split('-')[0]
        else:
            raise RuntimeError("Could not determine ZNB model")
        mSourcePower = {'ZNB4': -80, 'ZNB8': -80, 'ZNB20': -60, 'ZNB40': -60}
        if model not in mSourcePower.keys():
            raise RuntimeError(f"Unsupported ZNB model: {model}")
        self._min_source_power: float
        self._min_source_power = mSourcePower[model]

        self.add_parameter(name='vna_parameter',
                           label='VNA parameter',
                           get_cmd=f"CALC{self._instrument_channel}:"
                           f"PAR:MEAS? '{self._tracename}'",
                           get_parser=self._strip)
        self.add_parameter(name='power',
                           label='Power',
                           unit='dBm',
                           get_cmd=f'SOUR{n}:POW?',
                           set_cmd=f'SOUR{n}:POW {{:.4f}}',
                           get_parser=float,
                           vals=vals.Numbers(self._min_source_power, 25))
        # there is an 'increased bandwidth option' (p. 4 of manual) that does
        # not get taken into account here
        self.add_parameter(
            name='bandwidth',
            label='Bandwidth',
            unit='Hz',
            get_cmd=f'SENS{n}:BAND?',
            set_cmd=f'SENS{n}:BAND {{:.4f}}',
            get_parser=int,
            vals=vals.Enum(*np.append(
                10**6, np.kron([1, 1.5, 2, 3, 5, 7], 10**np.arange(6)))))
        self.add_parameter(name='avg',
                           label='Averages',
                           unit='',
                           get_cmd=f'SENS{n}:AVER:COUN?',
                           set_cmd=f'SENS{n}:AVER:COUN {{:.4f}}',
                           get_parser=int,
                           vals=vals.Ints(1, 5000))
        self.add_parameter(name='start',
                           get_cmd=f'SENS{n}:FREQ:START?',
                           set_cmd=self._set_start,
                           get_parser=float,
                           vals=vals.Numbers(self._parent._min_freq,
                                             self._parent._max_freq - 10))
        self.add_parameter(name='stop',
                           get_cmd=f'SENS{n}:FREQ:STOP?',
                           set_cmd=self._set_stop,
                           get_parser=float,
                           vals=vals.Numbers(self._parent._min_freq + 1,
                                             self._parent._max_freq))
        self.add_parameter(name='center',
                           get_cmd=f'SENS{n}:FREQ:CENT?',
                           set_cmd=self._set_center,
                           get_parser=float,
                           vals=vals.Numbers(self._parent._min_freq + 0.5,
                                             self._parent._max_freq - 10))
        self.add_parameter(
            name='span',
            get_cmd=f'SENS{n}:FREQ:SPAN?',
            set_cmd=self._set_span,
            get_parser=float,
            vals=vals.Numbers(1,
                              self._parent._max_freq - self._parent._min_freq))
        self.add_parameter(name='npts',
                           get_cmd=f'SENS{n}:SWE:POIN?',
                           set_cmd=self._set_npts,
                           get_parser=int)
        self.add_parameter(name='status',
                           get_cmd=f'CONF:CHAN{n}:MEAS?',
                           set_cmd=f'CONF:CHAN{n}:MEAS {{}}',
                           get_parser=int)
        self.add_parameter(name='format',
                           get_cmd=partial(self._get_format,
                                           tracename=self._tracename),
                           set_cmd=self._set_format,
                           val_mapping={
                               'dB': 'MLOG\n',
                               'Linear Magnitude': 'MLIN\n',
                               'Phase': 'PHAS\n',
                               'Unwr Phase': 'UPH\n',
                               'Polar': 'POL\n',
                               'Smith': 'SMIT\n',
                               'Inverse Smith': 'ISM\n',
                               'SWR': 'SWR\n',
                               'Real': 'REAL\n',
                               'Imaginary': 'IMAG\n',
                               'Delay': "GDEL\n",
                               'Complex': "COMP\n"
                           })

        self.add_parameter(name='trace_mag_phase',
                           start=self.start(),
                           stop=self.stop(),
                           npts=self.npts(),
                           channel=n,
                           parameter_class=FrequencySweepMagPhase)
        self.add_parameter(name='trace',
                           start=self.start(),
                           stop=self.stop(),
                           npts=self.npts(),
                           channel=n,
                           parameter_class=FrequencySweep)
        self.add_parameter(name='electrical_delay',
                           label='Electrical delay',
                           get_cmd=f'SENS{n}:CORR:EDEL2:TIME?',
                           set_cmd=f'SENS{n}:CORR:EDEL2:TIME {{}}',
                           get_parser=float,
                           unit='s')
        self.add_parameter(name='sweep_time',
                           label='Sweep time',
                           get_cmd=f'SENS{n}:SWE:TIME?',
                           get_parser=float,
                           unit='s')
        self.add_function('set_electrical_delay_auto',
                          call_cmd=f'SENS{n}:CORR:EDEL:AUTO ONCE')

        self.add_function('autoscale',
                          call_cmd='DISPlay:TRACe1:Y:SCALe:AUTO ONCE, '
                          f"{self._tracename}")
Пример #15
0
    def __init__(self, name, address, silent=False, **kwargs):
        """
        Create an instance of the instrument.

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

        warnings.warn(
            "This driver is old and will be removed from QCoDeS "
            "soon. Please use the Keysight_344xxA classes from the "
            "files "
            "instrument_drivers/Keysight"
            "/Keysight_344xxA_submodules "
            "instead.", UserWarning)

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

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

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

        self.has_DIG = 'DIG' in self._licenses()

        PLCs = {
            '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']

        ranges = {
            '34460A': [10**n for n in range(-3, 9)],  # 1 m to 100 M
            '34461A': [10**n for n in range(-3, 9)],  # 1 m to 100 M
            '34465A': [10**n for n in range(-3, 10)],  # 1 m to 1 G
            '34470A': [10**n for n in range(-3, 10)],  # 1 m to 1 G
        }

        # The resolution factor order matches the order of PLCs
        res_factors = {
            '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 = ranges[self.model]
        self.NPLC_list = PLCs[self.model]

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

        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('volt',
                           get_cmd=self._get_voltage,
                           label='Voltage',
                           unit='V')

        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('display_enabled',
                           label='Display enabled',
                           set_cmd='DISPlay:STATe {}',
                           get_cmd='DISPlay:STATe?',
                           val_mapping={
                               True: 1,
                               False: 0
                           },
                           docstring=textwrap.dedent("""\
            Disables or enables the front panel display. When disabled,
            the display dims, and all annunciators are disabled. However,
            the screen remains on.

            Disabling the display improves command execution speed from the
            remote interface and provides basic security.

            Displaying text with `display_text` parameter will work even
            when the display is disabled."""))

        self.add_parameter('display_text',
                           label='Display text',
                           set_cmd='DISPLAY:TEXT "{}"',
                           get_cmd='DISPLAY:TEXT?',
                           get_parser=lambda s: s.strip('"'),
                           vals=vals.Strings(),
                           docstring=textwrap.dedent("""\
            Displays the given text on the screen. Specifying empty string
            moves the display back to its normal state. The same can be
            achieved by calling `display_clear`."""))

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

        ####################################
        # TRIGGERING

        if self.model in ['34465A', '34470A']:
            _max_trigger_count = 1e9
        else:
            _max_trigger_count = 1e6

        self.add_parameter('trigger_count',
                           label='Trigger Count',
                           set_cmd='TRIGger:COUNt {}',
                           get_cmd='TRIGger:COUNt?',
                           get_parser=float,
                           vals=vals.MultiType(
                               vals.Numbers(1, _max_trigger_count),
                               vals.Enum('MIN', 'MAX', 'DEF', 'INF')),
                           docstring=textwrap.dedent("""\
            Selects the number of triggers that are accepted by the
            instrument before returning to the "idle" trigger state.

            You can use the specified trigger count in conjunction with
            `sample_count`. In this case, the number of measurements
            returned is the sample count multiplied by the trigger count.

            A variable trigger count is not available from the front panel.
            However, when you return to remote control of the instrument,
            the trigger count returns to the previous value you selected."""))

        self.add_parameter('trigger_delay',
                           label='Trigger Delay',
                           unit='s',
                           set_cmd='TRIGger:DELay {}',
                           get_cmd='TRIGger:DELay?',
                           vals=vals.MultiType(vals.Numbers(0, 3600),
                                               vals.Enum('MIN', 'MAX', 'DEF')),
                           get_parser=float,
                           docstring=textwrap.dedent("""\
            Sets the delay between the trigger signal and the first
            measurement. This may be useful in applications where you want
            to allow the input to settle before taking a measurement or for
            pacing a burst of measurements.

            Step size for DC measurements is approximately 1 µs. For AC
            measurements, step size depends on AC bandwidth.

            Selecting a specific trigger delay disables the automatic
            trigger delay."""))

        self.add_parameter('auto_trigger_delay_enabled',
                           label='Auto Trigger Delay Enabled',
                           set_cmd='TRIGger:DELay:AUTO {}',
                           get_cmd='TRIGger:DELay:AUTO?',
                           get_parser=int,
                           val_mapping={
                               True: 1,
                               False: 0
                           },
                           docstring=textwrap.dedent("""\
            Disables or enables automatic trigger delay. If enabled,
            the instrument determines the delay based on function, range,
            and integration time or bandwidth.

            Selecting a specific trigger delay using `trigger_delay` disables
            the automatic trigger delay."""))

        self.add_parameter('trigger_slope',
                           label='Trigger Slope',
                           set_cmd='TRIGger:SLOPe {}',
                           get_cmd='TRIGger:SLOPe?',
                           vals=vals.Enum('POS', 'NEG'))

        if self.model in ['34465A', '34470A'] and self.has_DIG:
            self.add_parameter('trigger_level',
                               label='Trigger Level',
                               unit='V',
                               set_cmd='TRIGger:LEVel {}',
                               get_cmd='TRIGger:LEVel?',
                               get_parser=float,
                               vals=vals.MultiType(
                                   vals.Numbers(-1000, 1000),
                                   vals.Enum('MIN', 'MAX', 'DEF')),
                               docstring=textwrap.dedent("""\
                Sets the level on which a trigger occurs when level
                triggering is enabled (`trigger_source set to "INT").

                Note that for 100 mV to 100 V ranges and autorange is off,
                the trigger level can only be set within ±120% of the
                range."""))

        _trigger_source_docstring = textwrap.dedent("""\
            Selects the trigger source for measurements.

            IMMediate: The trigger signal is always present. When you place
                the instrument in the "wait-for-trigger" state, the trigger is
                issued immediately.

            BUS: The instrument is triggered by `trigger` method of this
                driver once the DMM is in the "wait-for-trigger" state.

            EXTernal: The instrument accepts hardware triggers applied to
                the rear-panel Ext Trig input and takes the specified number
                of measurements (`sample_count`), each time a TTL pulse
                specified by `trigger_slope` is received. If the
                instrument receives an external trigger before it is ready,
                it buffers one trigger.""")
        _trigger_source_vals = vals.Enum('IMM', 'EXT', 'BUS')

        if self.model in ['34465A', '34470A'] and self.has_DIG:
            _trigger_source_vals = vals.Enum('IMM', 'EXT', 'BUS', 'INT')
            # extra empty lines are needed for readability of the docstring
            _trigger_source_docstring += textwrap.dedent("""\


            INTernal: Provides level triggering capability. To trigger on a
                level on the input signal, select INTernal for the source,
                and set the level and slope with the `trigger_level` and
                `trigger_slope` parameters.""")

        self.add_parameter('trigger_source',
                           label='Trigger Source',
                           set_cmd='TRIGger:SOURce {}',
                           get_cmd='TRIGger:SOURce?',
                           vals=_trigger_source_vals,
                           docstring=_trigger_source_docstring)

        ####################################
        # SAMPLING

        if self.model in ['34465A', '34470A']:
            _max_sample_count = 1e9
        else:
            _max_sample_count = 1e6

        self.add_parameter('sample_count',
                           label='Sample Count',
                           set_cmd=partial(self._set_databuffer_setpoints,
                                           'SAMPle:COUNt {}'),
                           get_cmd='SAMPle:COUNt?',
                           vals=vals.MultiType(
                               vals.Numbers(1, _max_sample_count),
                               vals.Enum('MIN', 'MAX', 'DEF')),
                           get_parser=int,
                           docstring=textwrap.dedent("""\
            Specifies the number of measurements (samples) the instrument
            takes per trigger.

            MAX selects 1 billion readings. However, when pretrigger is
            selected, the maximum is 50,000 readings (without the MEM
            option) or 2,000,000 readings (with the MEM option)"""))

        if self.has_DIG:
            self.add_parameter('sample_count_pretrigger',
                               label='Sample Pretrigger Count',
                               set_cmd='SAMPle:COUNt:PRETrigger {}',
                               get_cmd='SAMPle:COUNt:PRETrigger?',
                               vals=vals.MultiType(
                                   vals.Numbers(0, 2e6 - 1),
                                   vals.Enum('MIN', 'MAX', 'DEF')),
                               get_parser=int,
                               docstring=textwrap.dedent("""\
                Allows collection of the data being digitized the trigger.
                Reserves memory for pretrigger samples up to the specified
                num. of pretrigger samples."""))

        if self.model in ['34465A', '34470A']:
            self.add_parameter('sample_source',
                               label='Sample Timing Source',
                               set_cmd='SAMPle:SOURce {}',
                               get_cmd='SAMPle:SOURce?',
                               vals=vals.Enum('IMM', 'TIM'),
                               docstring=('Determines sampling time, '
                                          'immediate or using sample_timer'))

        self.add_parameter('sample_timer',
                           label='Sample Timer',
                           set_cmd='SAMPle:TIMer {}',
                           get_cmd='SAMPle:TIMer?',
                           unit='s',
                           vals=vals.MultiType(vals.Numbers(0, 3600),
                                               vals.Enum('MIN', 'MAX', 'DEF')),
                           get_parser=float,
                           docstring=textwrap.dedent("""\
            The value is rounded by the instrument to the nearest step. For DC
            measurements, the step size is 1 µs. For AC measurements,
            it is AC bandwidth dependent.

            Special values are: MIN - recommended minimum, MAX - maximum,
            DEF - default. In order to obtain the actual value of the
            parameter that gets set when setting it to one of these special
            values, just call the get method of the parameter, or use
            corresponding parameters in this driver,
            like `sample_timer_minimum`.

            Specifying a value that is between the absolute minimum (assumes
            no range changes) and the recommended minimum value,
            may generate a timing violation error when making measurements.

            Applying a value less than the absolute minimum will generate an
            error."""))

        self.add_parameter('sample_timer_minimum',
                           label='Minimal recommended sample time',
                           get_cmd='SAMPle:TIMer? MIN',
                           get_parser=float,
                           unit='s',
                           docstring=textwrap.dedent("""\
            This value is measurement dependent. It depends on such things
            as the integration time, autozero on or off, autorange on or
            off, and the measurement range. Basically, the minimum is
            automatically determined by the instrument so that the sample
            interval is always greater than the sampling time.

            Since the minimum value changes depending on configuration, a
            command order dependency exists. You must completely configure
            the measurement before setting the sample timer to minimum,
            or you may generate an error. A complete configuration includes
            such things as math statistics or scaling.

            When using autorange, the minimum value is the recommended value,
            not the absolute minimum value. With autorange enabled, minimum
            value is calculated assuming a single range change will occur
            for every measurement (not multiple ranges, just one range up or
            down per measurement)."""))

        ####################################
        # The array parameter

        self.add_parameter('data_buffer', parameter_class=ArrayMeasurement)

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

        if self.model in ['34465A', '34470A']:
            # Define the extreme aperture time values for the 34465A and 34470A
            utility_freq = self.line_frequency()
            if utility_freq == 50:
                apt_times = {'34465A': [0.3e-3, 2], '34470A': [0.3e-3, 2]}
            elif utility_freq == 60:
                apt_times = {
                    '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."""))

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

        if not silent:
            self.connect_message()
    def __init__(self, parent: 'MS46522B', name: str, channel: int, vna_parameter: str=None,
                 existing_trace_to_bind_to: Optional[str]=None) -> None:
        """
        Args:
            parent: Instrument that this channel is bound to.
            name: Name to use for this channel.
            channel: channel on the VNA to use
            : Name of parameter on the vna that this should
                measure such as S12. If left empty this will fall back to
                `name`.
            existing_trace_to_bind_to: Name of an existing trace on the VNA.
                If supplied try to bind to an existing trace with this name
                rather than creating a new trace.

        """
        n = channel
        self._instrument_channel = channel

        if vna_parameter is None:
            vna_parameter = name
        self._vna_parameter = vna_parameter
        super().__init__(parent, name)

        if existing_trace_to_bind_to is None:
            self._tracename = "Tr{}".format(channel)
        else:
            print('what to do?')
            # traces = self._parent.ask(f"CONFigure:TRACe:CATalog?")
            # if existing_trace_to_bind_to not in traces:
            #     raise RuntimeError(f"Trying to bind to {existing_trace_to_bind_to} "
            #                        f"which is not in {traces}")
            # self._tracename = existing_trace_to_bind_to

        # map hardware channel to measurement
        # hardware channels are mapped one to one to qcodes channels
        # we are not using sub traces within channels.
        # if existing_trace_to_bind_to is None:
        #     self.write("CALC{}:PAR:SDEF '{}', '{}'".format(self._instrument_channel,
        #                                                    self._tracename,
        #                                                    self._vna_parameter))

        # source power is dependent on model, but not well documented.
        # here we assume -60 dBm for ZNB20, the others are set,
        # due to lack of knowledge, to -80 dBm as of before the edit
        # full_modelname = self._parent.get_idn()['model']
        # model: Optional[str]
        # if full_modelname is not None:
        #     model = full_modelname.split('-')[0]
        # else:
        #    raise RuntimeError("Could not determine ZNB model")
        # mSourcePower = {'ZNB4':-80, 'ZNB8':-80, 'ZNB20':-60}
        # if model not in mSourcePower.keys():
        #     raise RuntimeError("Unsupported ZNB model: {}".format(model))
        self._min_source_power: float
        self._min_source_power = -30


        #----------------------------------------------------- start updating

        self.add_parameter(name='vna_parameter',
                           label='VNA parameter',
                           get_cmd="CALC{}:PAR:DEF? '{}'".format(self._instrument_channel,
                                                                  self._tracename),
                           get_parser=self._strip
                           )
        self.add_parameter(name='power',
                           label='Power',
                           unit='dBm',
                           get_cmd='SOUR{}:POW:PORT1?'.format(n),
                           set_cmd='SOUR{}:POW:PORT1 {{:.4f}}'.format(n),
                           get_parser=float,
                           vals=vals.Numbers(self._min_source_power, 30))
        # # there is an 'increased bandwidth option' (p. 4 of manual) that does
        # # not get taken into account here
        self.add_parameter(name='bandwidth',
                           label='Bandwidth',
                           unit='Hz',
                           get_cmd='SENS{}:BWID?'.format(n),
                           set_cmd='SENS{}:BWID {{:.4f}}'.format(n),
                           get_parser=int,
                           vals=vals.Enum(10,20,30,50,70,100, 200, 300,500,700, 1e3,3e3,5e3, 7e3, 10e3, 30e3, 50e3, 70e3, 100e3, 300e3, 500e3  ))
        #
        # self.add_parameter(name='avgstat',
        #                    label='Averagestatus',
        #                    unit='',
        #                    get_cmd='SENS{}:AVER?'.format(n),
        #                    set_cmd='SENS{}:AVER {}'.format(n),
        #                    get_parser=int,
        #                    val_mapping={True: '1\n', False: '0\n'})
        self.add_parameter(name='avg',
                           label='Averages',
                           unit='',
                           get_cmd='SENS{}:AVER:COUN?'.format(n),
                           set_cmd='SENS{}:AVER:COUN {{:.4f}}'.format(n),
                           get_parser=int,
                           vals=vals.Ints(1, 5000))
        self.add_parameter(name='start',
                           get_cmd='SENS{}:FREQ:START?'.format(n),
                           set_cmd=self._set_start,
                           get_parser=float,
                           vals=vals.Numbers(self._parent._min_freq, self._parent._max_freq - 10))
        self.add_parameter(name='stop',
                           get_cmd='SENS{}:FREQ:STOP?'.format(n),
                           set_cmd=self._set_stop,
                           get_parser=float,
                           vals=vals.Numbers(self._parent._min_freq + 1, self._parent._max_freq))
        self.add_parameter(name='center',
                           get_cmd='SENS{}:FREQ:CENT?'.format(n),
                           set_cmd=self._set_center,
                           get_parser=float,
                           vals=vals.Numbers(self._parent._min_freq + 0.5, self._parent._max_freq - 10))
        self.add_parameter(name='span',
                           get_cmd='SENS{}:FREQ:SPAN?'.format(n),
                           set_cmd=self._set_span,
                           get_parser=float,
                           vals=vals.Numbers(1, self._parent._max_freq - self._parent._min_freq))
        self.add_parameter(name='npts',
                           get_cmd='SENS{}:SWE:POIN?'.format(n),
                           set_cmd=self._set_npts,
                           get_parser=int)
        # self.add_parameter(name='status',
        #                    get_cmd='CONF:CHAN{}:MEAS?'.format(n),
        #                    set_cmd='CONF:CHAN{}:MEAS {{}}'.format(n),
        #                    get_parser=int)
        self.add_parameter(name='format',
                           get_cmd=partial(self._get_format, tracename=self._tracename),
                           set_cmd=self._set_format,
                           val_mapping={'dB': 'MLOG\n',
                                        'Linear Magnitude': 'MLIN\n',
                                        'Phase': 'PHAS\n',
                                        'Unwr Phase': 'UPH\n',
                                        'Polar': 'POL\n',
                                        'Smith': 'SMIT\n',
                                        'Inverse Smith': 'ISM\n',
                                        'SWR': 'SWR\n',
                                        'Real': 'REAL\n',
                                        'Imaginary': 'IMAG\n',
                                        'Delay': "GDEL\n",
                                        'Complex': "COMP\n"
                                        })

        self.add_parameter(name='trace_mag_phase',
                           start=self.start(),
                           stop=self.stop(),
                           npts=self.npts(),
                           channel=n,
                           parameter_class=FrequencySweepMagPhase)
        self.add_parameter(name='trace',
                           start=self.start(),
                           stop=self.stop(),
                           npts=self.npts(),
                           channel=n,
                           parameter_class=FrequencySweep)

        self.add_parameter(name='avgcount',
                           label='Average counter',
                           get_cmd=':SENS{}:AVER:SWE?'.format(n) ,
                           get_parser=int
                           )
        self.add_parameter(name='marker1_value',
                           label='Marker 1 value',
                           unit='dB',
                           get_cmd=':CALC:MARK1:Y?',
                           get_parser=float)
        self.add_parameter(name='marker1_frequency',
                           label='Marker 1 Frequency ',
                           unit='Hz',
                           get_cmd=':CALC:MARK1:X?',
                           set_cmd=':CALC:MARK1:X {:.4f}',
                           get_parser=float,
                           set_parser=float,
                           vals=vals.Numbers(100e3, 20e9))

        # self.add_function('autoscale',
        #                   call_cmd='DISPlay:TRACe1:Y:SCALe:AUTO ONCE, "{}"'.format(self._tracename))
        self.add_function('autoscale_all',
                          call_cmd=':DISP:WIND:Y:AUTO')
Пример #17
0
class DacBase(object):
    
    # Switch position values
    SWITCH_LEFT  = -1 # -10 <= U <=  0 [V]
    SWITCH_MID   = 0  #   0 <= U <= 10 [V]
    SWITCH_RIGHT = 1  # -10 <= U <= 10 [V]

    # Slot mode values
    SLOT_MODE_OFF    = 0 # Channel outputs are disconnected from the input, grounded with 10MOhm.
    SLOT_MODE_FINE   = 1 # 2-channel mode. Channels 0 and 1 are output, use 2 and 3 for fine adjustment of Channels 0 and 1 respectively
    SLOT_MODE_COARSE = 2 # All 4 channels are used as output
    
    # Trigger mode values
    TRIG_UPDATE_ALWAYS               = 0
    TRIG_UPDATE_NEVER                = 8
    TRIG_1_UPDATE_IF_LOW             = 2
    TRIG_1_UPDATE_IF_HIGH            = 10
    TRIG_1_UPDATE_UNTIL_RISING_EDGE  = 4
    TRIG_1_UPDATE_UNTIL_FALLING_EDGE = 6
    TRIG_1_UPDATE_AFTER_RISING_EDGE  = 12
    TRIG_1_UDPATE_AFTER_FALLING_EDGE = 14
    TRIG_2_UPDATE_IF_LOW             = 3
    TRIG_2_UPDATE_IF_HIGH            = 11
    TRIG_2_UPDATE_UNTIL_RISING_EDGE  = 5
    TRIG_2_UPDATE_UNTIL_FALLING_EDGE = 7
    TRIG_2_UPDATE_AFTER_RISING_EDGE  = 13
    TRIG_2_UDPATE_AFTER_FALLING_EDGE = 15
    
    # Validators
    _CHANNEL_VAL   = vals.Ints(0, 3)
    _SWITCH_VAL    = vals.Ints(SWITCH_LEFT, SWITCH_RIGHT)
    _MODE_VAL      = vals.Ints(SLOT_MODE_OFF, SLOT_MODE_COARSE)
    _SLOT_VAL      = vals.Ints(0, 4)
    _TRIG_MODE_VAL = vals.Enum(0, 2,3,4,5,6,7,8, 10,11,12,13,14,15) # The trigger modes 1 and 9 are undefined

    # Default values of the parameters
    _DEFAULT_VOLT          = 0
    _DEFAULT_SWITCH_POS    = SWITCH_MID
    _DEFAULT_LOWER_LIMIT   = 0
    _DEFAULT_UPPER_LIMIT   = 65536
    _DEFAULT_UPDATE_PERIOD = 1000
    _DEFAULT_SLOPE         = 0
    _DEFAULT_TRIG_MODE     = TRIG_UPDATE_ALWAYS
    _DEFAULT_SLOT_MODE     = SLOT_MODE_COARSE
    
    # Commands to send to the device
    _COMMAND_SET_SLOT          = "B{};"
    _COMMAND_SET_CHANNEL       = "C{};"
    _COMMAND_SET_VOLT          = "D{};"
    _COMMAND_SET_UPPER_LIMIT   = "U{};"
    _COMMAND_SET_LOWER_LIMIT   = "L{};"
    _COMMAND_SET_TRIG_MODE     = "G{};"
    _COMMAND_SET_SLOPE         = "S{};"
    _COMMAND_SET_UPDATE_PERIOD = "T{};"
    _COMMAND_SET_SLOT_MODE     = "M{};"
    _COMMAND_GET_VOLT          = "d;"
    
    
    @staticmethod
    def _dac_v_to_code(volt, min_volt, max_volt):
        """
        Convert a voltage to the internal dac code (number between 0-65536)
        based on the minimum/maximum values of a given channel.
        Midrange is 32768.
        
        Arguments:
            volt (float): voltage in V to convert
            min_volt (float): minimum voltage
            max_volt (float): maximum voltage
            
        Returns:
            (int): dac-code
        """
        if volt < min_volt or volt > max_volt:
            raise ValueError("Cannot convert voltage {} V to a voltage code, value out of range ({} V - {} V).".format(volt, min_volt, max_volt))

        frac = (volt - min_volt) / (max_volt - min_volt)
        val = int(round(frac * 65535))
        
        # extra check to be absolutely sure that the instrument does nothing
        # receive an out-of-bounds value
        if val > 65535 or val < 0:
            raise ValueError("Voltage ({} V) resulted in the voltage code {}, which is not within the allowed range.".format(volt, val))
        
        return val

    
    @staticmethod
    def _dac_code_to_v(code, min_volt, max_volt):
        """
        Convert the internal dac code (number between 0-65536) to the voltage value
        based on the minimum/maximum values of a given channel.
        
        Arguments:
            code (int): dac-code to convert
            min_volt (float): minimum voltage
            max_volt (float): maximum voltage
            
        Returns:
            (float): voltage in V
        """
        frac = code / 65535.0
        
        return (frac * (max_volt - min_volt)) + min_volt
    
    
    @staticmethod
    def _evaluate_switchpos(pos):
        """
        Returns the minimum and maximum voltages by the switch position
        
        Arguments:
            pos (int): switch position
                       {SWITCH_LEFT = -1, SWITCH_MID = 0, SWITCH_RIGHT = 1}
            
        Returns:
            (float, float): minimum and maximum voltage in V
        """
        min_volt = 0.
        max_volt = 0.
        
        if(pos == DacBase.SWITCH_LEFT):
            min_volt = -10.
        elif(pos == DacBase.SWITCH_MID):
            max_volt = 10.
        elif(pos == DacBase.SWITCH_RIGHT):
            min_volt = -10.
            max_volt = 10.
        else:
            raise ValueError("No valid switch position given.")
        
        return min_volt, max_volt
Пример #18
0
    def __init__(self, name, address, num_chans=48, update_currents=True):
        """
        Instantiates the instrument.

        Args:
            name (str): The instrument name used by qcodes
            address (str): The VISA name of the resource
            num_chans (int): Number of channels to assign. Default: 48
            update_currents (bool): Whether to query all channels for their
                current current value on startup. Default: True.

        Returns:
            QDac object
        """
        super().__init__(name, address)
        handle = self.visa_handle

        # This is the baud rate on power-up. It can be changed later but
        # you must start out with this value.
        handle.baud_rate = 480600
        handle.parity = visa.constants.Parity(0)
        handle.data_bits = 8
        self.set_terminator('\n')
        # TODO: do we want a method for write termination too?
        handle.write_termination = '\n'
        # TODO: do we need a query delay for robust operation?
        self._write_response = ''

        # The following bool is used in self.write
        self.debugmode = False

        if self._get_firmware_version() < 0.170202:
            raise RuntimeError('''
                               Obsolete QDAC Software version detected.
                               QCoDeS only supports version 0.170202 or newer.
                               Contact [email protected] for an update.
                               ''')

        self.num_chans = num_chans

        # Assigned slopes. Entries will eventually be [chan, slope]
        self._slopes = []
        # Function generators (used in _set_voltage)
        self._fgs = set(range(1, 9))
        self._assigned_fgs = {}  # {chan: fg}
        # Sync channels
        self._syncoutputs = []  # Entries: [chan, syncchannel]

        self.chan_range = range(1, 1 + self.num_chans)
        self.channel_validator = vals.Ints(1, self.num_chans)

        for i in self.chan_range:
            stri = str(i)
            self.add_parameter(name='ch{:02}_v'.format(i),
                               label='Channel ' + stri,
                               unit='V',
                               set_cmd=partial(self._set_voltage, i),
                               vals=vals.Numbers(-10, 10),
                               get_cmd=partial(self.read_state, i, 'v')
                               )
            self.add_parameter(name='ch{:02}_vrange'.format(i),
                               set_cmd=partial(self._set_vrange, i),
                               get_cmd=partial(self.read_state, i, 'vrange'),
                               vals=vals.Enum(0, 1)
                               )
            self.add_parameter(name='ch{:02}_irange'.format(i),
                               set_cmd='cur ' + stri + ' {}',
                               get_cmd=partial(self.read_state, i, 'irange')
                               )
            self.add_parameter(name='ch{:02}_i'.format(i),
                               label='Current ' + stri,
                               unit='A',
                               get_cmd='get ' + stri,
                               get_parser=self._current_parser
                               )
            self.add_parameter(name='ch{:02}_slope'.format(i),
                               label='Maximum voltage slope',
                               unit='V/s',
                               set_cmd=partial(self._setslope, i),
                               get_cmd=partial(self._getslope, i),
                               vals=vals.MultiType(vals.Enum('Inf'),
                                                   vals.Numbers(1e-3, 100))
                               )
            self.add_parameter(name='ch{:02}_sync'.format(i),
                               label='Channel {} sync output',
                               set_cmd=partial(self._setsync, i),
                               get_cmd=partial(self._getsync, i),
                               vals=vals.Ints(0, 5)
                               )

            self.add_parameter(name='ch{:02}_sync_delay'.format(i),
                               label='Channel {} sync pulse delay'.format(i),
                               unit='s',
                               parameter_class=ManualParameter,
                               initial_value=0)

            self.add_parameter(name='ch{:02}_sync_duration'.format(i),
                               label='Channel {} sync pulse duration'.format(i),
                               unit='s',
                               parameter_class=ManualParameter,
                               initial_value=0.01)

        for board in range(6):
            for sensor in range(3):
                label = 'Board {}, Temperature {}'.format(board, sensor)
                self.add_parameter(name='temp{}_{}'.format(board, sensor),
                                   label=label,
                                   unit='C',
                                   get_cmd='tem {} {}'.format(board, sensor),
                                   get_parser=self._num_verbose)

        self.add_parameter(name='cal',
                           set_cmd='cal {}',
                           vals=self.channel_validator)
        # TO-DO: maybe it's too dangerous to have this settable.
        # And perhaps ON is a better verbose mode default?
        self.add_parameter(name='verbose',
                           set_cmd='ver {}',
                           val_mapping={True: 1, False: 0})

        # Initialise the instrument, all channels DC (unbind func. generators)
        for chan in self.chan_range:
            # Note: this call does NOT change the voltage on the channel
            self.write('wav {} 0 1 0'.format(chan))

        self.verbose.set(False)
        self.connect_message()
        log.info('[*] Querying all channels for voltages and currents...')
        self._get_status(readcurrents=update_currents)
        log.info('[+] Done')
    def __init__(self, name, **kw):
        logging.info(__name__ + ' : Initializing instrument')
        super().__init__(name, **kw)
        self.add_parameter('QWG', parameter_class=InstrumentParameter)
        self.add_parameter('F_kernel_instr',
                           parameter_class=InstrumentParameter)

        self.add_parameter('F_amp', unit='frac',
                           docstring=('Amplitude of flux pulse as fraction of '
                                      'the peak amplitude. Beware of factor 2'
                                      ' with Vpp in the QWG'),
                           initial_value=0.5,
                           parameter_class=ManualParameter)
        self.add_parameter('F_length', unit='s',
                           parameter_class=ManualParameter,
                           initial_value=200e-9)
        self.add_parameter('F_ch', label='Flux channel',
                           vals=vals.Ints(),
                           parameter_class=ManualParameter)
        self.add_parameter('F_delay', label='Flux pulse delay',
                           unit='s',
                           initial_value=0,
                           vals=vals.Numbers(),
                           parameter_class=ManualParameter)
        self.add_parameter('F_compensation_delay',
                           label='compens. pulse delay',
                           unit='s',
                           initial_value=4e-6,
                           vals=vals.Numbers(),
                           parameter_class=ManualParameter)
        self.add_parameter('F_lambda_1',
                           docstring='first lambda coef. for martinis pulse',
                           label='Lambda_1',
                           unit='',
                           initial_value=0,
                           vals=vals.Numbers(),
                           parameter_class=ManualParameter)
        self.add_parameter('F_lambda_2',
                           docstring='second lambda coef. for martinis pulse',
                           label='Lambda_2',
                           unit='',
                           initial_value=0,
                           vals=vals.Numbers(),
                           parameter_class=ManualParameter)
        self.add_parameter('F_lambda_3',
                           docstring='third lambda coef. for martinis pulse',
                           label='Lambda_3',
                           unit='',
                           initial_value=0,
                           vals=vals.Numbers(),
                           parameter_class=ManualParameter)
        self.add_parameter('F_theta_f',
                           docstring='theta_f for martinis pulse',
                           label='theta_f',
                           unit='deg',
                           initial_value=90,
                           vals=vals.Numbers(),
                           parameter_class=ManualParameter)
        self.add_parameter('F_J2',
                           docstring='coupling between 11-02',
                           label='J2',
                           unit='Hz',
                           initial_value=10e6,
                           vals=vals.Numbers(),
                           parameter_class=ManualParameter)
        self.add_parameter('F_f_interaction',
                           label='interaction frequency',
                           unit='Hz',
                           initial_value=5e9,
                           vals=vals.Numbers(),
                           parameter_class=ManualParameter)
        self.add_parameter('F_dac_flux_coef',
                           docstring='conversion factor AWG voltage to flux',
                           label='dac flux coef',
                           unit='(V^-1)',
                           initial_value=1.0,
                           vals=vals.Numbers(),
                           parameter_class=ManualParameter)
        self.add_parameter('F_E_c',
                           label='qubit E_c',
                           unit='Hz',
                           initial_value=250e6,
                           vals=vals.Numbers(),
                           parameter_class=ManualParameter)
        self.add_parameter('F_f_01_max',
                           label='sweet spot freq',
                           unit='Hz',
                           initial_value=6e9,
                           vals=vals.Numbers(),
                           parameter_class=ManualParameter)
        self.add_parameter('F_asymmetry',
                           label='qubit asymmetry',
                           unit='Hz',
                           initial_value=0.0,
                           vals=vals.Numbers(),
                           parameter_class=ManualParameter)
        self.add_parameter('codeword_dict',
                           docstring='Dict assigning codewords to pulses',
                           label='codeword dict',
                           unit='',
                           initial_value={},
                           vals=vals.Anything(),
                           parameter_class=ManualParameter)
        self.add_parameter('sampling_rate',
                           docstring='Sampling rate of the QWG',
                           label='sampling rate',
                           unit='Hz',
                           initial_value=1.0e9,
                           vals=vals.Numbers(),
                           parameter_class=ManualParameter)
        self.add_parameter('Z_length',
                           docstring=('Duration of single qubit Z pulse in'
                                      ' seconds'),
                           label='Z length',
                           unit='s',
                           initial_value=10e-9,
                           vals=vals.Numbers(),
                           parameter_class=ManualParameter)
        self.add_parameter('Z_amp',
                           docstring=('Amplitude of the single qubit phase '
                                      'correction in CZ pulses.'),
                           label='Z amplitude',
                           unit='frac',
                           initial_value=0.0,
                           vals=vals.Numbers(),
                           parameter_class=ManualParameter)
        self.add_parameter('Z_amp_grover',
                           docstring=('Amplitude of the single qubit phase '
                                      'correction for the second CZ pulse '
                                      "used in Grover's algorithm."),
                           label='Z amplitude 2',
                           unit='frac',
                           initial_value=0.0,
                           vals=vals.Numbers(),
                           parameter_class=ManualParameter)

        self.add_parameter('max_waveform_length', unit='s',
                           parameter_class=ManualParameter,
                           initial_value=30e-6)
        self.add_parameter('codeword_channels',
                           parameter_class=ManualParameter,
                           docstring='Channels used for triggering specific '
                                     'codewords.',
                           vals=vals.Lists(vals.Ints()))

        self.add_parameter('disable_CZ',
                           parameter_class=ManualParameter,
                           vals=vals.Bool(),
                           initial_value=False)
        self.add_parameter('pulse_map',
                           initial_value={'cz': 'adiabatic_Z',
                                          'cz_grover': 'adiabatic_Z_grover',
                                          'square': 'square'},
                           parameter_class=ManualParameter,
                           vals=vals.Dict())
        self.add_parameter('wave_dict_unit',
                           get_cmd=self._get_wave_dict_unit,
                           set_cmd=self._set_wave_dict_unit,
                           docstring='Unit in which the waveforms are '
                           'specified.\n'
                           '"frac" means "fraction of the maximum QWG '
                           'range".\n'
                           '"V" means volts.',
                           vals=vals.Enum('frac', 'V'))
        self._wave_dict_unit = 'frac'  # Initial value for wave_dict_unit
        self.add_parameter('V_offset',
                           unit='V',
                           label='V offset',
                           docstring='pulsed sweet spot offset',
                           parameter_class=ManualParameter,
                           initial_value=0,
                           vals=vals.Numbers())
        self.add_parameter('V_per_phi0',
                           unit='V',
                           label='V per phi_0',
                           docstring='pulsed voltage required for one phi0 '
                                     'of flux',
                           parameter_class=ManualParameter,
                           initial_value=1,
                           vals=vals.Numbers())
        self.add_parameter('S_gauss_sigma',
                           unit='s',
                           label='gauss sigma',
                           docstring='Width (sigma) of Gaussian shaped flux '
                                     'pulse.',
                           parameter_class=ManualParameter,
                           initial_value=40e-9,
                           vals=vals.Numbers())
        self.add_parameter('S_amp',
                           unit='frac',
                           label='S_amp',
                           docstring='Amplitude of scoping flux pulse.',
                           parameter_class=ManualParameter,
                           initial_value=0.5,
                           vals=vals.Numbers())

        self._wave_dict = {}
Пример #20
0
    def __init__(self, name, Current_source_magnet_Z_name,
                 Current_source_heater_Z_name, Current_source_magnet_Y_name,
                 Current_source_heater_Y_name, MC_inst, **kw):  # IVVI.dac1
        super().__init__(name, **kw)

        self.protection_state = False
        # Set instrumentss
        self.add_parameter('i_magnet_z', parameter_class=InstrumentParameter)
        self.i_magnet_z = Current_source_magnet_Z_name
        self.add_parameter('i_heater_z', parameter_class=InstrumentParameter)
        self.i_heater_z = Current_source_heater_Z_name
        self.add_parameter('i_magnet_y', parameter_class=InstrumentParameter)
        self.i_magnet_y = Current_source_magnet_Y_name
        self.add_parameter('i_heater_y', parameter_class=InstrumentParameter)
        self.i_heater_y = Current_source_heater_Y_name
        self.MC = MC_inst
        # Specifications of One Axis AMI magnet with PCS_14768

        self.max_current_z = 10.0  # 5.0 # Amperes
        self.max_current_y = 10.0  # Amperes
        self.field_to_current_z = 0.0496  # Telsa/Ampere
        #   (Spec sheet says 0.496 kG/A = 49.6 mT/A)
        self.field_to_current_y = 0.0132  # Telsa/Ampere
        #   (Spec sheet says 0.132 kG/A = 13.2 mT/A)
        self.max_field_z = self.max_current_z * self.field_to_current_z  # Tesla
        #(Spec sheet says 20 kG = 2.0 T)
        self.max_field_y = self.max_current_y * self.field_to_current_y  # Tesla
        #(Spec sheet says 5 kG = 0.5 T)
        # self.Ramp_Rate = 0.05 # Ampere/Second
        self.step_grid_points_mag = 1e-3  # zig-zag step size in mT
        self.max_ramp_rate_z = 0.1  # Max ramp rate: 0.677 # Ampere/Second
        self.max_ramp_rate_y = 0.1  # Max ramp rate: 0.054 # Ampere/Second
        self.init_ramp_rate_z = 0.025
        self.init_ramp_rate_y = 0.1
        self.charging_voltage_z = 0.5  # Volt
        self.charging_voltage_y = 0.1  # Volt
        self.inductance_z = 0.7  # Henry
        self.inductance_y = 1.8  # Henry
        self.persistent_switch_heater_current_z = 19e-3  # Ampere (19 mA)
        self.persistent_switch_heater_current_y = 19.7e-3  # Ampere (19.7 mA)
        self.heater_mvolt_to_current_z = 0.020 * 1e-3  # A/mV (20 mA per 1000 mV)
        self.heater_mvolt_to_current_y = 0.020 * 1e-3  # A/mV (20 mA per 1000 mV)
        self.persistent_switch_heater_nominal_resistance_z = 78  # Ohms
        #(Measured at room temperature, thus normal conducing.)
        self.persistent_switch_heater_nominal_resistance_y = 81  # Ohms
        #(Measured at room temperature, thus normal conducing.)
        self.magnet_resistanc_in_parallel_with_switch_z = 36  # Ohms
        #(Measured at room temperature, thus normal conducting.)
        self.magnet_resistanc_in_parallel_with_switch_y = 37  # Ohms
        #(Measured at room temperature, thus normal conducting.)

        self.add_parameter(
            'source_current_z',
            get_cmd=self.get_source_current_z,
            set_cmd=self.set_source_current_z,
            label='Source Current Z',
            unit='A',
            vals=vals.Numbers(min_value=0., max_value=self.max_current_z),
            docstring='Current supplied to the Z-axis of the magnet')
        self.add_parameter(
            'source_current_y',
            get_cmd=self.get_source_current_y,
            set_cmd=self.set_source_current_y,
            label='Source Current Y',
            unit='A',
            vals=vals.Numbers(min_value=0., max_value=self.max_current_y),
            docstring='Current supplied to the Y-axis of the magnet')
        #ramp rate should not be a parameter
        self.add_parameter(
            'ramp_rate_z',
            label='Ramp Rate Z',
            unit='A/s',
            initial_value=self.init_ramp_rate_z,
            get_parser=float,
            vals=vals.Numbers(min_value=0., max_value=self.max_ramp_rate_z),
            parameter_class=ManualParameter,
            docstring='Ramp Rate of the Z-axis magnet current source')
        self.add_parameter(
            'ramp_rate_y',
            label='Ramp Rate Y',
            unit='A/s',
            initial_value=self.init_ramp_rate_y,
            get_parser=float,
            vals=vals.Numbers(min_value=0., max_value=self.max_ramp_rate_y),
            parameter_class=ManualParameter,
            docstring='Ramp Rate of the Y-axis magnet current source')
        self.add_parameter(
            'field',
            get_cmd=self.get_field,
            set_cmd=self.set_field,
            label='Persistent Field',
            unit='T',
            # vals=vals.Numbers(min_value=0.,max_value=min(self.max_field_y,self.max_field_z)),
            vals=vals.Numbers(min_value=0.,
                              max_value=max(self.max_field_y,
                                            self.max_field_z)),
            docstring='Persistent absolute magnetic field')
        self.add_parameter('angle',
                           get_cmd=self.get_angle,
                           set_cmd=self.set_angle,
                           label='Field angle',
                           unit='deg',
                           vals=vals.Numbers(min_value=-180., max_value=180.),
                           docstring='Angle of the field wrt. Z-axis')
        self.add_parameter('field_z',
                           get_cmd=self.get_field_z,
                           set_cmd=self.set_field_z,
                           label='Z-Field',
                           unit='T',
                           vals=vals.Numbers(min_value=0.,
                                             max_value=self.max_field_z),
                           docstring='Persistent Z-magnetic field')
        self.add_parameter('field_y',
                           get_cmd=self.get_field_y,
                           set_cmd=self.set_field_y,
                           label='Y-Field',
                           unit='T',
                           vals=vals.Numbers(min_value=-self.max_field_y,
                                             max_value=self.max_field_y),
                           docstring='Persistent Y-magnetic field')
        # It would be great if the variable field could only be
        # set by the program, not by the user. It should only serve as a memory
        # of the previous persistent field.
        self.add_parameter(
            'switch_state_z',
            get_cmd=self.get_switch_state_z,
            set_cmd=self.set_switch_state_z,
            label='Switch State Z',
            unit='',
            vals=vals.Enum('SuperConducting', 'NormalConducting'),
            docstring='Indicating whether the Z-Axis persistent current\
                               switch is superconducting or normal conducting')
        self.add_parameter(
            'switch_state_y',
            get_cmd=self.get_switch_state_y,
            set_cmd=self.set_switch_state_y,
            label='Switch State Y',
            unit='',
            vals=vals.Enum('SuperConducting', 'NormalConducting'),
            docstring='Indicating whether the Y-Axis persistent current\
                               switch is superconducting or normal conducting')

        self.protection_state = True

        self.get_all()
        '''
Пример #21
0
    def __init__(self, parent: Instrument, name: str, channum: int) -> None:
        """
        Args:
            parent: The instrument to which the channel is attached
            name: The name of the channel
            channum: The number of the channel in question. Must match the
                actual number as used by the instrument (1..4)
        """

        if channum not in [1, 2, 3, 4]:
            raise ValueError('Invalid channel number! Must be 1, 2, 3, or 4.')

        self.channum = channum

        super().__init__(parent, name)

        self.add_parameter('state',
                           label='Channel {} state'.format(channum),
                           get_cmd='CHANnel{}:STATe?'.format(channum),
                           set_cmd='CHANnel{}:STATE {{}}'.format(channum),
                           vals=vals.Enum('ON', 'OFF'),
                           docstring='Switches the channel on or off')

        self.add_parameter('coupling',
                           label='Channel {} coupling'.format(channum),
                           get_cmd='CHANnel{}:COUPling?'.format(channum),
                           set_cmd='CHANnel{}:COUPling {{}}'.format(channum),
                           vals=vals.Enum('DC', 'DCLimit', 'AC'),
                           docstring=('Selects the connection of the channel'
                                      'signal. DC: 50 Ohm, DCLimit 1 MOhm, '
                                      'AC: Con. through DC capacitor'))

        self.add_parameter('ground',
                           label='Channel {} ground'.format(channum),
                           get_cmd='CHANnel{}:GND?'.format(channum),
                           set_cmd='CHANnel{}:GND {{}}'.format(channum),
                           vals=vals.Enum('ON', 'OFF'),
                           docstring=('Connects/disconnects the signal to/from'
                                      'the ground.'))

        # NB (WilliamHPNielsen): This parameter depends on other parameters and
        # should be dynamically updated accordingly. Cf. p 1178 of the manual
        self.add_parameter(
            'scale',
            label='Channel {} Y scale'.format(channum),
            unit='V/div',
            get_cmd='CHANnel{}:SCALe?'.format(channum),
            set_cmd=self._set_scale,
            get_parser=float,
        )

        self.add_parameter('range',
                           label='Channel {} Y range'.format(channum),
                           unit='V',
                           get_cmd='CHANnel{}:RANGe?'.format(channum),
                           set_cmd=self._set_range,
                           get_parser=float)

        # TODO (WilliamHPNielsen): would it be better to recast this in terms
        # of Volts?
        self.add_parameter('position',
                           label='Channel {} vert. pos.'.format(channum),
                           unit='div',
                           get_cmd='CHANnel{}:POSition?'.format(channum),
                           set_cmd='CHANnel{}:POSition {{}}'.format(channum),
                           get_parser=float,
                           vals=vals.Numbers(-5, 5),
                           docstring=('Positive values move the waveform up,'
                                      ' negative values move it down.'))

        self.add_parameter(
            'offset',
            label='Channel {} offset'.format(channum),
            unit='V',
            get_cmd='CHANnel{}:OFFSet?'.format(channum),
            set_cmd='CHANnel{}:OFFSet {{}}'.format(channum),
            get_parser=float,
        )

        self.add_parameter('invert',
                           label='Channel {} inverted'.format(channum),
                           get_cmd='CHANnel{}:INVert?'.format(channum),
                           set_cmd='CHANnel{}:INVert {{}}'.format(channum),
                           vals=vals.Enum('ON', 'OFF'))

        # TODO (WilliamHPNielsen): This parameter should be dynamically
        # validated since 800 MHz BW is only available for 50 Ohm coupling
        self.add_parameter('bandwidth',
                           label='Channel {} bandwidth'.format(channum),
                           get_cmd='CHANnel{}:BANDwidth?'.format(channum),
                           set_cmd='CHANnel{}:BANDwidth {{}}'.format(channum),
                           vals=vals.Enum('FULL', 'B800', 'B200', 'B20'))

        self.add_parameter('impedance',
                           label='Channel {} impedance'.format(channum),
                           unit='Ohm',
                           get_cmd='CHANnel{}:IMPedance?'.format(channum),
                           set_cmd='CHANnel{}:IMPedance {{}}'.format(channum),
                           vals=vals.Ints(1, 100000),
                           docstring=('Sets the impedance of the channel '
                                      'for power calculations and '
                                      'measurements.'))

        self.add_parameter('overload',
                           label='Channel {} overload'.format(channum),
                           get_cmd='CHANnel{}:OVERload?'.format(channum))

        self.add_parameter(
            'arithmetics',
            label='Channel {} arithmetics'.format(channum),
            set_cmd='CHANnel{}:ARIThmetics {{}}'.format(channum),
            get_cmd='CHANnel{}:ARIThmetics?'.format(channum),
            val_mapping={
                'AVERAGE': 'AVER',
                'OFF': 'OFF',
                'ENVELOPE': 'ENV'
            })

        #########################
        # Trace

        self.add_parameter('trace',
                           channum=self.channum,
                           parameter_class=ScopeTrace)

        self._trace_ready = False
Пример #22
0
    def __init__(self, parent: '_Keysight_344xxA', name: str, **kwargs):
        super(Sample, self).__init__(parent, name, **kwargs)

        if self.parent.is_34465A_34470A:
            _max_sample_count = 1e9
        else:
            _max_sample_count = 1e6

        self.add_parameter('count',
                           label='Sample Count',
                           set_cmd='SAMPle:COUNt {}',
                           get_cmd='SAMPle:COUNt?',
                           vals=vals.MultiType(
                               vals.Numbers(1, _max_sample_count),
                               vals.Enum('MIN', 'MAX', 'DEF')),
                           get_parser=int,
                           docstring=textwrap.dedent("""\
            Specifies the number of measurements (samples) the instrument 
            takes per trigger.

            MAX selects 1 billion readings. However, when pretrigger is 
            selected, the maximum is 50,000 readings (without the MEM 
            option) or 2,000,000 readings (with the MEM option)"""))

        if self.parent.has_DIG:
            self.add_parameter('pretrigger_count',
                               label='Sample Pretrigger Count',
                               set_cmd='SAMPle:COUNt:PRETrigger {}',
                               get_cmd='SAMPle:COUNt:PRETrigger?',
                               vals=vals.MultiType(
                                   vals.Numbers(0, 2e6 - 1),
                                   vals.Enum('MIN', 'MAX', 'DEF')),
                               get_parser=int,
                               docstring=textwrap.dedent("""\
                Allows collection of the data being digitized the trigger. 
                Reserves memory for pretrigger samples up to the specified 
                num. of pretrigger samples."""))

        if self.parent.is_34465A_34470A:
            self.add_parameter('source',
                               label='Sample Timing Source',
                               set_cmd='SAMPle:SOURce {}',
                               get_cmd='SAMPle:SOURce?',
                               vals=vals.Enum('IMM', 'TIM'),
                               docstring=('Determines sampling time, '
                                          'immediate or using `sample.timer`'))

        self.add_parameter('timer',
                           label='Sample Timer',
                           set_cmd='SAMPle:TIMer {}',
                           get_cmd='SAMPle:TIMer?',
                           unit='s',
                           vals=vals.MultiType(vals.Numbers(0, 3600),
                                               vals.Enum('MIN', 'MAX', 'DEF')),
                           get_parser=float,
                           docstring=textwrap.dedent("""\
            The value is rounded by the instrument to the nearest step. For DC 
            measurements, the step size is 1 µs. For AC measurements, 
            it is AC bandwidth dependent.

            Special values are: MIN - recommended minimum, MAX - maximum, 
            DEF - default. In order to obtain the actual value of the 
            parameter that gets set when setting it to one of these special 
            values, just call the get method of the parameter, or use 
            corresponding parameters in this driver, 
            like `sample.timer_minimum`.

            Specifying a value that is between the absolute minimum (assumes 
            no range changes) and the recommended minimum value, 
            may generate a timing violation error when making measurements.

            Applying a value less than the absolute minimum will generate an 
            error."""))

        self.add_parameter('timer_minimum',
                           label='Minimal recommended sample time',
                           get_cmd='SAMPle:TIMer? MIN',
                           get_parser=float,
                           unit='s',
                           docstring=textwrap.dedent("""\
            This value is measurement dependent. It depends on such things 
            as the integration time, autozero on or off, autorange on or 
            off, and the measurement range. Basically, the minimum is 
            automatically determined by the instrument so that the sample 
            interval is always greater than the sampling time.

            Since the minimum value changes depending on configuration, a 
            command order dependency exists. You must completely configure 
            the measurement before setting the sample timer to minimum, 
            or you may generate an error. A complete configuration includes 
            such things as math statistics or scaling.

            When using autorange, the minimum value is the recommended value, 
            not the absolute minimum value. With autorange enabled, minimum 
            value is calculated assuming a single range change will occur 
            for every measurement (not multiple ranges, just one range up or 
            down per measurement)."""))
Пример #23
0
    def __init__(self, parent: '_Keysight_344xxA', name: str, **kwargs):
        super(Trigger, self).__init__(parent, name, **kwargs)

        if self.parent.is_34465A_34470A:
            _max_trigger_count = 1e9
        else:
            _max_trigger_count = 1e6

        self.add_parameter('count',
                           label='Trigger Count',
                           set_cmd='TRIGger:COUNt {}',
                           get_cmd='TRIGger:COUNt?',
                           get_parser=float,
                           vals=vals.MultiType(
                               vals.Numbers(1, _max_trigger_count),
                               vals.Enum('MIN', 'MAX', 'DEF', 'INF')),
                           docstring=textwrap.dedent("""\
            Selects the number of triggers that are accepted by the 
            instrument before returning to the "idle" trigger state.

            You can use the specified trigger count in conjunction with 
            `sample_count`. In this case, the number of measurements 
            returned is the sample count multiplied by the trigger count.

            A variable trigger count is not available from the front panel. 
            However, when you return to remote control of the instrument, 
            the trigger count returns to the previous value you selected."""))

        self.add_parameter('delay',
                           label='Trigger Delay',
                           unit='s',
                           set_cmd='TRIGger:DELay {}',
                           get_cmd='TRIGger:DELay?',
                           vals=vals.MultiType(vals.Numbers(0, 3600),
                                               vals.Enum('MIN', 'MAX', 'DEF')),
                           get_parser=float,
                           docstring=textwrap.dedent("""\
            Sets the delay between the trigger signal and the first 
            measurement. This may be useful in applications where you want 
            to allow the input to settle before taking a measurement or for 
            pacing a burst of measurements.

            Step size for DC measurements is approximately 1 µs. For AC 
            measurements, step size depends on AC bandwidth.

            Selecting a specific trigger delay disables the automatic 
            trigger delay."""))

        self.add_parameter('auto_delay_enabled',
                           label='Auto Trigger Delay Enabled',
                           set_cmd='TRIGger:DELay:AUTO {}',
                           get_cmd='TRIGger:DELay:AUTO?',
                           get_parser=int,
                           val_mapping={
                               True: 1,
                               False: 0
                           },
                           docstring=textwrap.dedent("""\
            Disables or enables automatic trigger delay. If enabled, 
            the instrument determines the delay based on function, range, 
            and integration time or bandwidth.

            Selecting a specific trigger delay using `trigger.delay` disables 
            the automatic trigger delay."""))

        self.add_parameter('slope',
                           label='Trigger Slope',
                           set_cmd='TRIGger:SLOPe {}',
                           get_cmd='TRIGger:SLOPe?',
                           vals=vals.Enum('POS', 'NEG'))

        if self.parent.is_34465A_34470A and self.parent.has_DIG:
            self.add_parameter('level',
                               label='Trigger Level',
                               unit='V',
                               set_cmd='TRIGger:LEVel {}',
                               get_cmd='TRIGger:LEVel?',
                               get_parser=float,
                               vals=vals.MultiType(
                                   vals.Numbers(-1000, 1000),
                                   vals.Enum('MIN', 'MAX', 'DEF')),
                               docstring=textwrap.dedent("""\
                Sets the level on which a trigger occurs when level 
                triggering is enabled (`trigger.source` set to "INT").

                Note that for 100 mV to 100 V ranges and autorange is off, 
                the trigger level can only be set within ±120% of the 
                range."""))

        _trigger_source_docstring = textwrap.dedent("""\
            Selects the trigger source for measurements.

            IMMediate: The trigger signal is always present. When you place 
                the instrument in the "wait-for-trigger" state, the trigger is 
                issued immediately.

            BUS: The instrument is triggered by `trigger.force` method of this 
                driver once the DMM is in the "wait-for-trigger" state.

            EXTernal: The instrument accepts hardware triggers applied to 
                the rear-panel Ext Trig input and takes the specified number 
                of measurements (`sample_count`), each time a TTL pulse 
                specified by `trigger.slope` is received. If the 
                instrument receives an external trigger before it is ready, 
                it buffers one trigger.""")
        _trigger_source_vals = vals.Enum('IMM', 'EXT', 'BUS')

        if self.parent.is_34465A_34470A and self.parent.has_DIG:
            _trigger_source_vals = vals.Enum('IMM', 'EXT', 'BUS', 'INT')
            # extra empty lines are needed for readability of the docstring
            _trigger_source_docstring += textwrap.dedent("""\


            INTernal: Provides level triggering capability. To trigger on a 
                level on the input signal, select INTernal for the source, 
                and set the level and slope with the `trigger.level` and 
                `trigger.slope` parameters.""")

        self.add_parameter('source',
                           label='Trigger Source',
                           set_cmd='TRIGger:SOURce {}',
                           get_cmd='TRIGger:SOURce?',
                           vals=_trigger_source_vals,
                           docstring=_trigger_source_docstring)
    def __init__(self, name, **kw):
        super(CBox_driven_transmon, self).__init__(name, **kw)
        # Change this when inheriting directly from Transmon instead of
        # from CBox driven Transmon.

        # Adding instrument parameters
        self.add_parameter('LO', parameter_class=InstrumentParameter)
        self.add_parameter('cw_source', parameter_class=InstrumentParameter)
        self.add_parameter('td_source', parameter_class=InstrumentParameter)
        self.add_parameter('IVVI', parameter_class=InstrumentParameter)
        self.add_parameter('FluxCtrl', parameter_class=InstrumentParameter)

        self.add_parameter('AWG', parameter_class=InstrumentParameter)

        self.add_parameter('heterodyne_instr',
                           parameter_class=InstrumentParameter)

        self.add_parameter('LutMan', parameter_class=InstrumentParameter)
        self.add_parameter('CBox', parameter_class=InstrumentParameter)
        self.add_parameter('MC', parameter_class=InstrumentParameter)

        self.add_parameter('RF_RO_source',
                           parameter_class=InstrumentParameter)

        self.add_parameter('mod_amp_cw', label='RO modulation ampl cw',
                           unit='V', initial_value=0.5,
                           parameter_class=ManualParameter)

        self.add_parameter('RO_power_cw', label='RO power cw',
                           unit='dBm',
                           parameter_class=ManualParameter)

        self.add_parameter('spec_pow', label='spectroscopy power',
                           unit='dBm',
                           parameter_class=ManualParameter)
        self.add_parameter('spec_pow_pulsed',
                           label='pulsed spectroscopy power',
                           unit='dBm',
                           parameter_class=ManualParameter)
        self.add_parameter('td_source_pow',
                           label='Time-domain power',
                           unit='dBm',
                           parameter_class=ManualParameter)

        self.add_parameter('spec_pulse_type', label='Pulsed spec pulse type',
                           parameter_class=ManualParameter,
                           initial_value='SquarePulse',
                           vals=vals.Enum('SquarePulse'))  # , SSB_DRAG_pulse))
        # we should also implement SSB_DRAG_pulse for pulsed spec
        self.add_parameter('spec_pulse_length',
                           label='Pulsed spec pulse duration',
                           unit='s',
                           vals=vals.Numbers(1e-9, 20e-6),
                           parameter_class=ManualParameter)
        self.add_parameter('spec_pulse_marker_channel',
                           unit='s',
                           vals=vals.Strings(),
                           parameter_class=ManualParameter)
        self.add_parameter('spec_pulse_depletion_time',
                           unit='s',
                           vals=vals.Numbers(1e-9, 50e-6),
                           parameter_class=ManualParameter)

        # Rename f_RO_mod
        # Time-domain parameters
        self.add_parameter('pulse_I_channel', initial_value='ch1',
                           vals=vals.Strings(),
                           parameter_class=ManualParameter)
        self.add_parameter('pulse_Q_channel', initial_value='ch2',
                           vals=vals.Strings(),
                           parameter_class=ManualParameter)
        self.add_parameter('pulse_I_offset', initial_value=0.0,
                           vals=vals.Numbers(min_value=-0.1, max_value=0.1),
                           parameter_class=ManualParameter)
        self.add_parameter('pulse_Q_offset', initial_value=0.0,
                           vals=vals.Numbers(min_value=-0.1, max_value=0.1),
                           parameter_class=ManualParameter)
        # readout parameters for time domain
        self.add_parameter('RO_acq_averages', initial_value=1024,
                           vals=vals.Numbers(min_value=0, max_value=1e6),
                           parameter_class=ManualParameter)
        self.add_parameter('RO_acq_integration_length', initial_value=1e-6,
                           vals=vals.Numbers(
                               min_value=10e-9, max_value=1000e-6),
                           parameter_class=ManualParameter)
        self.add_parameter('RO_acq_weight_function_I', initial_value=0,
                           vals=vals.Ints(0, 5),
                           parameter_class=ManualParameter)
        self.add_parameter('RO_acq_weight_function_Q', initial_value=1,
                           vals=vals.Ints(0, 5),
                           parameter_class=ManualParameter)
        # These parameters are only relevant if using MW_IQmod_pulse type
        # RO
        self.add_parameter('RO_I_channel', initial_value='ch3',
                           vals=vals.Strings(),
                           parameter_class=ManualParameter)
        self.add_parameter('RO_Q_channel', initial_value='ch4',
                           vals=vals.Strings(),
                           parameter_class=ManualParameter)
        self.add_parameter('RO_I_offset', initial_value=0.0,
                           vals=vals.Numbers(min_value=-0.1, max_value=0.1),
                           parameter_class=ManualParameter)
        self.add_parameter('RO_Q_offset', initial_value=0.0,
                           vals=vals.Numbers(min_value=-0.1, max_value=0.1),
                           parameter_class=ManualParameter)

        self.add_parameter('RO_pulse_type', initial_value='MW_IQmod_pulse_tek',
                           vals=vals.Enum('MW_IQmod_pulse_tek',
                                          'MW_IQmod_pulse_UHFQC',
                                          'Gated_MW_RO_pulse'),
                           parameter_class=ManualParameter)
        # Relevant when using a marker channel to gate a MW-RO tone.
        self.add_parameter('RO_pulse_marker_channel',
                           vals=vals.Strings(),
                           parameter_class=ManualParameter)
        self.add_parameter('RO_pulse_power', unit='dBm',
                           parameter_class=ManualParameter)

        self.add_parameter('f_pulse_mod',
                           initial_value=-100e6,
                           label='pulse-modulation frequency', unit='Hz',
                           parameter_class=ManualParameter)
        self.add_parameter('f_RO_mod',
                           label='Readout-modulation frequency', unit='Hz',
                           initial_value=-2e7,
                           parameter_class=ManualParameter)

        self.add_parameter('amp180',
                           label='Pi-pulse amplitude', unit='V',
                           initial_value=.25,
                           vals=vals.Numbers(min_value=-2.25, max_value=2.25),
                           parameter_class=ManualParameter)
        self.add_parameter('amp90_scale',
                           label='pulse amplitude scaling factor', unit='',
                           initial_value=.5,
                           vals=vals.Numbers(min_value=0, max_value=1.0),
                           parameter_class=ManualParameter)
        self.add_parameter('gauss_sigma', unit='s',
                           initial_value=10e-9,
                           parameter_class=ManualParameter)
        self.add_parameter('motzoi', label='Motzoi parameter', unit='',
                           initial_value=0,
                           parameter_class=ManualParameter)

        self.add_parameter('phi_skew', label='IQ phase skewness', unit='deg',
                           vals=vals.Numbers(-180, 180),
                           initial_value=0,
                           parameter_class=ManualParameter)
        self.add_parameter('alpha', label='QI amplitude skewness', unit='',
                           vals=vals.Numbers(.1, 2),
                           initial_value=1,
                           parameter_class=ManualParameter)

        # Single shot readout specific parameters
        self.add_parameter('RO_threshold', unit='dac-value',
                           initial_value=0,
                           parameter_class=ManualParameter)
        # CBox specific parameter
        self.add_parameter('signal_line', parameter_class=ManualParameter,
                           vals=vals.Enum(0, 1), initial_value=0)
        self.add_parameter('acquisition_instr',
                           set_cmd=self._do_set_acquisition_instr,
                           get_cmd=self._do_get_acquisition_instr,
                           vals=vals.Strings())

        self.add_parameter('flux_pulse_buffer',
                           label='Flux pulse buffer', unit='s',
                           initial_value=0.,
                           vals=vals.Numbers(min_value=0., max_value=50e-6),
                           parameter_class=ManualParameter)
        self.add_parameter('fluxing_channel', initial_value='ch1',
                           vals=vals.Strings(),
                           parameter_class=ManualParameter)
        self.add_parameter('fluxing_amp',
                           label='SWAP resolution', unit='V',
                           initial_value=.5,
                           vals=vals.Numbers(min_value=-1., max_value=1.),
                           parameter_class=ManualParameter)
        self.add_parameter('SWAP_amp',
                           label='SWAP amplitude', unit='V',
                           initial_value=0.02,
                           vals=vals.Numbers(min_value=0.02, max_value=4.5),
                           parameter_class=ManualParameter)
        self.add_parameter('SWAP_time',
                           label='SWAP Time', unit='s',
                           initial_value=0.,
                           vals=vals.Numbers(min_value=0., max_value=1e-6),
                           parameter_class=ManualParameter)
        self.add_parameter('flux_dead_time',
                           label='Time between flux pulse and comp.', unit='s',
                           initial_value=0.,
                           vals=vals.Numbers(min_value=0., max_value=50e-6),
                           parameter_class=ManualParameter)
        self.add_parameter('mw_to_flux_delay',
                           label='time between and mw pulse and start of flux pulse', unit='s',
                           initial_value=0.,
                           vals=vals.Numbers(min_value=0., max_value=50e-6),
                           parameter_class=ManualParameter)
        self.add_parameter('dist_dict',
                           get_cmd=self.get_dist_dict,
                           set_cmd=self.set_dist_dict,
                           vals=vals.Anything())
Пример #25
0
    def __init__(self,
                 name: str,
                 address: str,
                 silent: bool = False,
                 **kwargs):
        """
        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']

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

        self.has_DIG = 'DIG' in self._licenses()

        PLCs = {
            '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']

        ranges = {
            '34460A': [10**n for n in range(-3, 9)],  # 1 m to 100 M
            '34461A': [10**n for n in range(-3, 9)],  # 1 m to 100 M
            '34465A': [10**n for n in range(-3, 10)],  # 1 m to 1 G
            '34470A': [10**n for n in range(-3, 10)],  # 1 m to 1 G
        }

        # The resolution factor order matches the order of PLCs
        res_factors = {
            '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 = ranges[self.model]
        self.NPLC_list = PLCs[self.model]

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

        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:
            # Define the extreme aperture time values for the 34465A and 34470A
            utility_freq = self.line_frequency()
            if utility_freq == 50:
                apt_times = {'34465A': [0.3e-3, 2], '34470A': [0.3e-3, 2]}
            elif utility_freq == 60:
                apt_times = {
                    '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'))

        ####################################
        # Measuring parameter

        self.add_parameter('volt',
                           get_cmd=self._get_voltage,
                           label='Voltage',
                           unit='V')

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

        if not silent:
            self.connect_message()
Пример #26
0
    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']

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

        options = self._options()
        self.has_DIG = self.is_34465A_34470A and (
            'DIG' in options
            or LooseVersion('A.03') <= LooseVersion(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],
                '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']

        ranges = {'34410A': [10**n for n in range(3, 10)],  # 100 to 1 G
                  '34460A': [10**n for n in range(-3, 9)],  # 1 m to 100 M
                  '34461A': [10**n for n in range(-3, 9)],  # 1 m to 100 M
                  '34465A': [10**n for n in range(-3, 10)],  # 1 m to 1 G
                  '34470A': [10**n for n in range(-3, 10)],  # 1 m to 1 G
                  }

        # The resolution factor order matches the order of PLCs
        res_factors = {'34410A': [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 = ranges[self.model]
        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:
            # Define the extreme aperture time values for the 34465A and 34470A
            utility_freq = self.line_frequency()
            if utility_freq == 50:
                apt_times = {'34465A': [0.3e-3, 2],
                            '34470A': [0.3e-3, 2]}
            elif utility_freq == 60:
                apt_times = {'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()
Пример #27
0
    def __init__(self,
                 name: str,
                 address: str,
                 model: str = None,
                 timeout: float = 5.,
                 HD: bool = True,
                 terminator: str = '\n',
                 **kwargs) -> None:
        """
        Args:
            name: name of the instrument
            address: VISA resource address
            model: The instrument model. For newer firmware versions,
                this can be auto-detected
            timeout: The VISA query timeout
            HD: Does the unit have the High Definition Option (allowing
                16 bit vertical resolution)
            terminator: Command termination character to strip from VISA
                commands.
        """
        super().__init__(name=name,
                         address=address,
                         timeout=timeout,
                         terminator=terminator,
                         **kwargs)

        # With firmware versions earlier than 3.65, it seems that the
        # model number can NOT be queried from the instrument
        # (at least fails with RTO1024, fw 2.52.1.1), so in that case
        # the user must provide the model manually
        firmware_version = self.get_idn()['firmware']

        if LooseVersion(firmware_version) < LooseVersion('3'):
            log.warning('Old firmware version detected. This driver may '
                        'not be compatible. Please upgrade your firmware.')

        if LooseVersion(firmware_version) >= LooseVersion('3.65'):
            # strip just in case there is a newline character at the end
            self.model = self.ask('DIAGnostic:SERVice:WFAModel?').strip()
            if model is not None and model != self.model:
                warnings.warn("The model number provided by the user "
                              "does not match the instrument's response."
                              " I am going to assume that this oscilloscope "
                              "is a model {}".format(self.model))
        else:
            if model is None:
                raise ValueError('No model number provided. Please provide '
                                 'a model number (eg. "RTO1024").')
            else:
                self.model = model

        self.HD = HD

        # Now assign model-specific values
        self.num_chans = int(self.model[-1])

        self._horisontal_divs = int(self.ask('TIMebase:DIVisions?'))

        self.add_parameter('display',
                           label='Display state',
                           set_cmd='SYSTem:DISPlay:UPDate {}',
                           val_mapping={
                               'remote': 0,
                               'view': 1
                           })

        #########################
        # Triggering

        self.add_parameter('trigger_display',
                           label='Trigger display state',
                           set_cmd='DISPlay:TRIGger:LINes {}',
                           get_cmd='DISPlay:TRIGger:LINes?',
                           val_mapping={
                               'ON': 1,
                               'OFF': 0
                           })

        # TODO: (WilliamHPNielsen) There are more available trigger
        # settings than implemented here. See p. 1261 of the manual
        # here we just use trigger1, which is the A-trigger

        self.add_parameter('trigger_source',
                           label='Trigger source',
                           set_cmd='TRIGger1:SOURce {}',
                           get_cmd='TRIGger1:SOURce?',
                           val_mapping={
                               'CH1': 'CHAN1',
                               'CH2': 'CHAN2',
                               'CH3': 'CHAN3',
                               'CH4': 'CHAN4',
                               'EXT': 'EXT'
                           })

        self.add_parameter('trigger_type',
                           label='Trigger type',
                           set_cmd='TRIGger1:TYPE {}',
                           get_cmd='TRIGger1:TYPE?',
                           val_mapping={
                               'EDGE': 'EDGE',
                               'GLITCH': 'GLIT',
                               'WIDTH': 'WIDT',
                               'RUNT': 'RUNT',
                               'WINDOW': 'WIND',
                               'TIMEOUT': 'TIM',
                               'INTERVAL': 'INT',
                               'SLEWRATE': 'SLEW',
                               'DATATOCLOCK': 'DAT',
                               'STATE': 'STAT',
                               'PATTERN': 'PATT',
                               'ANEDGE': 'ANED',
                               'SERPATTERN': 'SERP',
                               'NFC': 'NFC',
                               'TV': 'TV',
                               'CDR': 'CDR'
                           })
        # See manual p. 1262 for an explanation of trigger types

        self.add_parameter('trigger_level',
                           label='Trigger level',
                           set_cmd=self._set_trigger_level,
                           get_cmd=self._get_trigger_level)

        self.add_parameter('trigger_edge_slope',
                           label='Edge trigger slope',
                           set_cmd='TRIGger1:EDGE:SLOPe {}',
                           get_cmd='TRIGger1:EDGE:SLOPe?',
                           vals=vals.Enum('POS', 'NEG', 'EITH'))

        #########################
        # Horizontal settings

        self.add_parameter('timebase_scale',
                           label='Timebase scale',
                           set_cmd=self._set_timebase_scale,
                           get_cmd='TIMebase:SCALe?',
                           unit='s/div',
                           get_parser=float,
                           vals=vals.Numbers(25e-12, 10000))

        self.add_parameter('timebase_range',
                           label='Timebase range',
                           set_cmd=self._set_timebase_range,
                           get_cmd='TIMebase:RANGe?',
                           unit='s',
                           get_parser=float,
                           vals=vals.Numbers(250e-12, 100e3))

        self.add_parameter('timebase_position',
                           label='Horizontal position',
                           set_cmd=self._set_timebase_position,
                           get_cmd='TIMEbase:HORizontal:POSition?',
                           get_parser=float,
                           unit='s',
                           vals=vals.Numbers(-100e24, 100e24))

        #########################
        # Acquisition

        # I couldn't find a way to query the run mode, so we manually keep
        # track of it. It is very important when getting the trace to make
        # sense of completed_acquisitions
        self.add_parameter('run_mode',
                           label='Run/acqusition mode of the scope',
                           get_cmd=None,
                           set_cmd=None)

        self.run_mode('RUN CONT')

        self.add_parameter('num_acquisitions',
                           label='Number of single acquisitions to perform',
                           get_cmd='ACQuire:COUNt?',
                           set_cmd='ACQuire:COUNt {}',
                           vals=vals.Ints(1, 16777215),
                           get_parser=int)

        self.add_parameter('completed_acquisitions',
                           label='Number of completed acquisitions',
                           get_cmd='ACQuire:CURRent?',
                           get_parser=int)

        self.add_parameter('sampling_rate',
                           label='Sample rate',
                           docstring='Number of averages for measuring '
                           'trace.',
                           unit='Sa/s',
                           get_cmd='ACQuire:POINts:ARATe' + '?',
                           get_parser=int)

        self.add_parameter('acquisition_sample_rate',
                           label='Acquisition sample rate',
                           unit='Sa/s',
                           docstring='recorded waveform samples per second',
                           get_cmd='ACQuire:SRATe' + '?',
                           set_cmd='ACQuire:SRATe ' + ' {:.2f}',
                           vals=vals.Numbers(2, 20e12),
                           get_parser=float)

        #########################
        # Data

        self.add_parameter('dataformat',
                           label='Export data format',
                           set_cmd='FORMat:DATA {}',
                           get_cmd='FORMat:DATA?',
                           vals=vals.Enum('ASC,0', 'REAL,32', 'INT,8',
                                          'INT,16'))

        #########################
        # High definition mode (might not be available on all instruments)

        if HD:
            self.add_parameter('high_definition_state',
                               label='High definition (16 bit) state',
                               set_cmd=self._set_hd_mode,
                               get_cmd='HDEFinition:STAte?',
                               val_mapping={
                                   'ON': 1,
                                   'OFF': 0
                               })

            self.add_parameter('high_definition_bandwidth',
                               label='High definition mode bandwidth',
                               set_cmd='HDEFinition:BWIDth {}',
                               get_cmd='HDEFinition:BWIDth?',
                               unit='Hz',
                               get_parser=float,
                               vals=vals.Numbers(1e4, 1e9))

        # Add the channels to the instrument
        for ch in range(1, self.num_chans + 1):
            chan = ScopeChannel(self, 'channel{}'.format(ch), ch)
            self.add_submodule('ch{}'.format(ch), chan)

        self.add_function('stop', call_cmd='STOP')
        self.add_function('reset', call_cmd='*RST')
        self.add_function('opc', call_cmd='*OPC?')
        self.add_function('stop_opc', call_cmd='*STOP;OPC?')
        # starts the shutdown of the system
        self.add_function('system_shutdown', call_cmd='SYSTem:EXIT')

        self.connect_message()
Пример #28
0
    def __init__(self, parent: 'B1520A', name: str, **kwargs: Any):
        super().__init__(parent, name, **kwargs)

        self.add_parameter(name='sweep_auto_abort',
                           set_cmd=self._set_sweep_auto_abort,
                           get_cmd=self._get_sweep_auto_abort,
                           set_parser=constants.Abort,
                           get_parser=constants.Abort,
                           vals=vals.Enum(*list(constants.Abort)),
                           initial_cache_value=constants.Abort.ENABLED,
                           docstring=textwrap.dedent("""
                           enables or disables the automatic abort function
                           for the CV (DC bias) sweep measurement (MM18) and
                           the pulsed bias sweep measurement (MM20). The
                           automatic abort function stops the measurement
                           when one of the following conditions occurs:
                               - NULL loop unbalance condition
                               - IV amplifier saturation condition
                               - Overflow on the AD converter
                           """))

        self.add_parameter(name='post_sweep_voltage_condition',
                           set_cmd=self._set_post_sweep_voltage_condition,
                           get_cmd=self._get_post_sweep_voltage_condition,
                           set_parser=constants.WMDCV.Post,
                           get_parser=constants.WMDCV.Post,
                           vals=vals.Enum(*list(constants.WMDCV.Post)),
                           initial_cache_value=constants.WMDCV.Post.START,
                           docstring=textwrap.dedent("""
                           This command also sets the post measurement
                           condition of the MFCMU. After the measurement is
                           normally completed, the DC bias sweep source
                           forces the value specified by the post parameter,
                           and the pulsed bias sweep source forces
                           the pulse base value.
                           If the measurement is stopped by the automatic
                           abort function, the DC bias sweep source forces
                           the start value, and the pulsed bias sweep source
                           forces the pulse base value after sweep.
                           """))

        self.add_parameter(name='hold_time',
                           initial_value=0.0,
                           vals=vals.Numbers(0, 655.35),
                           unit='s',
                           parameter_class=GroupParameter,
                           docstring=textwrap.dedent("""
                           Hold time (in seconds) that is the
                           wait time after starting measurement
                           and before starting delay time for
                           the first step 0 to 655.35, with 10
                           ms resolution. Numeric expression.
                          """))

        self.add_parameter(name='delay',
                           initial_value=0.0,
                           vals=vals.Numbers(0, 65.535),
                           unit='s',
                           parameter_class=GroupParameter,
                           docstring=textwrap.dedent("""
                           Delay time (in seconds) that is the wait time after
                           starting to force a step output and before
                            starting a step measurement. 0 to 65.535,
                            with 0.1 ms resolution. Numeric expression.
                            """))

        self.add_parameter(name='step_delay',
                           initial_value=0.0,
                           vals=vals.Numbers(0, 1),
                           unit='s',
                           parameter_class=GroupParameter,
                           docstring=textwrap.dedent("""
                            Step delay time (in seconds) that is the wait time
                            after starting a step measurement and before
                            starting to force the next step output. 0 to 1,
                            with 0.1 ms resolution. Numeric expression. If
                            this parameter is not set, step delay will be 0. If
                            step delay is shorter than the measurement time,
                            the B1500 waits until the measurement completes,
                            then forces the next step output.
                            """))

        self.add_parameter(name='trigger_delay',
                           initial_value=0.0,
                           unit='s',
                           parameter_class=GroupParameter,
                           docstring=textwrap.dedent("""
                            Step source trigger delay time (in seconds) that
                            is the wait time after completing a step output
                            setup and before sending a step output setup
                            completion trigger. 0 to the value of ``delay``,
                            with 0.1 ms resolution. Numeric expression. If this
                            parameter is not set, trigger delay will be 0.
                            """))

        self.add_parameter(name='measure_delay',
                           initial_value=0.0,
                           unit='s',
                           vals=vals.Numbers(0, 65.535),
                           parameter_class=GroupParameter,
                           docstring=textwrap.dedent("""
                           Step measurement trigger delay time (in seconds)
                           that is the wait time after receiving a start step
                           measurement trigger and before starting a step
                           measurement. 0 to 65.535, with 0.1 ms resolution.
                           Numeric expression. If this parameter is not set,
                           measure delay will be 0.
                           """))

        self._set_sweep_delays_group = Group(
            [
                self.hold_time, self.delay, self.step_delay,
                self.trigger_delay, self.measure_delay
            ],
            set_cmd='WTDCV '
            '{hold_time},'
            '{delay},'
            '{step_delay},'
            '{trigger_delay},'
            '{measure_delay}',
            get_cmd=self._get_sweep_delays(),
            get_parser=self._get_sweep_delays_parser)

        self.add_parameter(name='sweep_mode',
                           initial_value=constants.SweepMode.LINEAR,
                           vals=vals.Enum(*list(constants.SweepMode)),
                           set_parser=constants.SweepMode,
                           parameter_class=GroupParameter,
                           docstring=textwrap.dedent("""
                   Sweep mode.
                       1: Linear sweep (single stair, start to stop.)
                       2: Log sweep (single stair, start to stop.)
                       3: Linear sweep (double stair, start to stop to start.)
                       4: Log sweep (double stair, start to stop to start.)
                                  """))

        self.add_parameter(name='sweep_start',
                           initial_value=0.0,
                           unit='V',
                           vals=vals.Numbers(-25, 25),
                           parameter_class=GroupParameter,
                           docstring=textwrap.dedent("""
                   Start value of the DC bias sweep (in V). For the log  sweep,
                   start and stop must have the same polarity.
                                  """))

        self.add_parameter(name='sweep_end',
                           initial_value=0.0,
                           unit='V',
                           vals=vals.Numbers(-25, 25),
                           parameter_class=GroupParameter,
                           docstring=textwrap.dedent("""
                   Stop value of the DC bias sweep (in V). For the log sweep,
                   start and stop must have the same polarity.
                                  """))

        self.add_parameter(name='sweep_steps',
                           initial_value=1,
                           vals=vals.Ints(1, 1001),
                           parameter_class=GroupParameter,
                           docstring=textwrap.dedent("""
                   Number of steps for staircase sweep. Possible  values from 1 to
                   1001"""))

        self.add_parameter(name='_chan',
                           initial_value=self.parent.channels[0],
                           parameter_class=GroupParameter)

        self._set_sweep_steps_group = Group(
            [
                self._chan, self.sweep_mode, self.sweep_start, self.sweep_end,
                self.sweep_steps
            ],
            set_cmd='WDCV '
            '{_chan},'
            '{sweep_mode},'
            '{sweep_start},'
            '{sweep_end},'
            '{sweep_steps}',
            get_cmd=self._get_sweep_steps(),
            get_parser=self._get_sweep_steps_parser)
Пример #29
0
    def __init__(self, parent: Instrument, name: str, channel: str) -> None:
        """
        Args:
            parent: The Instrument instance to which the channel is
                to be attached.
            name: The 'colloquial' name of the channel
            channel: The name used by the Keithley, i.e. either
                'smua' or 'smub'
        """

        if channel not in ['smua', 'smub']:
            raise ValueError('channel must be either "smub" or "smua"')

        super().__init__(parent, name)
        self.model = self._parent.model
        self._extra_visa_timeout = 5000
        self._measurement_duration_factor = 2  # Ensures that we are always above
        # the expected time.
        vranges = self._parent._vranges
        iranges = self._parent._iranges
        vlimit_minmax = self.parent._vlimit_minmax
        ilimit_minmax = self.parent._ilimit_minmax

        self.add_parameter('volt',
                           parameter_class=_MeasurementVoltageParameter,
                           label='Voltage',
                           unit='V',
                           snapshot_get=False)

        self.add_parameter('ramp_voltage',
                           get_cmd=f'{channel}.measure.v()',
                           get_parser=float,
                           set_cmd=self.ramp_voltage_to,
                           label='Voltage',
                           unit='V')

        self.add_parameter(
            'ramp_voltage_step',
            label='Step size for ramp_voltage',
            unit='V',
            initial_value=10e-3,
            get_cmd=None,
            set_cmd=None,
        )

        self.add_parameter(
            'ramp_voltage_delay',
            label='Delay for ramp_voltage',
            unit='s',
            initial_value=0,
            get_cmd=None,
            set_cmd=None,
        )

        self.add_parameter('curr',
                           parameter_class=_MeasurementCurrentParameter,
                           label='Current',
                           unit='A',
                           snapshot_get=False)

        self.add_parameter('ramp_current',
                           get_cmd=f'{channel}.measure.i()',
                           get_parser=float,
                           set_cmd=self.ramp_current_to,
                           label='Current',
                           unit='A')

        self.add_parameter(
            'ramp_current_step',
            label='Step size for ramp_current',
            unit='A',
            initial_value=0.3e-3,
            get_cmd=None,
            set_cmd=None,
        )

        self.add_parameter(
            'ramp_current_delay',
            label='Delay for ramp_current',
            unit='s',
            initial_value=10e-3,
            get_cmd=None,
            set_cmd=None,
        )

        self.add_parameter('res',
                           get_cmd=f'{channel}.measure.r()',
                           get_parser=float,
                           set_cmd=False,
                           label='Resistance',
                           unit='Ohm')

        self.add_parameter('mode',
                           get_cmd=f'{channel}.source.func',
                           get_parser=float,
                           set_cmd=f'{channel}.source.func={{:d}}',
                           val_mapping={
                               'current': 0,
                               'voltage': 1
                           },
                           docstring='Selects the output source type. '
                           'Can be either voltage or current.')

        self.add_parameter('output',
                           get_cmd=f'{channel}.source.output',
                           get_parser=float,
                           set_cmd=f'{channel}.source.output={{:d}}',
                           val_mapping=create_on_off_val_mapping(on_val=1,
                                                                 off_val=0))

        self.add_parameter('linefreq',
                           label='Line frequency',
                           get_cmd='localnode.linefreq',
                           get_parser=float,
                           set_cmd=False,
                           unit='Hz')

        self.add_parameter('nplc',
                           label='Number of power line cycles',
                           set_cmd=f'{channel}.measure.nplc={{}}',
                           get_cmd=f'{channel}.measure.nplc',
                           get_parser=float,
                           docstring='Number of power line cycles, used '
                           'to perform measurements',
                           vals=vals.Numbers(0.001, 25))
        # volt range
        # needs get after set (WilliamHPNielsen): why?
        self.add_parameter('sourcerange_v',
                           label='voltage source range',
                           get_cmd=f'{channel}.source.rangev',
                           get_parser=float,
                           set_cmd=self._set_sourcerange_v,
                           unit='V',
                           docstring='The range used when sourcing voltage '
                           'This affects the range and the precision '
                           'of the source.',
                           vals=vals.Enum(*vranges[self.model]))

        self.add_parameter(
            'source_autorange_v_enabled',
            label='voltage source autorange',
            get_cmd=f'{channel}.source.autorangev',
            get_parser=float,
            set_cmd=f'{channel}.source.autorangev={{}}',
            docstring='Set autorange on/off for source voltage.',
            val_mapping=create_on_off_val_mapping(on_val=1, off_val=0))

        self.add_parameter('measurerange_v',
                           label='voltage measure range',
                           get_cmd=f'{channel}.measure.rangev',
                           get_parser=float,
                           set_cmd=self._set_measurerange_v,
                           unit='V',
                           docstring='The range to perform voltage '
                           'measurements in. This affects the range '
                           'and the precision of the measurement. '
                           'Note that if you both measure and '
                           'source current this will have no effect, '
                           'set `sourcerange_v` instead',
                           vals=vals.Enum(*vranges[self.model]))

        self.add_parameter(
            'measure_autorange_v_enabled',
            label='voltage measure autorange',
            get_cmd=f'{channel}.measure.autorangev',
            get_parser=float,
            set_cmd=f'{channel}.measure.autorangev={{}}',
            docstring='Set autorange on/off for measure voltage.',
            val_mapping=create_on_off_val_mapping(on_val=1, off_val=0))
        # current range
        # needs get after set
        self.add_parameter('sourcerange_i',
                           label='current source range',
                           get_cmd=f'{channel}.source.rangei',
                           get_parser=float,
                           set_cmd=self._set_sourcerange_i,
                           unit='A',
                           docstring='The range used when sourcing current '
                           'This affects the range and the '
                           'precision of the source.',
                           vals=vals.Enum(*iranges[self.model]))

        self.add_parameter(
            'source_autorange_i_enabled',
            label='current source autorange',
            get_cmd=f'{channel}.source.autorangei',
            get_parser=float,
            set_cmd=f'{channel}.source.autorangei={{}}',
            docstring='Set autorange on/off for source current.',
            val_mapping=create_on_off_val_mapping(on_val=1, off_val=0))

        self.add_parameter('measurerange_i',
                           label='current measure range',
                           get_cmd=f'{channel}.measure.rangei',
                           get_parser=float,
                           set_cmd=self._set_measurerange_i,
                           unit='A',
                           docstring='The range to perform current '
                           'measurements in. This affects the range '
                           'and the precision of the measurement. '
                           'Note that if you both measure and source '
                           'current this will have no effect, set '
                           '`sourcerange_i` instead',
                           vals=vals.Enum(*iranges[self.model]))

        self.add_parameter(
            'measure_autorange_i_enabled',
            label='current autorange',
            get_cmd=f'{channel}.measure.autorangei',
            get_parser=float,
            set_cmd=f'{channel}.measure.autorangei={{}}',
            docstring='Set autorange on/off for measure current.',
            val_mapping=create_on_off_val_mapping(on_val=1, off_val=0))
        # Compliance limit
        self.add_parameter('limitv',
                           get_cmd=f'{channel}.source.limitv',
                           get_parser=float,
                           set_cmd=f'{channel}.source.limitv={{}}',
                           docstring='Voltage limit e.g. the maximum voltage '
                           'allowed in current mode. If exceeded '
                           'the current will be clipped.',
                           vals=vals.Numbers(vlimit_minmax[self.model][0],
                                             vlimit_minmax[self.model][1]),
                           unit='V')
        # Compliance limit
        self.add_parameter('limiti',
                           get_cmd=f'{channel}.source.limiti',
                           get_parser=float,
                           set_cmd=f'{channel}.source.limiti={{}}',
                           docstring='Current limit e.g. the maximum current '
                           'allowed in voltage mode. If exceeded '
                           'the voltage will be clipped.',
                           vals=vals.Numbers(ilimit_minmax[self.model][0],
                                             ilimit_minmax[self.model][1]),
                           unit='A')

        self.add_parameter('fastsweep', parameter_class=LuaSweepParameter)

        self.add_parameter('timetrace_npts',
                           initial_value=500,
                           label='Number of points',
                           get_cmd=None,
                           set_cmd=None)

        self.add_parameter('timetrace_dt',
                           initial_value=1e-3,
                           label='Time resolution',
                           unit='s',
                           get_cmd=None,
                           set_cmd=None)

        self.add_parameter(name='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)

        self.add_parameter('timetrace_mode',
                           initial_value='current',
                           get_cmd=None,
                           set_cmd=self.timetrace._set_mode,
                           vals=vals.Enum('current', 'voltage'))

        self.channel = channel
Пример #30
0
    def __init__(self, parent: 'KeysightB1500', name: Optional[str],
                 slot_nr: int, **kwargs: Any):
        super().__init__(parent, name, slot_nr, **kwargs)

        self.channels = (ChNr(slot_nr), )
        self.setup_fnc_already_run = False
        self._ranging_mode: constants.RangingMode = constants.RangingMode.AUTO
        self._measurement_range_for_non_auto: Optional[int] = None

        self.add_parameter(name="voltage_dc",
                           unit="V",
                           set_cmd=self._set_voltage_dc,
                           get_cmd=self._get_voltage_dc,
                           snapshot_get=False)

        self.add_parameter(name="voltage_ac",
                           unit="V",
                           set_cmd=self._set_voltage_ac,
                           get_cmd=self._get_voltage_ac,
                           snapshot_get=False)

        self.add_parameter(name="frequency",
                           unit="Hz",
                           set_cmd=self._set_frequency,
                           get_cmd=self._get_frequency,
                           snapshot_get=False)

        self.add_parameter(name="capacitance",
                           get_cmd=self._get_capacitance,
                           snapshot_value=False)

        self.add_submodule('correction', Correction(self, 'correction'))

        self.add_parameter(name="phase_compensation_mode",
                           set_cmd=self._set_phase_compensation_mode,
                           get_cmd=None,
                           set_parser=constants.ADJ.Mode,
                           docstring=textwrap.dedent("""
            This parameter selects the MFCMU phase compensation mode. This
            command initializes the MFCMU. The available modes are captured
            in :class:`constants.ADJ.Mode`:

                - 0: Auto mode. Initial setting.
                - 1: Manual mode.
                - 2: Load adaptive mode.

            For mode=0, the KeysightB1500 sets the compensation data
            automatically. For mode=1, execute the
            :meth:`phase_compensation` method ( the ``ADJ?`` command) to
            perform the phase compensation and set the compensation data.
            For mode=2, the KeysightB1500 performs the phase compensation
            before every measurement. It is useful when there are wide load
            fluctuations by changing the bias and so on."""))

        self.add_submodule('cv_sweep', CVSweeper(self, 'cv_sweep'))

        self.add_parameter(name='adc_coef',
                           initial_value=1,
                           parameter_class=GroupParameter,
                           vals=vals.Ints(1, 1023),
                           docstring=textwrap.dedent("""
            Coefficient used to define the number of averaging samples or
            the averaging time. Integer expression.
                - For mode=0: 1 to 1023. Initial setting/default setting is 2.
                - For mode=2: 1 to 100. Initial setting/default setting is 1.
            """))

        self.add_parameter(name='adc_mode',
                           initial_value=constants.ACT.Mode.PLC,
                           parameter_class=GroupParameter,
                           vals=vals.Enum(*list(constants.ACT.Mode)),
                           set_parser=constants.ACT.Mode,
                           docstring=textwrap.dedent("""
            Sets the number of averaging samples or the averaging time set
            to the A/D converter of the MFCMU

                ``constants.ACT.Mode.AUTO``: Auto mode. Defines the number
                of averaging samples given by the following formula. Then
                initial averaging is the number of averaging samples
                automatically set by the B1500 and you cannot change.

                Number of averaging samples = N x initial averaging

                ``constants.ACT.Mode.PLC``: Power line cycle (PLC) mode.
                Defines the averaging time given by the following formula.

                Averaging time = N / power line frequency
                                       """))

        self._adc_group = Group([self.adc_mode, self.adc_coef],
                                set_cmd='ACT {adc_mode},{adc_coef}',
                                get_cmd=self._get_adc_mode(),
                                get_parser=self._get_adc_mode_parser)

        self.add_parameter(name='ranging_mode',
                           set_cmd=self._set_ranging_mode,
                           vals=vals.Enum(*list(constants.RangingMode)),
                           set_parser=constants.RangingMode,
                           get_cmd=None,
                           docstring=textwrap.dedent("""
            Specifies the measurement range or the measurement ranging type
            of the MFCMU. In the initial setting, the auto ranging is set.
            The range changing occurs immediately after the trigger
            (that is, during the measurements).
            Possible ranging modes are autorange and fixed range.
                           """))

        self.add_parameter(name='measurement_range_for_non_auto',
                           set_cmd=self._set_measurement_range_for_non_auto,
                           get_cmd=None,
                           docstring=textwrap.dedent("""
            Measurement range. Needs to set when ``ranging_mode`` is set to
            PLC. The value should be integer 0 or more. 50 ohm, 100 ohm,
            300 ohm, 1 kilo ohm, 3 kilo ohm, 10 kilo ohm, 30 kilo ohm,
            100 kilo ohm, and 300 kilo ohm are selectable. Available
            measurement ranges depend on the output signal frequency set by
            the FC command."""))

        self.add_parameter(name="measurement_mode",
                           get_cmd=None,
                           set_cmd=self._set_measurement_mode,
                           set_parser=MM.Mode,
                           vals=vals.Enum(*list(MM.Mode)),
                           docstring=textwrap.dedent("""
            Set measurement mode for this module.

            It is recommended for this parameter to use values from
            :class:`.constants.MM.Mode` enumeration.

            Refer to the documentation of ``MM`` command in the programming
            guide for more information.
                            """))

        self.add_parameter(
            name='impedance_model',
            set_cmd=self._set_impedance_model,
            get_cmd=None,
            vals=vals.Enum(*list(constants.IMP.MeasurementMode)),
            set_parser=constants.IMP.MeasurementMode,
            initial_value=constants.IMP.MeasurementMode.Cp_D,
            docstring=textwrap.dedent("""
            The IMP command specifies the parameter measured by the MFCMU.
            Look at the ``constants.IMP.MeasurementMode`` for all the modes.
                           """))

        self.add_parameter(name='ac_dc_volt_monitor',
                           set_cmd=self._set_ac_dc_volt_monitor,
                           get_cmd=None,
                           vals=vals.Ints(0, 1),
                           initial_value=False,
                           docstring=textwrap.dedent("""
            This command enables or disables the data monitor and data
            output of the MFCMU AC voltage and DC voltage.
                0: Disables the data monitor and output. Initial setting.
                1: Enables the data monitor and output.
                           """))

        self.add_parameter(name='cv_sweep_voltages',
                           get_cmd=self._cv_sweep_voltages,
                           unit='V',
                           label='Voltage',
                           docstring=textwrap.dedent("""
            Outputs the tuple of voltages to sweep.  sweep_start, sweep_end
            and sweep_step functions are used to define the values of
            voltages. There are possible modes; linear sweep, log sweep,
            linear 2 way sweep and log 2 way sweep. The  output of
            sweep_mode method is used to decide which mode to use.
                           """))

        self.add_parameter(name='run_sweep',
                           parameter_class=CVSweepMeasurement,
                           docstring=textwrap.dedent("""
            This is MultiParameter. Running the sweep runs the measurement
            on the list of values of cv_sweep_voltages. The output is a
            primary parameter (for ex Capacitance) and a secondary
            parameter (for ex Dissipation) both of whom use the same
            setpoint cv_sweep_voltages. The impedance_model defines exactly
            what will be the primary and secondary parameter. The default
            case is Capacitance and Dissipation.
                           """))