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, parent, name, channum): """ Args: parent (Instrument): The instrument to which the channel is attached. name (str): The name of the channel channum (int): The number of the channel in question (1-48) """ super().__init__(parent, name) # Validate the channel self._CHANNEL_VALIDATION.validate(channum) # Add the parameters self.add_parameter('v', label=f'Channel {channum} voltage', unit='V', set_cmd=partial(self._parent._set_voltage, channum), get_cmd=partial(self._parent._get_voltage, channum), get_parser=float, vals=vals.Numbers(-10, 10)) self.add_parameter('vrange', label=f'Channel {channum} atten.', set_cmd=partial(self._parent._set_vrange, channum), get_cmd=partial(self._parent._get_vrange, channum), vals=vals.Enum(0, 1)) self.add_parameter('i', label=f'Channel {channum} current', get_cmd=f'get {channum}', unit='A', get_parser=self._parent._current_parser) self.add_parameter('irange', label=f'Channel {channum} irange', set_cmd=f'cur {channum} {{}}', get_cmd=f'cur {channum}', get_parser=int) self.add_parameter('slope', label=f'Channel {channum} slope', unit='V/s', set_cmd=partial(self._parent._setslope, channum), get_cmd=partial(self._parent._getslope, channum), vals=vals.MultiType(vals.Enum('Inf'), vals.Numbers(1e-3, 100))) self.add_parameter('sync', label=f'Channel {channum} sync output', set_cmd=partial(self._parent._setsync, channum), get_cmd=partial(self._parent._getsync, channum), vals=vals.Ints(0, 5)) self.add_parameter(name='sync_delay', label=f'Channel {channum} sync pulse delay', unit='s', get_cmd=None, set_cmd=None, initial_value=0) self.add_parameter(name='sync_duration', label=f'Channel {channum} sync pulse duration', unit='s', get_cmd=None, set_cmd=None, initial_value=0.01)
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, address, DIG=False, utility_freq=50, 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. utility_freq (int): The local utility frequency in Hz. Default: 50 DIG (bool): Is the DIG option installed on the instrument? Default: False. silent (bool): If True, the connect_message of the instrument is supressed. Default: False Returns: Keysight_34465A """ if utility_freq not in [50, 60]: raise ValueError('Can not set utility frequency to ' '{}. '.format(utility_freq) + 'Please enter either 50 Hz or 60 Hz.') super().__init__(name, address, terminator='\n', **kwargs) idn = self.IDN.get() self.model = idn['model'] #################################### # Instrument specifications 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 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 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'] # Define the extreme aperture time values for the 34465A and 34470A if utility_freq == 50: apt_times = {'34465A': [0.3e-3, 2], '34470A': [0.3e-3, 2]} if utility_freq == 60: apt_times = {'34465A': [0.3e-3, 1.67], '34470A': [0.3e-3, 1.67]} if DIG: apt_times['34465A'][0] = 20e-6 apt_times['34470A'][0] = 20e-6 self._resolution_factors = res_factors[self.model] self.ranges = ranges[self.model] self.NPLC_list = PLCs[self.model] self._apt_times = apt_times[self.model] def errorparser(rawmssg: str) -> (int, str): """ Parses the error message. Args: rawmssg: The raw return value of 'SYSTem:ERRor?' Returns: The error code and the error message. """ code = int(rawmssg.split(',')[0]) mssg = rawmssg.split(',')[1].strip().replace('"', '') return code, mssg #################################### # PARAMETERS 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') 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') 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_text', label='Display text', set_cmd='DISPLAY:TEXT "{}"', get_cmd='DISPLAY:TEXT?', vals=vals.Strings()) # TRIGGERING 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, 1e6), vals.Enum('MIN', 'MAX', 'DEF', 'INF'))) self.add_parameter('trigger_delay', label='Trigger Delay', set_cmd='TRIGger:DELay {}', get_cmd='TRIGger:DELay?', vals=vals.MultiType(vals.Numbers(0, 3600), vals.Enum('MIN', 'MAX', 'DEF')), get_parser=float) self.add_parameter('trigger_slope', label='Trigger Slope', set_cmd='TRIGger:SLOPe {}', get_cmd='TRIGger:SLOPe?', vals=vals.Enum('POS', 'NEG')) self.add_parameter('trigger_source', label='Trigger Source', set_cmd='TRIGger:SOURce {}', get_cmd='TRIGger:SOURce?', vals=vals.Enum('IMM', 'EXT', 'BUS', 'INT')) # SAMPLING 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, 1e6), vals.Enum('MIN', 'MAX', 'DEF')), get_parser=int) if 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=('Allows collection of the data ' 'being digitized the trigger. Reserves ' 'memory for pretrigger samples up to the' ' specified num. of pretrigger samples.')) 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) self.add_parameter('sample_timer_minimum', label='Minimal sample time', get_cmd='SAMPle:TIMer? MIN', get_parser=float, unit='s') # SYSTEM self.add_parameter('error', label='Error message', get_cmd='SYSTem:ERRor?', get_parser=errorparser) # The array parameter self.add_parameter('data_buffer', parameter_class=ArrayMeasurement) #################################### # Model-specific parameters if self.model in ['34465A', '34470A']: 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')) 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(*self._apt_times), docstring=('Setting the aperture time ' 'automatically enables the aperture' ' mode.')) self.add_function('init_measurement', call_cmd='INIT') self.add_function('reset', call_cmd='*RST') self.add_function('display_clear', call_cmd=('DISPLay:TEXT:CLEar')) self.add_function('abort_measurement', call_cmd='ABORt') if not silent: self.connect_message()
def _add_waveform_parameters(self): """ Adds the parameters required to generate the standard waveforms The following prefixes are used for waveform parameters sq cz czd mcz custom """ self.add_parameter('sq_amp', initial_value=.5, # units is part of the total range of AWG8 label='Square pulse amplitude', unit='dac value', vals=vals.Numbers(), parameter_class=ManualParameter) self.add_parameter('sq_length', unit='s', label='Square pulse length', initial_value=40e-9, vals=vals.Numbers(0, 100e-6), parameter_class=ManualParameter) self.add_parameter('cz_length', vals=vals.Numbers(), unit='s', initial_value=35e-9, parameter_class=ManualParameter) self.add_parameter('cz_lambda_2', vals=vals.Numbers(), initial_value=0, parameter_class=ManualParameter) self.add_parameter('cz_lambda_3', vals=vals.Numbers(), initial_value=0, parameter_class=ManualParameter) self.add_parameter('cz_theta_f', vals=vals.Numbers(), unit='deg', initial_value=80, parameter_class=ManualParameter) self.add_parameter('czd_length_ratio', vals=vals.Numbers(0, 1), initial_value=0.5, parameter_class=ManualParameter) self.add_parameter( 'czd_lambda_2', docstring='lambda_2 parameter of the negative part of the cz pulse' ' if set to np.nan will default to the value of the main parameter', vals=vals.MultiType(vals.Numbers(), NP_NANs()), initial_value=np.nan, parameter_class=ManualParameter) self.add_parameter( 'czd_lambda_3', docstring='lambda_3 parameter of the negative part of the cz pulse' ' if set to np.nan will default to the value of the main parameter', vals=vals.MultiType(vals.Numbers(), NP_NANs()), initial_value=np.nan, parameter_class=ManualParameter) self.add_parameter( 'czd_theta_f', docstring='theta_f parameter of the negative part of the cz pulse' ' if set to np.nan will default to the value of the main parameter', vals=vals.MultiType(vals.Numbers(), NP_NANs()), unit='deg', initial_value=np.nan, parameter_class=ManualParameter) self.add_parameter('cz_freq_01_max', vals=vals.Numbers(), # initial value is chosen to not raise errors initial_value=6e9, unit='Hz', parameter_class=ManualParameter) self.add_parameter('cz_J2', vals=vals.Numbers(), unit='Hz', # initial value is chosen to not raise errors initial_value=15e6, parameter_class=ManualParameter) self.add_parameter('cz_freq_interaction', vals=vals.Numbers(), # initial value is chosen to not raise errors initial_value=5e9, unit='Hz', parameter_class=ManualParameter) self.add_parameter('cz_phase_corr_length', unit='s', initial_value=5e-9, vals=vals.Numbers(), parameter_class=ManualParameter) self.add_parameter('cz_phase_corr_amp', unit='dac value', initial_value=0, vals=vals.Numbers(), parameter_class=ManualParameter) self.add_parameter('czd_amp_ratio', docstring='Amplitude ratio for double sided CZ gate', initial_value=1, vals=vals.Numbers(), parameter_class=ManualParameter) self.add_parameter('czd_amp_offset', docstring='used to add an offset to the negative ' ' pulse that is used in the net-zero cz gate', initial_value=0, unit='dac value', vals=vals.Numbers(), parameter_class=ManualParameter) self.add_parameter('czd_double_sided', initial_value=False, vals=vals.Bool(), parameter_class=ManualParameter) self.add_parameter('mcz_nr_of_repeated_gates', initial_value=1, vals=vals.PermissiveInts(1, 40), parameter_class=ManualParameter) self.add_parameter('mcz_gate_separation', unit='s', label='Gate separation', initial_value=0, docstring=('Separtion between the start of CZ gates' 'in the "multi_cz" gate'), parameter_class=ManualParameter, vals=vals.Numbers(min_value=0)) self.add_parameter( 'custom_wf', initial_value=np.array([]), label='Custom waveform', docstring=('Specifies a custom waveform, note that ' '`custom_wf_length` is used to cut of the waveform if' 'it is set.'), parameter_class=ManualParameter, vals=vals.Arrays()) self.add_parameter( 'custom_wf_length', unit='s', label='Custom waveform length', initial_value=np.inf, docstring=('Used to determine at what sample the custom waveform ' 'is forced to zero. This is used to facilitate easy ' 'cryoscope measurements of custom waveforms.'), parameter_class=ManualParameter, vals=vals.Numbers(min_value=0))
def __init__(self, parent: '_Keysight_344xxA', name: str, **kwargs): super(Sample, self).__init__(parent, name, **kwargs) if self.parent.is_34465A_34470A: _max_sample_count = 1e9 else: _max_sample_count = 1e6 self.add_parameter('count', label='Sample Count', set_cmd='SAMPle:COUNt {}', get_cmd='SAMPle:COUNt?', vals=vals.MultiType( vals.Numbers(1, _max_sample_count), vals.Enum('MIN', 'MAX', 'DEF')), get_parser=int, docstring=textwrap.dedent("""\ Specifies the number of measurements (samples) the instrument takes per trigger. MAX selects 1 billion readings. However, when pretrigger is selected, the maximum is 50,000 readings (without the MEM option) or 2,000,000 readings (with the MEM option)""")) if self.parent.has_DIG: self.add_parameter('pretrigger_count', label='Sample Pretrigger Count', set_cmd='SAMPle:COUNt:PRETrigger {}', get_cmd='SAMPle:COUNt:PRETrigger?', vals=vals.MultiType( vals.Numbers(0, 2e6 - 1), vals.Enum('MIN', 'MAX', 'DEF')), get_parser=int, docstring=textwrap.dedent("""\ Allows collection of the data being digitized the trigger. Reserves memory for pretrigger samples up to the specified num. of pretrigger samples.""")) if self.parent.is_34465A_34470A: self.add_parameter('source', label='Sample Timing Source', set_cmd='SAMPle:SOURce {}', get_cmd='SAMPle:SOURce?', vals=vals.Enum('IMM', 'TIM'), docstring=('Determines sampling time, ' 'immediate or using `sample.timer`')) self.add_parameter('timer', label='Sample Timer', set_cmd='SAMPle:TIMer {}', get_cmd='SAMPle:TIMer?', unit='s', vals=vals.MultiType(vals.Numbers(0, 3600), vals.Enum('MIN', 'MAX', 'DEF')), get_parser=float, docstring=textwrap.dedent("""\ The value is rounded by the instrument to the nearest step. For DC measurements, the step size is 1 µs. For AC measurements, it is AC bandwidth dependent. Special values are: MIN - recommended minimum, MAX - maximum, DEF - default. In order to obtain the actual value of the parameter that gets set when setting it to one of these special values, just call the get method of the parameter, or use corresponding parameters in this driver, like `sample.timer_minimum`. Specifying a value that is between the absolute minimum (assumes no range changes) and the recommended minimum value, may generate a timing violation error when making measurements. Applying a value less than the absolute minimum will generate an error.""")) self.add_parameter('timer_minimum', label='Minimal recommended sample time', get_cmd='SAMPle:TIMer? MIN', get_parser=float, unit='s', docstring=textwrap.dedent("""\ This value is measurement dependent. It depends on such things as the integration time, autozero on or off, autorange on or off, and the measurement range. Basically, the minimum is automatically determined by the instrument so that the sample interval is always greater than the sampling time. Since the minimum value changes depending on configuration, a command order dependency exists. You must completely configure the measurement before setting the sample timer to minimum, or you may generate an error. A complete configuration includes such things as math statistics or scaling. When using autorange, the minimum value is the recommended value, not the absolute minimum value. With autorange enabled, minimum value is calculated assuming a single range change will occur for every measurement (not multiple ranges, just one range up or down per measurement)."""))
def __init__(self, name: str, address: str, timeout=8, **kwargs): """ Args: name: Name to use internally in QCoDeS address: VISA ressource address COM4 is the currently connected usb port) timeout: for the serial communication """ super().__init__(name, **kwargs) self.address = address self.terminator = '\n' self._open_serial_connection(timeout) self._ac_init = False self._ac_ampl = False self._ac_freq = False self.add_parameter('current', label='Current', get_cmd='SOUR:CURR?', set_cmd='SOUR:CURR {}', get_parser=float, unit='A', vals=vals.Numbers(-105e-3, 105e-3)) self.add_parameter('output', get_cmd='OUTP:STAT?', set_cmd='OUTP:STAT {}', get_parser=int, set_parser=parse_output_bool, vals=vals.Enum(*boolcheck)) self.add_parameter('range', get_cmd='CURR:RANG?', set_cmd='CURR:RANG {}', get_parser=float, unit='A', vals=vals.Numbers(-105e-3, 105e-3)) self.add_parameter('auto_range', get_cmd='CURR:RANG:AUTO?', set_cmd='CURR:RANG:AUTO {}', get_parser=int, set_parser=parse_output_bool, vals=vals.Enum(*boolcheck)) self.add_parameter('compliance', get_cmd='CURR:COMP?', set_cmd='CURR:COMP {}', unit='V', get_parser=float, vals=vals.Numbers(-.1, 105)) self.add_parameter('delay', unit='s', get_cmd='SOUR:DEL?', set_cmd='SOUR:DEL {}', get_parser=float, vals=vals.Numbers(0.001, 999999.999)) self.add_parameter('filter', get_cmd='CURR:FILT?', set_cmd='CURR:FILT {}', get_parser=int, set_parser=parse_output_bool, vals=vals.Enum(*boolcheck)) self.add_parameter('speed', get_cmd='OUTP:RESP?', set_cmd='OUTP:RESP {}', get_parser=str, vals=vals.Enum('slow', 'fast', 'SLOW', 'FAST')) self.add_parameter('display', snapshot_get=False, get_cmd='DISP:ENAB?', set_cmd='DISP:ENAB {}', get_parser=int, set_parser=parse_output_bool, vals=vals.Enum(*boolcheck)) self.add_parameter('beeper', snapshot_get=False, get_cmd='SYST:BEEP?', set_cmd='SYST:BEEP {}', get_parser=int, set_parser=parse_output_bool, vals=vals.Enum(*boolcheck)) self.add_parameter('AC_amplitude', get_cmd='SOUR:WAVE:AMPL?', set_cmd=self._setac_amplitude, get_parser=float, unit='A', vals=vals.Numbers(2e-12, 0.105)) self.add_parameter('AC_frequency', get_cmd='SOUR:WAVE:FREQ?', set_cmd=self._setac_frequency, get_parser=float, unit='Hz', vals=vals.Numbers(0, 1e5)) self.add_parameter('AC_offset', get_cmd='SOUR:WAVE:OFFS?', set_cmd='SOUR:WAVE:OFFS {}', get_parser=float, unit='A', vals=vals.Numbers(-0.105, 0.105)) self.add_parameter('AC_duration_time', get_cmd='SOUR:WAVE:DUR:TIME?', set_cmd='SOUR:WAVE:DUR:TIME {}', get_parser=float, unit='s', vals=vals.MultiType( vals.Enum('INF'), vals.Numbers(100e-9, 999999.999))) self.add_parameter('AC_duration_cycles', get_cmd='SOUR:WAVE:DUR:CYCL?', set_cmd='SOUR:WAVE:DUR:CYCL {}', get_parser=float, unit='cycles', vals=vals.MultiType( vals.Enum('INF'), vals.Numbers(0.001, 99999999900))) self.add_parameter('AC_phasemark', get_cmd='SOUR:WAVE:PMAR:STAT?', set_cmd='SOUR:WAVE:PMAR:STAT {}', get_parser=int, set_parser=parse_output_bool, vals=vals.Enum(*boolcheck)) self.add_parameter('AC_phasemark_offset', get_cmd='SOUR:WAVE:PMAR?', set_cmd='SOUR:WAVE:PMAR {}', get_parser=float, unit='degrees', vals=vals.Numbers(0, 360)) self.add_parameter('AC_ranging', get_cmd='SOUR:WAVE:RANG?', set_cmd='SOUR:WAVE:RANG {}', get_parser=str, vals=vals.Enum('BEST', 'best', 'FIX', 'fix', 'FIXED', 'fixed')) self.connect_message()
def __init__(self, name, address, **kwargs): super().__init__(name, address, terminator='\n', timeout=20, **kwargs) self.add_parameter('trigger_mode', label='Trigger mode', unit='', get_cmd='OUTPut:TRIGger:MODE?', get_parser=str, set_cmd='OUTPut:TRIGger:MODE {}', vals=vals.Enum('TRIGger', 'TRIG', 'SYNC')) #: Source/output parameters, 2 channels for src in [1, 2]: #: Outputs self.add_parameter('impedance_output{}'.format(src), label='Output {} impedance'.format(src), unit='Ohm', get_cmd='OUTPut{}:IMPedance?'.format(src), get_parser=float, set_cmd='OUTPut{}:IMPedance {{}}'.format(src), vals=vals.Strings()) self.add_parameter('polarity_output{}'.format(src), label='Output {} polarity'.format(src), unit='', get_cmd='OUTPut{}:POLarity?'.format(src), get_parser=str, set_cmd='OUTPut{}:POLarity {{}}'.format(src), vals=vals.Enum('NORMal', 'NORM', 'INVerted', 'INV')) self.add_parameter('state_output{}'.format(src), label='Output {} state'.format(src), unit='', get_cmd='OUTPut{}:STATe?'.format(src), get_parser=lambda x: bool(int(x)), set_cmd='OUTPut{}:STATe {{}}'.format(src), vals=vals.Enum('OFF', 0, 'ON', 1)) #: Amplitude modulation self.add_parameter('am_depth{}'.format(src), label='Source {} AM depth'.format(src), unit='%', get_cmd='SOURce{}:AM:DEPTh?'.format(src), get_parser=float, set_cmd='SOURce{}:AM:DEPTh {{}}'.format(src), vals=vals.Strings()) #: Frequency modulation self.add_parameter( 'fm_deviation{}'.format(src), label='Source {} FM deviation'.format(src), unit='Hz', get_cmd='SOURce{}:FM:DEViation?'.format(src), get_parser=float, set_cmd='SOURce{}:FM:DEViation {{}}'.format(src), vals=vals.Strings()) #: Phase modulation self.add_parameter( 'pm_deviation{}'.format(src), label='Source {} PM deviation'.format(src), unit='Radians', get_cmd='SOURce{}:PM:DEViation?'.format(src), get_parser=float, set_cmd='SOURce{}:PM:DEViation {{}}'.format(src), vals=vals.Strings()) #: Pulse-width modulation self.add_parameter( 'pwm_duty_deviation{}'.format(src), label='Source {} PWM duty cycle deviation'.format(src), unit='%', get_cmd='SOURce{}:PWM:DEViation:DCYCle?'.format(src), get_parser=float, set_cmd='SOURce{}:PWM:DEViation:DCYCle {{}}'.format(src), vals=vals.Numbers(min_value=0, max_value=100)) #: Amplitude, frequency, phase, and pulse-width modulation for mod_type in ['AM', 'FM', 'PM', 'PWM']: self.add_parameter( '{}_internal_freq{}'.format(mod_type.lower(), src), label='Source {} {} interal frequency'.format( src, mod_type), unit='Hz', get_cmd='SOURce{}:{}:INTernal:FREQuency?'.format( src, mod_type), get_parser=float, set_cmd='SOURce{}:{}:INTernal:FREQuency {{}}'.format( src, mod_type), vals=vals.Strings()) self.add_parameter( '{}_internal_function{}'.format(mod_type.lower(), src), label='Source {} {} interal function'.format( src, mod_type), unit='', get_cmd='SOURce{}:{}:INTernal:FUNCtion?'.format( src, mod_type), get_parser=str, set_cmd='SOURce{}:{}:INTernal:FUNCtion {{}}'.format( src, mod_type), vals=vals.Enum('SINusoid', 'SIN', 'SQUare', 'SQU', 'TRIangle', 'TRI', 'RAMP', 'NRAMp', 'NRAM', 'PRNoise', 'PRN', 'USER', 'USER1', 'USER2', 'USER3', 'USER4', 'EMEMory', 'EMEM', 'EFILe', 'EFIL')) self.add_parameter( '{}_internal_efile{}'.format(mod_type.lower(), src), label='Source {} {} interal EFile'.format(src, mod_type), unit='', get_cmd='SOURce{}:{}:INTernal:FUNCtion:EFILe?'.format( src, mod_type), get_parser=str, set_cmd='SOURce{}:{}:INTernal:FUNCtion:EFILe {{}}'.format( src, mod_type), vals=vals.Strings()) self.add_parameter( '{}_internal_source{}'.format(mod_type.lower(), src), label='Source {} {} source'.format(src, mod_type), unit='', get_cmd='SOURce{}:{}:SOURce?'.format(src, mod_type), get_parser=str, set_cmd='SOURce{}:{}:SOURce? {{}}'.format(src, mod_type), vals=vals.Enum('INTernal', 'INT', 'EXTernal', 'EXT')) self.add_parameter( '{}_state{}'.format(mod_type.lower(), src), label='Source {} {} interal state'.format(src, mod_type), unit='', get_cmd='SOURce{}:{}:STATe?'.format(src, mod_type), get_parser=lambda x: bool(int(x)), set_cmd='SOURce{}:{}:STATe {{}}'.format(src, mod_type), vals=vals.Enum('OFF', 0, 'ON', 1)) #: Burst mode self.add_parameter('burst_mode{}'.format(src), label='Source {} burst mode'.format(src), unit='', get_cmd='SOURce{}:BURSt:MODE?'.format(src), get_parser=str, set_cmd='SOURce{}:BURSt:MODE {{}}'.format(src), vals=vals.Enum('TRIGgered', 'TRIG', 'GATed', 'GAT')) self.add_parameter( 'burst_ncycles{}'.format(src), label='Source {} burst N cycles'.format(src), unit='', get_cmd='SOURce{}:BURSt:NCYCles?'.format(src), get_parser=float, set_cmd='SOURce{}:BURSt:NCYCles {{}}'.format(src), vals=vals.MultiType( vals.Ints(min_value=1, max_value=1000000), vals.Enum('INFinity', 'INF', 'MAXimum', 'MAX', 'MINimum', 'MIN'))) self.add_parameter('burst_state{}'.format(src), label='Source {} burst state'.format(src), unit='', get_cmd='SOURce{}:BURSt:STATe?'.format(src), get_parser=lambda x: bool(int(x)), set_cmd='SOURce{}:BURSt:STATe {{}}'.format(src), vals=vals.Enum('OFF', 0, 'ON', 1)) self.add_parameter( 'burst_tdelay{}'.format(src), label='Source {} burst time delay'.format(src), unit='s', get_cmd='SOURce{}:BURSt:TDELay?'.format(src), get_parser=float, set_cmd='SOURce{}:BURSt:TDELay {{}}'.format(src), vals=vals.Strings()) if src == 1: combine_enum = ('NOISe', 'NOIS', 'EXTernal', 'EXT', 'BOTH', '') else: combine_enum = ('NOISe', 'NOIS', '') self.add_parameter( 'combine{}'.format(src), label='Source {} combine signals'.format(src), unit='', get_cmd='SOURce{}:COMBine:FEED?'.format(src), get_parser=str, set_cmd='SOURce{}:COMBine:FEED {{}}'.format(src), vals=vals.Enum(combine_enum)) #: Frequency controls self.add_parameter( 'center_freq{}'.format(src), label='Source {} center frequency'.format(src), unit='Hz', get_cmd='SOURce{}:FREQuency:CENTer?'.format(src), get_parser=float, set_cmd='SOURce{}:FREQuency:CENTer {{}}'.format(src), vals=vals.Strings()) self.add_parameter( 'freq_concurrent{}'.format(src), label='Source {} concurrent frequency'.format(src), unit='', get_cmd='SOURce{}:FREQuency:CONCurrent?'.format(src), get_parser=lambda x: bool(int(x)), set_cmd='SOURce{}:FREQuency:CONCurrent {{}}'.format(src), vals=vals.Enum('OFF', 0, 'ON', 1)) self.add_parameter( 'freq_cw{}'.format(src), label='Source {} continuous frequency'.format(src), unit='Hz', get_cmd='SOURce{}:FREQuency:CW?'.format(src), get_parser=float, set_cmd='SOURce{}:FREQuency:CW {{}}'.format(src), vals=vals.Strings()) self.add_parameter( 'freq_fixed{}'.format(src), label='Source {} fixed frequency'.format(src), unit='Hz', get_cmd='SOURce{}:FREQuency:FIXed?'.format(src), get_parser=float, set_cmd='SOURce{}:FREQuency:FIXed {{}}'.format(src), vals=vals.Strings()) self.add_parameter( 'freq_mode{}'.format(src), label='Source {} frequency mode'.format(src), unit='', get_cmd='SOURce{}:FREQuency:MODE?'.format(src), get_parser=str, set_cmd='SOURce{}:FREQuency:MODE {{}}'.format(src), vals=vals.Enum('CW', 'FIXed', 'FIX', 'SWEep', 'SWE')) self.add_parameter( 'freq_span{}'.format(src), label='Source {} frequency span'.format(src), unit='Hz', get_cmd='SOURce{}:FREQuency:SPAN?'.format(src), get_parser=float, set_cmd='SOURce{}:FREQuency:SPAN {{}}'.format(src), vals=vals.Strings()) self.add_parameter( 'freq_start{}'.format(src), label='Source {} frequency start'.format(src), unit='Hz', get_cmd='SOURce{}:FREQuency:STARt?'.format(src), get_parser=float, set_cmd='SOURce{}:FREQuency:STARt {{}}'.format(src), vals=vals.Strings()) self.add_parameter( 'freq_stop{}'.format(src), label='Source {} frequency stop'.format(src), unit='Hz', get_cmd='SOURce{}:FREQuency:STOP?'.format(src), get_parser=float, set_cmd='SOURce{}:FREQuency:STOP {{}}'.format(src), vals=vals.Strings()) #: FSK modulation self.add_parameter( 'fsk_freq{}'.format(src), label='Source {} FSK frequency'.format(src), unit='Hz', get_cmd='SOURce{}:FSKey:FREQuency?'.format(src), get_parser=float, set_cmd='SOURce{}:FSKey:FREQuency {{}}'.format(src), vals=vals.Strings()) self.add_parameter( 'fsk_internal_rate{}'.format(src), label='Source {} FSK internal rate'.format(src), unit='Hz', get_cmd='SOURce{}:FSKey:INTernal:RATE?'.format(src), get_parser=float, set_cmd='SOURce{}:FSKey:INTernal:RATE {{}}'.format(src), vals=vals.Strings()) self.add_parameter( 'fsk_source{}'.format(src), label='Source {} FSK source'.format(src), unit='', get_cmd='SOURce{}:FSKey:SOURce?'.format(src), get_parser=str, set_cmd='SOURce{}:FSKey:SOURce {{}}'.format(src), vals=vals.Enum('INTernal', 'INT', 'EXTernal', 'EXT')) self.add_parameter('fsk_state{}'.format(src), label='Source {} FSK state'.format(src), unit='', get_cmd='SOURce{}:FSKey:STATe?'.format(src), get_parser=lambda x: bool(int(x)), set_cmd='SOURce{}:FSKey:STATe {{}}'.format(src), vals=vals.Enum('OFF', 0, 'ON', 1)) #: Function parameters self.add_parameter( 'function_efile{}'.format(src), label='Source {} function efile'.format(src), unit='', get_cmd='SOURce{}:FUNCtion:EFILe?'.format(src), get_parser=str, set_cmd='SOURce{}:FUNCtion:EFILe {{}}'.format(src), vals=vals.Strings()) self.add_parameter( 'function_ramp_symmetry{}'.format(src), label='Source {} function ramp symmetry'.format(src), unit='%', get_cmd='SOURce{}:FUNCtion:RAMP:SYMMetry?'.format(src), get_parser=float, set_cmd='SOURce{}:FUNCtion:RAMP:SYMMetry {{}}'.format(src), vals=vals.Numbers(min_value=0, max_value=100)) self.add_parameter( 'function_shape{}'.format(src), label='Source {} function shape'.format(src), unit='', get_cmd='SOURce{}:FUNCtion:SHAPe?'.format(src), get_parser=str, set_cmd='SOURce{}:FUNCtion:SHAPe {{}}'.format(src), vals=vals.Enum('SINusoid', 'SIN', 'SQUare', 'SQU', 'TRIangle', 'TRI', 'RAMP', 'NRAMp', 'NRAM', 'PRNoise', 'PRN', 'USER', 'USER1', 'USER2', 'USER3', 'USER4', 'EMEMory', 'EMEM', 'EFILe', 'EFIL', 'USER', 'USER1', 'USER2', 'USER3', 'USER4', 'EMEMory', 'EMEM', 'EFILe', 'EFIL')) #: Phase parameters self.add_parameter( 'phase{}'.format(src), label='Source {} phase'.format(src), unit='Radians', get_cmd='SOURce{}:PHASe:ADJust?'.format(src), get_parser=float, set_cmd='SOURce{}:PHASe:ADJust {{}}'.format(src), vals=vals.Strings()) #: Pulse parameters self.add_parameter( 'pulse_duty_cycle{}'.format(src), label='Source {} pulse duty cycle'.format(src), unit='%', get_cmd='SOURce{}:PULSe:DCYCle?'.format(src), get_parser=float, set_cmd='SOURce{}:PULSe:DCYCle {{}}'.format(src), vals=vals.Strings()) self.add_parameter('pulse_delay{}'.format(src), label='Source {} pulse delay'.format(src), unit='s', get_cmd='SOURce{}:PULSe:DELay?'.format(src), get_parser=float, set_cmd='SOURce{}:PULSe:DELay {{}}'.format(src), vals=vals.Strings()) self.add_parameter('pulse_hold{}'.format(src), label='Source {} pulse hold'.format(src), unit='', get_cmd='SOURce{}:PULSe:HOLD?'.format(src), get_parser=str, set_cmd='SOURce{}:PULSe:HOLD {{}}'.format(src), vals=vals.Enum('WIDTh', 'WIDT', 'DUTY')) self.add_parameter( 'pulse_period{}'.format(src), label='Source {} pulse period'.format(src), unit='s', get_cmd='SOURce{}:PULSe:PERiod?'.format(src), get_parser=float, set_cmd='SOURce{}:PULSe:PERiod {{}}'.format(src), vals=vals.Strings()) self.add_parameter( 'pulse_trans_lead{}'.format(src), label='Source {} pulse leading edge time'.format(src), unit='s', get_cmd='SOURce{}:PULSe:TRANsition:LEADing?'.format(src), get_parser=float, set_cmd='SOURce{}:PULSe:TRANsition:LEADing {{}}'.format(src), vals=vals.Strings()) self.add_parameter( 'pulse_trans_trail{}'.format(src), label='Source {} pulse trailing edge time'.format(src), unit='s', get_cmd='SOURce{}:PULSe:TRANsition:TRAiling?'.format(src), get_parser=float, set_cmd='SOURce{}:PULSe:TRANsition:TRAiling {{}}'.format(src), vals=vals.Strings()) self.add_parameter('pulse_width{}'.format(src), label='Source {} pulse width'.format(src), unit='s', get_cmd='SOURce{}:PULSe:WIDTh?'.format(src), get_parser=float, set_cmd='SOURce{}:PULSe:WIDTh {{}}'.format(src), vals=vals.Strings()) #: Sweep parameters self.add_parameter('sweep_hold_time{}'.format(src), label='Source {} sweep hold time'.format(src), unit='s', get_cmd='SOURce{}:SWEep:HTIMe?'.format(src), get_parser=float, set_cmd='SOURce{}:SWEep:HTIMe {{}}'.format(src), vals=vals.Strings()) self.add_parameter('sweep_mode{}'.format(src), label='Source {} sweep mode'.format(src), unit='', get_cmd='SOURce{}:SWEep:MODE?'.format(src), get_parser=str, set_cmd='SOURce{}:SWEep:MODE {{}}'.format(src), vals=vals.Enum('AUTO', 'MANual', 'MAN')) self.add_parameter('sweep_return_time{}'.format(src), label='Source {} sweep return time'.format(src), unit='s', get_cmd='SOURce{}:SWEep:RTIMe?'.format(src), get_parser=float, set_cmd='SOURce{}:SWEep:RTIMe {{}}'.format(src), vals=vals.Strings()) self.add_parameter( 'sweep_spacing{}'.format(src), label='Source {} sweep spacing'.format(src), unit='', get_cmd='SOURce{}:SWEep:SPACing?'.format(src), get_parser=str, set_cmd='SOURce{}:SWEep:SPACing {{}}'.format(src), vals=vals.Enum('LINear', 'LIN', 'LOGarithmic', 'LOG')) self.add_parameter('sweep_time{}'.format(src), label='Source {} sweep time'.format(src), unit='s', get_cmd='SOURce{}:SWEep:TIME?'.format(src), get_parser=float, set_cmd='SOURce{}:SWEep:TIME {{}}'.format(src), vals=vals.Strings()) #: Voltage parameters self.add_parameter( 'voltage_concurrent{}'.format(src), label='Source {} concurrent voltage'.format(src), unit='', get_cmd='SOURce{}:VOLTage:CONCurrent:STATe?'.format(src), get_parser=lambda x: bool(int(x)), set_cmd='SOURce{}:VOLTage:CONCurrent:STATe {{}}'.format(src), vals=vals.Enum('OFF', 0, 'ON', 1)) self.add_parameter( 'voltage_high{}'.format(src), label='Source {} high voltage level'.format(src), unit='V', get_cmd='SOURce{}:VOLTage:LEVel:IMMediate:HIGH?'.format(src), get_parser=float, set_cmd='SOURce{}:VOLTage:LEVel:IMMediate:HIGH {{}}'.format( src), vals=vals.Strings()) self.add_parameter( 'voltage_low{}'.format(src), label='Source {} low voltage level'.format(src), unit='V', get_cmd='SOURce{}:VOLTage:LEVel:IMMediate:LOW?'.format(src), get_parser=float, set_cmd='SOURce{}:VOLTage:LEVel:IMMediate:LOW {{}}'.format( src), vals=vals.Strings()) self.add_parameter( 'voltage_offset{}'.format(src), label='Source {} voltage offset'.format(src), unit='V', get_cmd='SOURce{}:VOLTage:LEVel:IMMediate:OFFSet?'.format(src), get_parser=float, set_cmd='SOURce{}:VOLTage:LEVel:IMMediate:OFFSet {{}}'.format( src), vals=vals.Strings()) self.add_parameter( 'voltage_unit{}'.format(src), label='Source {} voltage unit'.format(src), unit='', get_cmd='SOURce{}:VOLTage:UNIT?'.format(src), get_parser=str, set_cmd='SOURce{}:VOLTage:UNIT {{}}'.format(src), vals=vals.Enum('VPP', 'VRMS', 'DBM')) self.add_parameter( 'voltage_amplitude{}'.format(src), label='Source {} voltage amplitude'.format(src), unit=getattr(self, 'voltage_unit{}'.format(src))(), get_cmd='SOURce{}:VOLTage:LEVel:IMMediate:AMPLitude?'.format( src), get_parser=float, set_cmd='SOURce{}:VOLTage:LEVel:IMMediate:AMPLitude {{}}'. format(src), vals=vals.Strings()) self.add_parameter( 'voltage_limit_high{}'.format(src), label='Source {} voltage limit high'.format(src), unit='V', get_cmd='SOURce{}:VOLTage:LIMit:HIGH?'.format(src), get_parser=float, set_cmd='SOURce{}:VOLTage:LIMit:HIGH {{}}'.format(src), vals=vals.Strings()) self.add_parameter( 'voltage_limit_low{}'.format(src), label='Source {} voltage limit low'.format(src), unit='V', get_cmd='SOURce{}:VOLTage:LIMit:LOW?'.format(src), get_parser=float, set_cmd='SOURce{}:VOLTage:LIMit:LOW {{}}'.format(src), vals=vals.Strings()) #: Noise parameters for src in [3, 4]: self.add_parameter( 'noise_level{}'.format(src), label='Source {} noise level'.format(src), unit='%', get_cmd='SOURce{}:POWer:LEVel:IMMediate:AMPLitude?'.format( src), get_parser=float, set_cmd='SOURce{}:POWer:LEVel:IMMediate:AMPLitude {{}}'.format( src), vals=vals.Strings()) self.add_parameter('ref_osc_source', label='Reference clock source'.format(src), unit='', get_cmd='SOURce:ROSCillator:SOURce?', get_parser=str, set_cmd='SOURce:ROSCillator:SOURce {}', vals=vals.Enum('INTernal', 'INT', 'EXTernal', 'EXT')) #: Trigger parameters self.add_parameter('trigger_slope', label='Trigger slope', unit='', get_cmd='TRIGger:SEQuence:SLOPe?', get_parser=str, set_cmd='TRIGger:SEQuence:SLOPe {}', vals=vals.Enum('POSitive', 'POS', 'NEGative', 'NEG')) self.add_parameter('trigger_source', label='Trigger source', unit='', get_cmd='TRIGger:SEQuence:SOURce?', get_parser=str, set_cmd='TRIGger:SEQuence:SOURce {}', vals=vals.Enum('TIMer', 'TIM', 'EXTernal', 'EXT')) self.add_parameter('trigger_timer', label='Trigger timer period', unit='s', get_cmd='TRIGger:SEQuence:TIMer?', get_parser=float, set_cmd='TRIGger:SEQuence:TIMer {}', vals=vals.Strings()) self.snapshot(update=True) self.connect_message()
def __init__(self, instrument_name, **kwargs): super().__init__(instrument_name, **kwargs) # Initialize channels self._input_channels = { 'ext1': Channel(instrument_name=self.instrument_name(), name='ext1', input=True), 'ext2': Channel(instrument_name=self.instrument_name(), name='ext2', input=True), 'int1': Channel(instrument_name=self.instrument_name(), name='int1', input=True), 'int2': Channel(instrument_name=self.instrument_name(), name='int2', input=True), 'I': Channel(instrument_name=self.instrument_name(), name='I', input=True), 'Q': Channel(instrument_name=self.instrument_name(), name='Q', input=True) } self._output_channels = { 'RF_out': Channel(instrument_name=self.instrument_name(), name='RF_out', output=True), } self._channels = { **self._input_channels, **self._output_channels, 'trig_in': Channel(instrument_name=self.instrument_name(), name='trig_in', input=True), 'pattern_trig_in': Channel(instrument_name=self.instrument_name(), name='pattern_trig_in', input=True) } self.pulse_implementations = [ SinePulseImplementation( pulse_requirements=[('frequency', {'min': 250e3, 'max': 44e9})] ), MultiSinePulseImplementation(), SingleWaveformPulseImplementation(), FrequencyRampPulseImplementation( pulse_requirements=[ ('frequency_start', {'min': 250e3, 'max': 44e9}), ('frequency_stop', {'min': 250e3, 'max': 44e9})] ) ] self.add_parameter('envelope_padding', unit='s', set_cmd=None, initial_value=0, vals=vals.Numbers(min_value=0, max_value=10e-3), docstring="Padding for any pulses that use either " "IQ and/or FM modulation. This is to " "ensure that any such pulses start before " "the gate marker pulse, and end afterwards. " "This is ignored for chirp pulses where " "FM_mode = 'IQ'.") self.envelope_IQ = Parameter( set_cmd=None, vals=vals.Bool(), initial_value=True, docstring="Apply the envelope padding to the IQ pulse instead of marker pulse." "If True, the marker pulse length equals the pulse length, and the " "I and Q pulses are extended by the envelope padding " "before (after) the pulse start (stop) time. " "If False, the marker pulse starts before (after) the pulse start (stop) " "time, and the IQ pulses starts (stops) at the pulse start (stop) time." "This means that there might be some leakage at the carrier frequency " "when the IQ is zero, but the marker pulse is still high." ) self.add_parameter('I_phase_correction', unit='deg', set_cmd=None, initial_value=0, docstring="Additional phase added to I pulse, which compensates " "any phase mismatch between I and Q components. Only for " "FM_mode = 'IQ'.") self.add_parameter('Q_phase_correction', unit='deg', set_cmd=None, initial_value=0, docstring="Additional phase added to Q pulse, which compensates " "any phase mismatch between Q and I components. Only for " "FM_mode = 'IQ'.") self.add_parameter('I_amplitude_correction', unit='V', set_cmd=None, initial_value=0, vals=vals.Numbers(min_value=-1, max_value=0), docstring="Amplitude correction added to the amplitude of I pulse" "to compensate for any mismatch in amplitude/power " "between I and Q components. The correction is restricted " "in value between -1V to 0V to ensure the I/Q inputs do not " "receive signals above 1V. Only for FM_mode = 'IQ'.") self.add_parameter('Q_amplitude_correction', unit='V', set_cmd=None, initial_value=0, vals=vals.Numbers(min_value=-1, max_value=0), docstring="Amplitude correction added to the amplitude of Q pulse" "to compensate for any mismatch in amplitude/power " "between Q and I components. The correction is restricted " "in value between -1V to 0V to ensure the I/Q inputs do not " "receive signals above 1V. Only for FM_mode = 'IQ'.") self.add_parameter('marker_amplitude', unit='V', set_cmd=None, initial_value=1.5, docstring="Amplitude of marker pulse used for gating") self.add_parameter('modulation_channel', set_cmd=None, initial_value='ext1', vals=vals.Enum(*self._input_channels), docstring="Channel to use for FM.") self.add_parameter('fix_frequency', set_cmd=None, initial_value=False, vals=vals.Bool(), docstring="Whether to fix frequency to current " "value, or to dynamically choose frequency" " during setup") self.add_parameter('fix_frequency_deviation', set_cmd=None, initial_value=False, vals=vals.Bool(), docstring="Whether to fix frequency_deviation to " "current value, or to dynamically choose " "deviation during setup") self.add_parameter('frequency_carrier_choice', set_cmd=None, initial_value='center', vals=vals.MultiType(vals.Enum('min', 'center', 'max'), vals.Numbers()), docstring='The choice for the microwave frequency, ' 'This is used if pulses with multiple ' 'frequencies are used, or if frequency ' 'modulation is needed. Ignored if ' 'fix_frequency = True. Can be either "max",' '"min", or "center", or a number which is ' 'the offset from the center') self.add_parameter('frequency', unit='Hz', set_cmd=None, initial_value=None) self.add_parameter('frequency_deviation', unit='Hz', set_cmd=None, initial_value=None) self.add_parameter('power', unit='dBm', set_cmd=None, initial_value=None) self.add_parameter('IQ_modulation', initial_value=None, vals=vals.Enum('on', 'off'), docstring='Whether to use IQ modulation. This ' 'cannot be directly set, but is determined ' 'by FM_mode and whether pulses have ' 'frequency_sideband not None.') self.add_parameter('IQ_channels', initial_value='IQ', vals=vals.Enum('IQ', 'I', 'Q'), set_cmd=None, docstring="Which channels to use for IQ modulation." "Double-sideband modulation is used if only 'I' or 'Q' " "is chosen, while single-sideband modulation is used when " "'IQ' is chosen.") self.add_parameter('force_IQ', set_cmd=None, initial_value=False, vals=vals.Bool(), docstring='Force IQ modulation to be enabled, even when' 'outputting only a single frequency.') self.add_parameter('FM_mode', set_cmd=None, initial_value='ramp', vals=vals.Enum('ramp', 'IQ'), docstring="Type of frequency modulation used. " "Can be either 'ramp' in which case the " "internal FM is used by converting a DC " "amplitude from an ext port, or 'IQ', in " "which case the internal FM is turned off.")
def __init__(self, name: str, address: str, **kwargs): super().__init__(name, address, terminator='\n', **kwargs) self.range_vals = { 2e-3: 0, 20e-3: 1, 200e-3: 2, 2: 3, 20: 4, 200: 5, 2e3: 6, 20e3: 7, 200e3: 8, 2e6: 9, np.nan: np.nan } self.excitation_vals = { 20e-6: 0, 60e-6: 1, 200e-6: 2, 600e-6: 3, 2e-3: 4, 6e-3: 5, 20e-3: 6, np.nan: np.nan } self.dfilter_vals = { 0.2: '00', 0.4: '01', 0.6: '02', 0.8: '03', 1.0: '04', 1.6: '05', 2.0: '06', 3.0: '07', 5.0: '08', 7.0: '09', 10.0: '10', 15.0: '11', 20.0: '12', 30.0: '13', 45.0: '14', 60.0: '15', 90.0: '16', 120.0: '17', 180.0: '18', 300.0: '19', 420.0: '20', 600.0: '21', 900.0: '22', 1200.0: '23', 1800.0: '24', np.nan: np.nan } self.afilter_vals = { 0.01: 0, 0.1: 1, 0.3: 2, 1.0: 3, 3.0: 4, 10.0: 5, 30.0: 6 } self.add_parameter('range', set_cmd='Range {}', val_mapping=self.range_vals, get_cmd=partial(self.get_string_repeat, 'Get 6'), get_parser=partial(self.get6parser, 'range'), unit='Ohms') self.add_parameter('autorange', set_cmd='Autorange {}', vals=vals.Ints(0, 1)) self.add_parameter('excitation', set_cmd='Excitation {}', get_cmd=partial(self.get_string_repeat, 'Get 6'), get_parser=partial(self.get6parser, 'excitation'), val_mapping=self.excitation_vals, unit='V') self.add_parameter('exc_pct', set_cmd='Varexc ={}', set_parser=partial(zfill_parser, 2), get_cmd=partial(self.get_string_repeat, 'Get 6'), get_parser=partial(self.get6parser, 'exc_pct'), vals=vals.Ints(5, 99)) self.add_parameter('exc_pct_on', set_cmd='Varexc {}', vals=vals.Ints(0, 1)) self.add_parameter('R_measure', get_cmd=partial(self.get_string_repeat, 'Get 0'), unit='Ohms', get_parser=R_parser) self.add_parameter('DelR_measure', get_cmd=partial(self.get_string_repeat, 'Get 2'), get_parser=R_parser, unit='Ohms') self.add_parameter('X_measure', get_cmd=partial(self.get_string_repeat, 'Get 1'), get_parser=R_parser) self.add_parameter('DelX_measure', get_cmd=partial(self.get_string_repeat, 'Get 3'), get_parser=R_parser) self.add_parameter('x10mode', set_cmd='Mode {}', get_cmd=partial(self.get_string_repeat, 'Get 6'), get_parser=partial(self.get6parser, 'x10mode'), vals=vals.Ints(0, 1)) self.add_parameter('dfilter', set_cmd=self.dfilter_set, get_cmd=partial(self.get_string_repeat, 'Get 6'), get_parser=partial(self.get6parser, 'dfilter'), val_mapping=self.dfilter_vals, unit='s') self.add_parameter('afilter', set_cmd='Noise F={}', val_mapping=self.afilter_vals, unit='s') self.add_parameter('afilter_input', set_cmd='Noise I={}', val_mapping={ 'delR': 0, 'delX': 1 }) self.add_parameter('R_offset', label='LR Resistance', set_cmd='Offset {}', set_parser=partial(offset_parser, 'R'), get_cmd=partial(self.get_string_repeat, 'Get 4'), get_parser=R_parser, unit='Ohms', vals=vals.MultiType(vals.Numbers(-99.9995, 99.9995), vals.Enum('R', 'X'))) self.add_parameter('X_offset', set_cmd='Offset {}', set_parser=partial(offset_parser, 'X'), get_cmd=partial(self.get_string_repeat, 'Get 5'), get_parser=R_parser, vals=vals.MultiType(vals.Numbers(-99.9995, 99.9995), vals.Enum('R', 'X')))
def __init__(self, name: str, address: str, reset: bool=False, **kwargs): """ Args: name: Name to use internally in QCoDeS address: VISA ressource address reset: Set Keithley to defaults? True or False """ super().__init__(name, address, terminator='\n', **kwargs) self._ac_init = False self._ac_ampl = False self._ac_freq = False self.add_parameter('current', label='Current', get_cmd='SOUR:CURR?', set_cmd='SOUR:CURR {}', get_parser=float, unit='A', vals=vals.Numbers()) self.add_parameter('output', get_cmd='OUTP:STAT?', set_cmd='OUTP:STAT {}', get_parser=int, set_parser=parse_output_bool, vals=vals.Enum(*boolcheck)) self.add_parameter('range', get_cmd='CURR:RANG?', set_cmd='CURR:RANG {}', get_parser=float, unit='A', vals=vals.Numbers(-105e-3, 105e-3)) self.add_parameter('auto_range', get_cmd='CURR:RANG:AUTO?', set_cmd='CURR:RANG:AUTO {}', get_parser=int, set_parser=parse_output_bool, vals=vals.Enum(*boolcheck)) self.add_parameter('compliance', get_cmd='CURR:COMP?', set_cmd='CURR:COMP {}', unit='V', get_parser=float, vals=vals.Numbers(-.1, 105)) self.add_parameter('delay', unit='s', get_cmd='SOUR:DEL?', set_cmd='SOUR:DEL {}', get_parser=float, vals=vals.Numbers(0.001, 999999.999)) self.add_parameter('filter', get_cmd='CURR:FILT?', set_cmd='CURR:FILT {}', get_parser=int, set_parser=parse_output_bool, vals=vals.Enum(*boolcheck)) self.add_parameter('speed', get_cmd='OUTP:RESP?', set_cmd='OUTP:RESP {}', get_parser=str, vals=vals.Enum('slow', 'fast', 'SLOW', 'FAST')) self.add_parameter('display', snapshot_get=False, get_cmd='DISP:ENAB?', set_cmd='DISP:ENAB {}', get_parser=int, set_parser=parse_output_bool, vals=vals.Enum(*boolcheck)) self.add_parameter('beeper', snapshot_get=False, get_cmd='SYST:BEEP?', set_cmd='SYST:BEEP {}', get_parser=int, set_parser=parse_output_bool, vals=vals.Enum(*boolcheck)) self.add_parameter('AC_amplitude', get_cmd='SOUR:WAVE:AMPL?', set_cmd=self._setac_amplitude, get_parser=float, unit='A', vals=vals.Numbers(2e-12, 0.105)) self.add_parameter('AC_frequency', get_cmd='SOUR:WAVE:FREQ?', set_cmd=self._setac_frequency, get_parser=float, unit='Hz', vals=vals.Numbers(0, 1e5)) self.add_parameter('AC_offset', get_cmd='SOUR:WAVE:OFFS?', set_cmd='SOUR:WAVE:OFFS {}', get_parser=float, unit='A', vals=vals.Numbers(-0.105, 0.105)) self.add_parameter('AC_duration_time', get_cmd='SOUR:WAVE:DUR:TIME?', set_cmd='SOUR:WAVE:DUR:TIME {}', get_parser=float, unit='s', vals=vals.MultiType(vals.Enum('INF'), vals.Numbers(100e-9, 999999.999))) self.add_parameter('AC_duration_cycles', get_cmd='SOUR:WAVE:DUR:CYCL?', set_cmd='SOUR:WAVE:DUR:CYCL {}', get_parser=float, unit='cycles', vals=vals.MultiType(vals.Enum('INF'), vals.Numbers(0.001, 99999999900))) self.add_parameter('AC_phasemark', get_cmd='SOUR:WAVE:PMAR:STAT?', set_cmd='SOUR:WAVE:PMAR:STAT {}', get_parser=int, set_parser=parse_output_bool, vals=vals.Enum(*boolcheck)) self.add_parameter('AC_phasemark_offset', get_cmd='SOUR:WAVE:PMAR?', set_cmd='SOUR:WAVE:PMAR {}', get_parser=float, unit='degrees', vals=vals.Numbers(0, 360)) self.add_parameter('AC_ranging', get_cmd='SOUR:WAVE:RANG?', set_cmd='SOUR:WAVE:RANG {}', get_parser=str, vals=vals.Enum('BEST', 'best', 'FIX', 'fix', 'FIXED', 'fixed')) # Related to attached 2182(a) nanovoltmeter self.add_parameter('unit', label='diff conductance unit', get_cmd='UNIT?', set_cmd='UNIT {}', initial_value='OHMS', get_parser=str, vals=vals.Enum('V', 'ohms', 'OHMS', 'S', 'SIEM', 'siem', 'siemens', 'SIEMENS')) self.add_parameter('k2182_present', get_cmd='SOUR:DELT:NVPR?', get_parser=int) self.add_parameter('delta_arm', get_cmd='SOUR:DELT:ARM?', get_parser=int) self.add_parameter('diff_arm', get_cmd='SOUR:DCON:ARM?', get_parser=int) self.add_parameter('delta_IV_sweep', # STILL A WORK IN PROGRESS snapshot_get=False, get_cmd=self.delta_IV_sweep_get, set_cmd=self.delta_IV_sweep_set, get_parser=float, set_parser=float) # These are only useable if you have connected to the Keithley 2182 # Through an RS-232 port. Make sure to check the settings on the 2182 # at set to GPIB: off, RS-232 on self.add_parameter('k2_measure', snapshot_get=False, get_cmd=partial(self.k2_read_cmd, 'SENS:DATA:FRES?'), get_parser=float, unit='V') self.add_parameter('k2_range', snapshot_get=False, set_cmd='SYST:COMM:SER:SEND "VOLT:RANG {}"', get_cmd=partial(self.k2_read_cmd, 'VOLT:RANG?'), set_parser=float, get_parser=float, vals=vals.Numbers(0, 120)) self.add_parameter('k2_nplc', snapshot_get=False, set_cmd='SYST:COMM:SER:SEND "VOLT:NPLC {}"', get_cmd=partial(self.k2_read_cmd, 'VOLT:NPLC?'), set_parser=float, get_parser=float, vals=vals.Numbers(0.01, 60)) self.add_parameter('k2_line_sync', snapshot_get=False, set_cmd='SYST:COMM:SER:SEND "SYST:LSYN {}"', get_cmd=partial(self.k2_read_cmd, 'SYST:LSYN?'), set_parser=parse_output_bool, get_parser=int, vals=vals.Enum(*boolcheck)) self.add_parameter('k2_front_autozero', snapshot_get=False, set_cmd='SYST:COMM:SER:SEND "SYST:FAZ {}"', get_cmd=partial(self.k2_read_cmd, 'SYST:FAZ?'), set_parser=parse_output_bool, get_parser=int, vals=vals.Enum(*boolcheck)) self.add_parameter('k2_autozero', snapshot_get=False, set_cmd='SYST:COMM:SER:SEND "SYST:AZER {}"', get_cmd=partial(self.k2_read_cmd, 'SYST:AZER?'), set_parser=parse_output_bool, get_parser=int, vals=vals.Enum(*boolcheck)) self.add_parameter('k2_dfilter_count', snapshot_get=False, get_cmd=partial(self.k2_read_cmd, 'SENS:VOLT:DFIL:COUN?'), set_cmd='SYST:COMM:SER:SEND "SENS:VOLT:DFIL:COUN {}"', get_parser=int, set_parser=int, vals=vals.Ints(1, 100)) self.add_parameter('k2_dfilter_window', snapshot_get=False, get_cmd=partial(self.k2_read_cmd, 'SENS:VOLT:DFIL:WIND?'), set_cmd='SYST:COMM:SER:SEND "SENS:VOLT:DFIL:WIND {}"', get_parser=float, set_parser=float, vals=vals.Numbers(0.01, 10)) self.add_parameter('k2_dfilter_type', snapshot_get=False, get_cmd=partial(self.k2_read_cmd, 'SENS:VOLT:DFIL:TCON?'), set_cmd='SYST:COMM:SER:SEND "SENS:VOLT:DFIL:TCON {}"', vals=vals.Enum('MOV', 'REP')) self.add_function('abort_arm', call_cmd='SOUR:SWE:ABOR') self.add_function('reset', call_cmd='*RST') # TODO: Getting error messages doesn't work self.add_function('get_error', call_cmd='SYST:ERR?') if reset: self.reset() self.connect_message()
def __init__(self, name, timeout=5, address=''): Instrument.__init__(self, name) self._address = address self._terminator = '' self.add_parameter('timeout', unit='s', initial_value=5, parameter_class=ManualParameter, vals=vals.MultiType(vals.Numbers(min_value=0), vals.Enum(None))) self.add_parameter('address', unit='', initial_value='', parameter_class=ManualParameter, vals=vals.Strings()) self.add_parameter('DC_output', label='DC Output (ON/OFF)', parameter_class=ManualParameter, vals=vals.Ints(0, 1)) for i in range(1, 5): self.add_parameter('ch{}_state'.format(i), initial_value=1, label='Status channel {}'.format(i), parameter_class=ManualParameter, vals=vals.Ints(0, 1)) self.add_parameter('ch{}_amp'.format(i), initial_value=1., label='Amplitude channel {}'.format(i), unit='Vpp', parameter_class=ManualParameter, vals=vals.Numbers(0.02, 4.5)) self.add_parameter('ch{}_offset'.format(i), initial_value=0, label='Offset channel {}'.format(i), unit='V', parameter_class=ManualParameter, vals=vals.Numbers(-.1, .1)) self.add_parameter('ch{}_waveform'.format(i), initial_value="", label='Waveform channel {}'.format(i), parameter_class=ManualParameter, vals=vals.Strings()) self.add_parameter('ch{}_direct_output'.format(i), initial_value=1, label='Direct output channel {}'.format(i), parameter_class=ManualParameter, vals=vals.Ints(0, 1)) self.add_parameter('ch{}_filter'.format(i), initial_value='INF', label='Low pass filter channel {}'.format(i), unit='Hz', parameter_class=ManualParameter, vals=vals.Enum(20e6, 100e6, 9.9e37, 'INF', 'INFinity')) self.add_parameter('ch{}_DC_out'.format(i), initial_value=0, label='DC output level channel {}'.format(i), unit='V', parameter_class=ManualParameter, vals=vals.Numbers(-3, 5)) for j in range(1, 3): self.add_parameter('ch{}_m{}_del'.format(i, j), initial_value=0, label='Channel {} Marker {} delay'.format( i, j), unit='ns', parameter_class=ManualParameter, vals=vals.Numbers(0, 1)) self.add_parameter( 'ch{}_m{}_high'.format(i, j), initial_value=2, label='Channel {} Marker {} high level'.format(i, j), unit='V', parameter_class=ManualParameter, vals=vals.Numbers(-2.7, 2.7)) self.add_parameter( 'ch{}_m{}_low'.format(i, j), initial_value=0, label='Channel {} Marker {} low level'.format(i, j), unit='V', parameter_class=ManualParameter, vals=vals.Numbers(-2.7, 2.7)) self.add_parameter('clock_freq', label='Clock frequency', unit='Hz', vals=vals.Numbers(1e6, 1.2e9), parameter_class=ManualParameter, initial_value=1.2e9) self.awg_files = {} self.file = None self.stop() # to init self._state
def __init__(self, instrument_name, **kwargs): super().__init__(instrument_name, **kwargs) # Initialize channels self._input_channels = { 'ext1': Channel(instrument_name=self.instrument_name(), name='ext1', input=True), 'ext2': Channel(instrument_name=self.instrument_name(), name='ext2', input=True), 'I': Channel(instrument_name=self.instrument_name(), name='I', input=True), 'Q': Channel(instrument_name=self.instrument_name(), name='Q', input=True) } self._output_channels = { 'RF_out': Channel(instrument_name=self.instrument_name(), name='RF_out', output=True), } self._channels = { **self._input_channels, **self._output_channels, 'trig_in': Channel(instrument_name=self.instrument_name(), name='trig_in', input=True), 'pattern_trig_in': Channel(instrument_name=self.instrument_name(), name='pattern_trig_in', input=True) } self.pulse_implementations = [ SinePulseImplementation( pulse_requirements=[('frequency', {'min': 250e3, 'max': 44e9})] ), FrequencyRampPulseImplementation( pulse_requirements=[ ('frequency_start', {'min': 250e3, 'max': 44e9}), ('frequency_stop', {'min': 250e3, 'max': 44e9})] ) ] self.add_parameter('envelope_padding', unit='s', set_cmd=None, initial_value=0, vals=vals.Numbers(min_value=0, max_value=10e-3), docstring="Padding for any pulses that use either " "IQ and/or FM modulation. This is to " "ensure that any such pulses start before " "the gate marker pulse, and end afterwards. " "This is ignored for chirp pulses where " "FM_mode = 'IQ'.") self.add_parameter('marker_amplitude', unit='V', set_cmd=None, initial_value=1.5, docstring="Amplitude of marker pulse used for gating") self.add_parameter('modulation_channel', set_cmd=None, initial_value='ext1', vals=vals.Enum(*self._input_channels), docstring="Channel to use for FM.") self.add_parameter('fix_frequency', set_cmd=None, initial_value=False, vals=vals.Bool(), docstring="Whether to fix frequency to current " "value, or to dynamically choose frequency" " during setup") self.add_parameter('fix_frequency_deviation', set_cmd=None, initial_value=False, vals=vals.Bool(), docstring="Whether to fix frequency_deviation to " "current value, or to dynamically choose " "deviation during setup") self.add_parameter('frequency_carrier_choice', set_cmd=None, initial_value='center', vals=vals.MultiType(vals.Enum('min', 'center', 'max'), vals.Numbers()), docstring='The choice for the microwave frequency, ' 'This is used if pulses with multiple ' 'frequencies are used, or if frequency ' 'modulation is needed. Ignored if ' 'fix_frequency = True. Can be either "max",' '"min", or "center", or a number which is ' 'the offset from the center') self.add_parameter('frequency', unit='Hz', set_cmd=None, initial_value=None) self.add_parameter('frequency_deviation', unit='Hz', set_cmd=None, initial_value=None) self.add_parameter('IQ_modulation', initial_value=None, vals=vals.Enum('on', 'off'), docstring='Whether to use IQ modulation. This ' 'cannot be directly set, but is determined ' 'by FM_mode and whether pulses have ' 'frequency_sideband not None') self.add_parameter('FM_mode', set_cmd=None, initial_value='ramp', vals=vals.Enum('ramp', 'IQ'), docstring="Type of frequency modulation used. " "Can be either 'ramp' in which case the " "internal FM is used by converting a DC " "amplitude from an ext port, or 'IQ', in " "which case the internal FM is turned off.")
def __init__(self, name: str = 'Pulsar', master_awg: str = None): """Pulsar constructor. Args: name: Instrument name. master_awg: Name of the AWG that triggers all the other AWG-s and should be started last (after other AWG-s are already waiting for a trigger. """ super().__init__(name) self._sequence_cache = dict() self.reset_sequence_cache() self.add_parameter('master_awg', parameter_class=InstrumentRefParameter, initial_value=master_awg) self.add_parameter('inter_element_spacing', vals=vals.MultiType(vals.Numbers(0), vals.Enum('auto')), set_cmd=self._set_inter_element_spacing, get_cmd=self._get_inter_element_spacing) self.add_parameter('reuse_waveforms', initial_value=False, parameter_class=ManualParameter, vals=vals.Bool()) self.add_parameter('use_sequence_cache', initial_value=False, parameter_class=ManualParameter, vals=vals.Bool(), set_parser=self._use_sequence_cache_parser) self.add_parameter('prepend_zeros', initial_value=0, vals=vals.Ints(), parameter_class=ManualParameter) self.add_parameter('flux_crosstalk_cancellation', initial_value=False, parameter_class=ManualParameter) self.add_parameter('flux_channels', initial_value=[], parameter_class=ManualParameter) self.add_parameter('flux_crosstalk_cancellation_mtx', initial_value=None, parameter_class=ManualParameter) self.add_parameter('flux_crosstalk_cancellation_shift_mtx', initial_value=None, parameter_class=ManualParameter) self.add_parameter('resolve_overlapping_elements', vals=vals.Bool(), initial_value=False, parameter_class=ManualParameter, docstring='Flag determining whether overlapping ' 'elements should be resolved by ' 'combining them into one element. NB: ' 'overlap resolution only applies to' 'non-trigger elements!') # This parameter can be used to record only a specified consecutive # subset of segments of a programmed hard sweep. This is used by the # sweep function FilteredSweep. The parameter expects a tuple of indices # indicating the first and the last segment to be measured. (Segments # with the property allow_filter set to False are always measured.) self.add_parameter('filter_segments', set_cmd=self._set_filter_segments, get_cmd=self._get_filter_segments, initial_value=None) self.add_parameter('sigouts_on_after_programming', initial_value=True, parameter_class=ManualParameter, vals=vals.Bool(), docstring='Whether signal outputs should be ' 'switched off automatically after ' 'programming a AWGs. Can be set to ' 'False to save time if it is ensured ' 'that the channels are switched on ' 'somewhere else.') self.add_parameter('trigger_pulse_parameters', initial_value={}, label='trigger pulse parameters', parameter_class=ManualParameter, docstring='A dict whose keys are channel names and ' 'whose values are dicts of pulse ' 'parameters to overwrite the default ' 'trigger pulse parameters whenever a ' 'trigger pulse is played on the ' 'respective channel. In addition, the ' 'dict can contain keys of the form ' '{channel}_first to provide different ' 'parameters for the first trigger pulse ' 'on that channel in a sequence.') self._inter_element_spacing = 'auto' self.channels = set() # channel names self.awgs: Set[str] = set() # AWG names self.awg_interfaces: Dict[str, PulsarAWGInterface] = {} self.last_sequence = None self.last_elements = None self._awgs_with_waveforms = set() self.channel_groups = {} self.num_channel_groups = {} self._awgs_prequeried_state = False self._hash_to_wavename_table = {} self._filter_segments = None Pulsar._instance = self
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: "QDac", name: str, channum: int): """ Args: parent: The instrument to which the channel belongs. name: The name of the channel channum: The number of the channel (1-24 or 1-48) """ super().__init__(parent, name) # Add the parameters self.add_parameter( name='v', label=f'Channel {channum} voltage', unit='V', set_cmd=partial(self._parent._set_voltage, channum), get_cmd=f'set {channum}', get_parser=float, # Initial range. Updated on init and during # operation: vals=vals.Numbers(-9.99, 9.99)) self.add_parameter(name='mode', label=f'Channel {channum} mode.', set_cmd=partial(self._parent._set_mode, channum), get_cmd=None, vals=vals.Enum(*list(Mode))) self.add_parameter(name='i', label=f'Channel {channum} current', get_cmd=f'get {channum}', unit='A', get_parser=self._parent._current_parser) self.add_parameter(name='slope', label=f'Channel {channum} slope', unit='V/s', set_cmd=partial(self._parent._setslope, channum), get_cmd=partial(self._parent._getslope, channum), vals=vals.MultiType(vals.Enum('Inf'), vals.Numbers(1e-3, 10000))) self.add_parameter( name='sync', label=f'Channel {channum} sync output', set_cmd=partial(self._parent._setsync, channum), get_cmd=partial(self._parent._getsync, channum), vals=vals.Ints(0, 4) # Updated at qdac init ) self.add_parameter(name='sync_delay', label=f'Channel {channum} sync pulse delay', unit='s', get_cmd=None, set_cmd=None, vals=vals.Numbers(0, 10000), initial_value=0) self.add_parameter(name='sync_duration', label=f'Channel {channum} sync pulse duration', unit='s', get_cmd=None, set_cmd=None, vals=vals.Numbers(0.001, 10000), initial_value=0.01)
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, **kwargs): dll_path = 'C:\\WINDOWS\\System32\\ATSApi.dll' super().__init__(name, dll_path=dll_path, **kwargs) # add parameters # ----- Parameters for the configuration of the board ----- self.add_parameter(name='clock_source', parameter_class=TraceParameter, get_cmd=None, label='Clock Source', unit=None, initial_value='INTERNAL_CLOCK', val_mapping={'INTERNAL_CLOCK': 1, 'FAST_EXTERNAL_CLOCK': 2, 'EXTERNAL_CLOCK_10MHz_REF': 7}) self.add_parameter(name='external_sample_rate', get_cmd=None, parameter_class=TraceParameter, label='External Sample Rate', unit='S/s', vals=validators.MultiType(validators.Ints(300000000, 2000000000), validators.Enum('UNDEFINED')), initial_value='UNDEFINED') self.add_parameter(name='sample_rate', get_cmd=None, parameter_class=TraceParameter, label='Internal Sample Rate', unit='S/s', initial_value='UNDEFINED', val_mapping={1_000: 1, 2_000: 2, 5_000: 4, 10_000: 8, 20_000: 10, 50_000: 12, 100_000: 14, 200_000: 16, 500_000: 18, 1_000_000: 20, 2_000_000: 24, 5_000_000: 26, 10_000_000: 28, 20_000_000: 30, 25_000_000: 33, 50_000_000: 34, 100_000_000: 36, 125_000_000: 37, 160_000_000: 38, 180_000_000: 39, 200_000_000: 40, 250_000_000: 43, 500_000_000: 48, 800_000_000: 50, 1_000_000_000: 53, 1_200_000_000: 55, 1_500_000_000: 58, 1_800_000_000: 61, 2_000_000_000: 63, 2_400_000_000: 106, 3_000_000_000: 117, 3_600_000_000: 123, 4_000_000_000: 128, 'EXTERNAL_CLOCK': 64, 'UNDEFINED': 'UNDEFINED'})
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, daq_card_name: str, xy_channel_names: Tuple[str, str], clock_rate: float, scan_speed_V_per_s: float, **kwargs): """ Create an instance of the instrument. Args: name (str): The internal QCoDeS name of the instrument daq_card_name (str): The device name from the list system = nidaqmx.system.System.local() [device.name for device in system.devices] """ super().__init__(name, **kwargs) self._daq_card = PXI_6251(daq_card_name, **kwargs) self._daq_card.add_task("ao_task") self._daq_card.ao_task.add_ao_volt_channel('X', xy_channel_names[0]) self._daq_card.ao_task.add_ao_volt_channel('Y', xy_channel_names[1]) self._daq_card.ao_task._task.out_stream.regen_mode = RegenerationMode.DONT_ALLOW_REGENERATION self._daq_card.ao_task.add_sample_clock( clock_rate, sample_mode=AcquisitionType.FINITE) self._daq_card.ao_task._task.register_done_event( self.task_done_callback) self._pos = (None, None) self._target_pos = (None, None) self.add_parameter(name='x_min', label='x min value', unit='V', set_cmd=self._daq_card.ao_task.X.ao_min.set, get_cmd=self._daq_card.ao_task.X.ao_min.get, vals=vals.Numbers()) self.add_parameter(name='x_max', label='x max value', unit='V', set_cmd=self._daq_card.ao_task.X.ao_max.set, get_cmd=self._daq_card.ao_task.X.ao_max.get, vals=vals.Numbers()) self.add_parameter(name='y_min', label='y min value', unit='V', set_cmd=self._daq_card.ao_task.Y.ao_min.set, get_cmd=self._daq_card.ao_task.Y.ao_min.get, vals=vals.Numbers()) self.add_parameter(name='y_max', label='y max value', unit='V', set_cmd=self._daq_card.ao_task.Y.ao_max.set, get_cmd=self._daq_card.ao_task.Y.ao_max.get, vals=vals.Numbers()) self.add_parameter(name='scan_speed', parameter_class=ManualParameter, initial_value=scan_speed_V_per_s, label='scanning speed', unit='V_per_s', vals=vals.MultiType(vals.Numbers(), vals.Enum(None))) self.add_parameter( name='samp_rate', label='sampling rate', unit='samples/s', set_cmd=self._daq_card.ao_task.clock.samp_clk_rate.set, get_cmd=self._daq_card.ao_task.clock.samp_clk_rate.get, vals=vals.Numbers(min_value=0, max_value=self._daq_card.ao_task._task.timing. samp_clk_max_rate)) self.add_parameter( name='N_samp', label='N samples', unit='', set_cmd=self._daq_card.ao_task.clock.samp_quant_samp_per_chan.set, get_cmd=self._daq_card.ao_task.clock.samp_quant_samp_per_chan.get, vals=vals.Ints(min_value=0))