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)
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)
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'
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'
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'])
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)
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)
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)
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)
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)
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())
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()
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}")
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')
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
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 = {}
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() '''
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
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)."""))
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())
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()
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()
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()
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)
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
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. """))