class SR830(VisaInstrument): """ This is the qcodes driver for the Stanford Research Systems SR830 Lock-in Amplifier """ _VOLT_TO_N = { 2e-9: 0, 5e-9: 1, 10e-9: 2, 20e-9: 3, 50e-9: 4, 100e-9: 5, 200e-9: 6, 500e-9: 7, 1e-6: 8, 2e-6: 9, 5e-6: 10, 10e-6: 11, 20e-6: 12, 50e-6: 13, 100e-6: 14, 200e-6: 15, 500e-6: 16, 1e-3: 17, 2e-3: 18, 5e-3: 19, 10e-3: 20, 20e-3: 21, 50e-3: 22, 100e-3: 23, 200e-3: 24, 500e-3: 25, 1: 26 } _N_TO_VOLT = {v: k for k, v in _VOLT_TO_N.items()} _CURR_TO_N = { 2e-15: 0, 5e-15: 1, 10e-15: 2, 20e-15: 3, 50e-15: 4, 100e-15: 5, 200e-15: 6, 500e-15: 7, 1e-12: 8, 2e-12: 9, 5e-12: 10, 10e-12: 11, 20e-12: 12, 50e-12: 13, 100e-12: 14, 200e-12: 15, 500e-12: 16, 1e-9: 17, 2e-9: 18, 5e-9: 19, 10e-9: 20, 20e-9: 21, 50e-9: 22, 100e-9: 23, 200e-9: 24, 500e-9: 25, 1e-6: 26 } _N_TO_CURR = {v: k for k, v in _CURR_TO_N.items()} _VOLT_ENUM = Enum(*_VOLT_TO_N.keys()) _CURR_ENUM = Enum(*_CURR_TO_N.keys()) _INPUT_CONFIG_TO_N = { 'a': 0, 'a-b': 1, 'I 1M': 2, 'I 100M': 3, } _N_TO_INPUT_CONFIG = {v: k for k, v in _INPUT_CONFIG_TO_N.items()} def __init__(self, name, address, **kwargs): super().__init__(name, address, **kwargs) # Reference and phase self.add_parameter('phase', label='Phase', get_cmd='PHAS?', get_parser=float, set_cmd='PHAS {:.2f}', unit='deg', vals=Numbers(min_value=-360, max_value=729.99)) self.add_parameter('reference_source', label='Reference source', get_cmd='FMOD?', set_cmd='FMOD {}', val_mapping={ 'external': 0, 'internal': 1, }, vals=Enum('external', 'internal')) self.add_parameter('frequency', label='Frequency', get_cmd='FREQ?', get_parser=float, set_cmd='FREQ {:.4f}', unit='Hz', vals=Numbers(min_value=1e-3, max_value=102e3)) self.add_parameter('ext_trigger', label='External trigger', get_cmd='RSLP?', set_cmd='RSLP {}', val_mapping={ 'sine': 0, 'TTL rising': 1, 'TTL falling': 2, }) self.add_parameter('harmonic', label='Harmonic', get_cmd='HARM?', get_parser=int, set_cmd='HARM {:d}', vals=Ints(min_value=1, max_value=19999)) self.add_parameter('amplitude', label='Amplitude', get_cmd='SLVL?', get_parser=float, set_cmd='SLVL {:.3f}', unit='V', vals=Numbers(min_value=0.004, max_value=5.000)) # Input and filter self.add_parameter('input_config', label='Input configuration', get_cmd='ISRC?', get_parser=self._get_input_config, set_cmd='ISRC {}', set_parser=self._set_input_config, vals=Enum(*self._INPUT_CONFIG_TO_N.keys())) self.add_parameter('input_shield', label='Input shield', get_cmd='IGND?', set_cmd='IGND {}', val_mapping={ 'float': 0, 'ground': 1, }) self.add_parameter('input_coupling', label='Input coupling', get_cmd='ICPL?', set_cmd='ICPL {}', val_mapping={ 'AC': 0, 'DC': 1, }) self.add_parameter('notch_filter', label='Notch filter', get_cmd='ILIN?', set_cmd='ILIN {}', val_mapping={ 'off': 0, 'line in': 1, '2x line in': 2, 'both': 3, }) # Gain and time constant self.add_parameter(name='sensitivity', label='Sensitivity', get_cmd='SENS?', set_cmd='SENS {:d}', get_parser=self._get_sensitivity, set_parser=self._set_sensitivity) self.add_parameter('reserve', label='Reserve', get_cmd='RMOD?', set_cmd='RMOD {}', val_mapping={ 'high': 0, 'normal': 1, 'low noise': 2, }) self.add_parameter('time_constant', label='Time constant', get_cmd='OFLT?', set_cmd='OFLT {}', unit='s', val_mapping={ 10e-6: 0, 30e-6: 1, 100e-6: 2, 300e-6: 3, 1e-3: 4, 3e-3: 5, 10e-3: 6, 30e-3: 7, 100e-3: 8, 300e-3: 9, 1: 10, 3: 11, 10: 12, 30: 13, 100: 14, 300: 15, 1e3: 16, 3e3: 17, 10e3: 18, 30e3: 19, }) self.add_parameter('filter_slope', label='Filter slope', get_cmd='OFSL?', set_cmd='OFSL {}', unit='dB/oct', val_mapping={ 6: 0, 12: 1, 18: 2, 24: 3, }) self.add_parameter('sync_filter', label='Sync filter', get_cmd='SYNC?', set_cmd='SYNC {}', val_mapping={ 'off': 0, 'on': 1, }) def parse_offset_get(s): parts = s.split(',') return float(parts[0]), int(parts[1]) # TODO: Parameters that can be set with multiple arguments # For the OEXP command for example two arguments are needed self.add_parameter('X_offset', get_cmd='OEXP? 1', get_parser=parse_offset_get) self.add_parameter('Y_offset', get_cmd='OEXP? 2', get_parser=parse_offset_get) self.add_parameter('R_offset', get_cmd='OEXP? 3', get_parser=parse_offset_get) # Aux input/output for i in [1, 2, 3, 4]: self.add_parameter('aux_in{}'.format(i), label='Aux input {}'.format(i), get_cmd='OAUX? {}'.format(i), get_parser=float, unit='V') self.add_parameter('aux_out{}'.format(i), label='Aux output {}'.format(i), get_cmd='AUXV? {}'.format(i), get_parser=float, set_cmd='AUXV {0}, {{}}'.format(i), unit='V') # Setup self.add_parameter('output_interface', label='Output interface', get_cmd='OUTX?', set_cmd='OUTX {}', val_mapping={ 'RS232': '0\n', 'GPIB': '1\n', }) # Channel setup for ch in range(1, 3): # detailed validation and mapping performed in set/get functions self.add_parameter('ch{}_ratio'.format(ch), label='Channel {} ratio'.format(ch), get_cmd=partial(self._get_ch_ratio, ch), set_cmd=partial(self._set_ch_ratio, ch), vals=Strings()) self.add_parameter('ch{}_display'.format(ch), label='Channel {} display'.format(ch), get_cmd=partial(self._get_ch_display, ch), set_cmd=partial(self._set_ch_display, ch), vals=Strings()) self.add_parameter('ch{}_databuffer'.format(ch), channel=ch, parameter_class=ChannelBuffer) # Data transfer self.add_parameter('X', get_cmd='OUTP? 1', get_parser=float, unit='V') self.add_parameter('Y', get_cmd='OUTP? 2', get_parser=float, unit='V') self.add_parameter('R', get_cmd='OUTP? 3', get_parser=float, unit='V') self.add_parameter('P', get_cmd='OUTP? 4', get_parser=float, unit='deg') # Data buffer settings self.add_parameter('buffer_SR', label='Buffer sample rate', get_cmd='SRAT ?', set_cmd=self._set_buffer_SR, unit='Hz', val_mapping={ 62.5e-3: 0, 0.125: 1, 0.250: 2, 0.5: 3, 1: 4, 2: 5, 4: 6, 8: 7, 16: 8, 32: 9, 64: 10, 128: 11, 256: 12, 512: 13, 'Trigger': 14 }, get_parser=int) self.add_parameter('buffer_acq_mode', label='Buffer acquistion mode', get_cmd='SEND ?', set_cmd='SEND {}', val_mapping={ 'single shot': 0, 'loop': 1 }, get_parser=int) self.add_parameter('buffer_trig_mode', label='Buffer trigger start mode', get_cmd='TSTR ?', set_cmd='TSTR {}', val_mapping={ 'ON': 1, 'OFF': 0 }, get_parser=int) self.add_parameter('buffer_npts', label='Buffer number of stored points', get_cmd='SPTS ?', get_parser=int) # Auto functions self.add_function('auto_gain', call_cmd='AGAN') self.add_function('auto_reserve', call_cmd='ARSV') self.add_function('auto_phase', call_cmd='APHS') self.add_function('auto_offset', call_cmd='AOFF {0}', args=[Enum(1, 2, 3)]) # Interface self.add_function('reset', call_cmd='*RST') self.add_function('disable_front_panel', call_cmd='OVRM 0') self.add_function('enable_front_panel', call_cmd='OVRM 1') self.add_function('send_trigger', call_cmd='TRIG', docstring=("Send a software trigger. " "This command has the same effect as a " "trigger at the rear panel trigger" " input.")) self.add_function('buffer_start', call_cmd='STRT', docstring=("The buffer_start command starts or " "resumes data storage. buffer_start" " is ignored if storage is already in" " progress.")) self.add_function('buffer_pause', call_cmd='PAUS', docstring=("The buffer_pause command pauses data " "storage. If storage is already paused " "or reset then this command is ignored.")) self.add_function('buffer_reset', call_cmd='REST', docstring=("The buffer_reset command resets the data" " buffers. The buffer_reset command can " "be sent at any time - any storage in " "progress, paused or not, will be reset." " This command will erase the data " "buffer.")) # Initialize the proper units of the outputs and sensitivities self.input_config() # start keeping track of buffer setpoints self._buffer1_ready = False self._buffer2_ready = False self.connect_message() SNAP_PARAMETERS = { 'x': '1', 'y': '2', 'r': '3', 'p': '4', 'phase': '4', 'θ': '4', 'aux1': '5', 'aux2': '6', 'aux3': '7', 'aux4': '8', 'freq': '9', 'ch1': '10', 'ch2': '11' } def snap(self, *parameters: str) -> Tuple[float, ...]: """ Get between 2 and 6 parameters at a single instant. This provides a coherent snapshot of measured signals. Pick up to 6 from: X, Y, R, θ, the aux inputs 1-4, frequency, or what is currently displayed on channels 1 and 2. Reading X and Y (or R and θ) gives a coherent snapshot of the signal. Snap is important when the time constant is very short, a time constant less than 100 ms. Args: *parameters From 2 to 6 strings of names of parameters for which the values are requested. including: 'x', 'y', 'r', 'p', 'phase' or 'θ', 'aux1', 'aux2', 'aux3', 'aux4', 'freq', 'ch1', and 'ch2'. Returns: A tuple of floating point values in the same order as requested. Examples: lockin.snap('x','y') -> tuple(x,y) lockin.snap('aux1','aux2','freq','phase') -> tuple(aux1,aux2,freq,phase) Note: Volts for x, y, r, and aux 1-4 Degrees for θ Hertz for freq Unknown for ch1 and ch2. It will depend on what was set. - If X,Y,R and θ are all read, then the values of X,Y are recorded approximately 10 µs apart from R,θ. Thus, the values of X and Y may not yield the exact values of R and θ from a single snap. - The values of the Aux Inputs may have an uncertainty of up to 32 µs. - The frequency is computed only every other period or 40 ms, whichever is longer. """ if not 2 <= len(parameters) <= 6: raise KeyError( 'It is only possible to request values of 2 to 6 parameters' ' at a time.') for name in parameters: if name.lower() not in self.SNAP_PARAMETERS: raise KeyError(f'{name} is an unknown parameter. Refer' f' to `SNAP_PARAMETERS` for a list of valid' f' parameter names') p_ids = [self.SNAP_PARAMETERS[name.lower()] for name in parameters] output = self.ask(f'SNAP? {",".join(p_ids)}') return tuple(float(val) for val in output.split(',')) def increment_sensitivity(self): """ Increment the sensitivity setting of the lock-in. This is equivalent to pushing the sensitivity up button on the front panel. This has no effect if the sensitivity is already at the maximum. Returns: Whether or not the sensitivity was actually changed. """ return self._change_sensitivity(1) def decrement_sensitivity(self): """ Decrement the sensitivity setting of the lock-in. This is equivalent to pushing the sensitivity down button on the front panel. This has no effect if the sensitivity is already at the minimum. Returns: Whether or not the sensitivity was actually changed. """ return self._change_sensitivity(-1) def _change_sensitivity(self, dn): _ = self.sensitivity.get() n = int(self.sensitivity.raw_value) if self.input_config() in ['a', 'a-b']: n_to = self._N_TO_VOLT else: n_to = self._N_TO_CURR if n + dn > max(n_to.keys()) or n + dn < min(n_to.keys()): return False self.sensitivity.set(n_to[n + dn]) return True def _set_buffer_SR(self, SR): self.write('SRAT {}'.format(SR)) self._buffer1_ready = False self._buffer2_ready = False def _get_ch_ratio(self, channel): val_mapping = { 1: { 0: 'none', 1: 'Aux In 1', 2: 'Aux In 2' }, 2: { 0: 'none', 1: 'Aux In 3', 2: 'Aux In 4' } } resp = int(self.ask('DDEF ? {}'.format(channel)).split(',')[1]) return val_mapping[channel][resp] def _set_ch_ratio(self, channel, ratio): val_mapping = { 1: { 'none': 0, 'Aux In 1': 1, 'Aux In 2': 2 }, 2: { 'none': 0, 'Aux In 3': 1, 'Aux In 4': 2 } } vals = val_mapping[channel].keys() if ratio not in vals: raise ValueError('{} not in {}'.format(ratio, vals)) ratio = val_mapping[channel][ratio] disp_val = int(self.ask('DDEF ? {}'.format(channel)).split(',')[0]) self.write('DDEF {}, {}, {}'.format(channel, disp_val, ratio)) self._buffer_ready = False def _get_ch_display(self, channel): val_mapping = { 1: { 0: 'X', 1: 'R', 2: 'X Noise', 3: 'Aux In 1', 4: 'Aux In 2' }, 2: { 0: 'Y', 1: 'Phase', 2: 'Y Noise', 3: 'Aux In 3', 4: 'Aux In 4' } } resp = int(self.ask('DDEF ? {}'.format(channel)).split(',')[0]) return val_mapping[channel][resp] def _set_ch_display(self, channel, disp): val_mapping = { 1: { 'X': 0, 'R': 1, 'X Noise': 2, 'Aux In 1': 3, 'Aux In 2': 4 }, 2: { 'Y': 0, 'Phase': 1, 'Y Noise': 2, 'Aux In 3': 3, 'Aux In 4': 4 } } vals = val_mapping[channel].keys() if disp not in vals: raise ValueError('{} not in {}'.format(disp, vals)) disp = val_mapping[channel][disp] # Since ratio AND display are set simultaneously, # we get and then re-set the current ratio value ratio_val = int(self.ask('DDEF ? {}'.format(channel)).split(',')[1]) self.write('DDEF {}, {}, {}'.format(channel, disp, ratio_val)) self._buffer_ready = False def _set_units(self, unit): # TODO: # make a public parameter function that allows to change the units for param in [self.X, self.Y, self.R, self.sensitivity]: param.unit = unit def _get_input_config(self, s): mode = self._N_TO_INPUT_CONFIG[int(s)] if mode in ['a', 'a-b']: self.sensitivity.vals = self._VOLT_ENUM self._set_units('V') else: self.sensitivity.vals = self._CURR_ENUM self._set_units('A') return mode def _set_input_config(self, s): if s in ['a', 'a-b']: self.sensitivity.vals = self._VOLT_ENUM self._set_units('V') else: self.sensitivity.vals = self._CURR_ENUM self._set_units('A') return self._INPUT_CONFIG_TO_N[s] def _get_sensitivity(self, s): if self.input_config() in ['a', 'a-b']: return self._N_TO_VOLT[int(s)] else: return self._N_TO_CURR[int(s)] def _set_sensitivity(self, s): if self.input_config() in ['a', 'a-b']: return self._VOLT_TO_N[s] else: return self._CURR_TO_N[s]
def __init__( self, parent: VisaInstrument, name: str, proper_function: str ) -> None: super().__init__(parent, name) self._proper_function = proper_function range_vals = self.function_modes[self._proper_function]["range_vals"] unit = self.function_modes[self._proper_function]["unit"] self.function = self.parent.digi_sense_function self.add_parameter( self._proper_function, get_cmd=self._measure, unit=unit, docstring="Make measurements, place them in a reading buffer, and " "return the last reading." ) self.add_parameter( "range", get_cmd=f":SENSe:DIGitize:{self._proper_function}:RANGe?", set_cmd=f":SENSe:DIGitize:{self._proper_function}:RANGe {{}}", vals=range_vals, get_parser=float, unit=unit, docstring="Determine the positive full-scale measure range." ) self.add_parameter( "input_impedance", get_cmd=":SENSe:DIGitize:VOLTage:INPutimpedance?", set_cmd=":SENSe:DIGitize:VOLTage:INPutimpedance {}", vals=Enum("AUTO", "MOHM10"), docstring="Determine when the 10 MΩ input divider is enabled. " "'MOHM10' means 10 MΩ for all ranges." ) self.add_parameter( 'acq_rate', get_cmd=f":SENSe:DIGitize:{self._proper_function}:SRATE?", set_cmd=f":SENSe:DIGitize:{self._proper_function}:SRATE {{}}", vals=Ints(1000, 1000000), docstring="Define the precise acquisition rate at which the " "digitizing measurements are made." ) self.add_parameter( "aperture", get_cmd=f":SENSe:DIGitize:{self._proper_function}:APERture?", set_cmd=f":SENSe:DIGitize:{self._proper_function}:APERture {{}}", unit="us", docstring="Determine the aperture setting." ) self.add_parameter( "count", get_cmd="SENSe:DIGitize:COUNt?", set_cmd="SENSe:DIGitize:COUNt {}", vals=Ints(1, 55000000), docstring="Set the number of measurements to digitize when a " "measurement is requested" )
def __init__( self, parent: 'Keithley7510', name: str, size: Optional[int] = None, style: str = '' ) -> None: super().__init__(parent, name) self._size = size self.style = style if self.short_name not in self.default_buffer: # when making a new buffer, the "size" parameter is required. if size is None: raise TypeError( "buffer() missing 1 required positional argument: 'size'" ) self.write( f":TRACe:MAKE '{self.short_name}', {self._size}, {self.style}" ) else: # when referring to default buffer, "size" parameter is not needed. if size is not None: self.log.warning( f"Please use method 'size()' to resize default buffer " f"{self.short_name} size to {self._size}." ) self.add_parameter( "size", get_cmd=f":TRACe:POINts? '{self.short_name}'", set_cmd=f":TRACe:POINts {{}}, '{self.short_name}'", get_parser=int, docstring="The number of readings a buffer can store." ) self.add_parameter( "number_of_readings", get_cmd=f":TRACe:ACTual? '{self.short_name}'", get_parser=int, docstring="Get the number of readings in the reading buffer." ) self.add_parameter( "last_index", get_cmd=f":TRACe:ACTual:END? '{self.short_name}'", get_parser=int, docstring="Get the last index of readings in the reading buffer." ) self.add_parameter( "first_index", get_cmd=f":TRACe:ACTual:STARt? '{self.short_name}'", get_parser=int, docstring="Get the starting index of readings in the reading " "buffer." ) self.add_parameter( "data_start", initial_value=1, get_cmd=None, set_cmd=None, docstring="First index of the data to be returned." ) self.add_parameter( "data_end", initial_value=1, get_cmd=None, set_cmd=None, docstring="Last index of the data to be returned." ) self.add_parameter( "elements", get_cmd=None, get_parser=self._from_scpi_to_name, set_cmd=None, set_parser=self._from_name_to_scpi, vals=Lists(Enum(*list(self.buffer_elements.keys()))), docstring="List of buffer elements to read." ) self.add_parameter( "setpoints_start", label="start value for the setpoints", source=None, parameter_class=DelegateParameter ) self.add_parameter( "setpoints_stop", label="stop value for the setpoints", source=None, parameter_class=DelegateParameter ) self.add_parameter( "n_pts", label="total n for the setpoints", get_cmd=self._get_n_pts ) self.add_parameter( "setpoints", parameter_class=GeneratedSetPoints, start=self.setpoints_start, stop=self.setpoints_stop, n_points=self.n_pts, vals=Arrays(shape=(self.n_pts.get_latest,)) ) self.add_parameter( "t_start", label="start time", unit="s", initial_value=0, get_cmd=None, set_cmd=None, set_parser=float ) self.add_parameter( "t_stop", label="stop time", unit="s", initial_value=1, get_cmd=None, set_cmd=None, set_parser=float ) self.add_parameter( "fill_mode", get_cmd=f":TRACe:FILL:MODE? '{self.short_name}'", set_cmd=f":TRACe:FILL:MODE {{}}, '{self.short_name}'", vals=Enum('CONT', 'continuous', 'ONCE', 'once'), docstring="if a reading buffer is filled continuously or is filled" " once and stops" )
def __init__(self, name: str, address: str, **kwargs: Any): super().__init__(name, address, terminator='\n', **kwargs) self._card = 0 self.add_parameter(name='get_status', get_cmd='*ESR?', get_parser=int, docstring='Queries status register.') self.add_parameter(name='get_error', get_cmd=':SYST:ERR?', docstring='Queries error queue') self.add_parameter(name='connections', get_cmd=f':CLOS:CARD? {self._card}', get_parser=KeysightB220X.parse_channel_list, docstring='queries currently active connections ' 'and returns a set of tuples {(input, ' 'output), ...}') self.add_parameter( name='connection_rule', get_cmd=self._get_connection_rule, set_cmd=self._set_connection_rule, val_mapping={ 'free': 'FREE', 'single': 'SROU' }, docstring=("specifies connection rule. Parameter " "one of 'free' (default) or 'single'.\n\n" "In 'free' mode\n" " - each input port can be connected to " "multiple output ports\n" " - and each output port can be " "connected to multiple input ports.\n" " - Caution: If the Free connection rule " "has been specified, ensure multiple " "input ports are not connected to the " "same output port. Such configurations " "can cause damage\n\n" "In single route mode:\n" " - each input port can be connected to " "only one output port\n" " - and each output port can be " "connected to only one input port.\n" " - existing connection to a port will " "be disconnected when a new connection " "is made.\n")) self.add_parameter(name='connection_sequence', get_cmd=f':CONN:SEQ? {self._card}', set_cmd=f':CONN:SEQ {self._card},{{}}', val_mapping={ 'none': 'NSEQ', 'bbm': 'BBM', 'mbb': 'MBBR' }, docstring="One of 'none', 'bbm' (Break before " "make) or 'mbb' (make before break)") self.add_parameter(name='bias_input_port', get_cmd=f':BIAS:PORT? {self._card}', set_cmd=f':BIAS:PORT {self._card},{{}}', vals=MultiType(KeysightB220X._available_input_ports, Enum(-1)), get_parser=int, docstring="Selects the input that will be used as " "bias input port (default 10). The Bias " "input port cannot be used on subsequent " "`connect` or `disconnect` commands if " "Bias mode is ON") self.add_parameter(name='bias_mode', get_cmd=f':BIAS? {self._card}', set_cmd=f':BIAS {self._card},{{}}', val_mapping={ True: 1, False: 0 }, docstring="Param: True for ON, False for OFF") self.add_parameter(name='gnd_input_port', get_cmd=f':AGND:PORT? {self._card}', set_cmd=f':AGND:PORT {self._card},{{}}', vals=MultiType(KeysightB220X._available_input_ports, Enum(-1)), get_parser=int, docstring="Selects the input that will be used as " "GND input port (default 12). The GND " "input port cannot be used on subsequent " "`connect` or `disconnect` commands if " "GND mode is ON") self.add_parameter(name='gnd_mode', get_cmd=f':AGND? {self._card}', set_cmd=f':AGND {self._card},{{}}', val_mapping={ True: 1, False: 0 }) self.add_parameter(name='unused_inputs', get_cmd=f':AGND:UNUSED? {self._card}', set_cmd=f":AGND:UNUSED {self._card},'{{}}'", get_parser=lambda response: [ int(x) for x in response.strip("'").split(',') if x.strip().isdigit() ], set_parser=lambda value: str(value).strip('[]'), vals=Lists(KeysightB220X._available_input_ports)) self.add_parameter(name='couple_ports', get_cmd=f':COUP:PORT? {self._card}', set_cmd=f":COUP:PORT {self._card},'{{}}'", set_parser=lambda value: str(value).strip('[]()'), get_parser=lambda response: [ int(x) for x in response.strip("'").split(',') if x.strip().isdigit() ], vals=Lists(Enum(1, 3, 5, 7, 9, 11, 13))) self.add_parameter(name='couple_mode', get_cmd=f':COUP? {self._card}', set_cmd=f':COUP {self._card},{{}}', val_mapping={ True: 1, False: 0 }, docstring="Param: True for ON, False for OFF") self.connect_message()
def __init__(self, name, address, **kwargs): super().__init__(name, address, **kwargs) # Reference and phase self.add_parameter('phase', label='Phase', get_cmd='PHAS?', get_parser=float, set_cmd='PHAS {:.2f}', unit='deg', vals=Numbers(min_value=-360, max_value=729.99)) self.add_parameter('reference_source', label='Reference source', get_cmd='FMOD?', set_cmd='FMOD {}', val_mapping={ 'external': 0, 'internal': 1, }, vals=Enum('external', 'internal')) self.add_parameter('frequency', label='Frequency', get_cmd='FREQ?', get_parser=float, set_cmd='FREQ {:.4f}', unit='Hz', vals=Numbers(min_value=1e-3, max_value=102e3)) self.add_parameter('ext_trigger', label='External trigger', get_cmd='RSLP?', set_cmd='RSLP {}', val_mapping={ 'sine': 0, 'TTL rising': 1, 'TTL falling': 2, }) self.add_parameter('harmonic', label='Harmonic', get_cmd='HARM?', get_parser=int, set_cmd='HARM {:d}', vals=Ints(min_value=1, max_value=19999)) self.add_parameter('amplitude', label='Amplitude', get_cmd='SLVL?', get_parser=float, set_cmd='SLVL {:.3f}', unit='V', vals=Numbers(min_value=0.004, max_value=5.000)) # Input and filter self.add_parameter('input_config', label='Input configuration', get_cmd='ISRC?', get_parser=self._get_input_config, set_cmd='ISRC {}', set_parser=self._set_input_config, vals=Enum(*self._INPUT_CONFIG_TO_N.keys())) self.add_parameter('input_shield', label='Input shield', get_cmd='IGND?', set_cmd='IGND {}', val_mapping={ 'float': 0, 'ground': 1, }) self.add_parameter('input_coupling', label='Input coupling', get_cmd='ICPL?', set_cmd='ICPL {}', val_mapping={ 'AC': 0, 'DC': 1, }) self.add_parameter('notch_filter', label='Notch filter', get_cmd='ILIN?', set_cmd='ILIN {}', val_mapping={ 'off': 0, 'line in': 1, '2x line in': 2, 'both': 3, }) # Gain and time constant self.add_parameter(name='sensitivity', label='Sensitivity', get_cmd='SENS?', set_cmd='SENS {:d}', get_parser=self._get_sensitivity, set_parser=self._set_sensitivity ) self.add_parameter('reserve', label='Reserve', get_cmd='RMOD?', set_cmd='RMOD {}', val_mapping={ 'high': 0, 'normal': 1, 'low noise': 2, }) self.add_parameter('time_constant', label='Time constant', get_cmd='OFLT?', set_cmd='OFLT {}', unit='s', val_mapping={ 10e-6: 0, 30e-6: 1, 100e-6: 2, 300e-6: 3, 1e-3: 4, 3e-3: 5, 10e-3: 6, 30e-3: 7, 100e-3: 8, 300e-3: 9, 1: 10, 3: 11, 10: 12, 30: 13, 100: 14, 300: 15, 1e3: 16, 3e3: 17, 10e3: 18, 30e3: 19, }) self.add_parameter('filter_slope', label='Filter slope', get_cmd='OFSL?', set_cmd='OFSL {}', unit='dB/oct', val_mapping={ 6: 0, 12: 1, 18: 2, 24: 3, }) self.add_parameter('sync_filter', label='Sync filter', get_cmd='SYNC?', set_cmd='SYNC {}', val_mapping={ 'off': 0, 'on': 1, }) def parse_offset_get(s): parts = s.split(',') return float(parts[0]), int(parts[1]) # TODO: Parameters that can be set with multiple arguments # For the OEXP command for example two arguments are needed self.add_parameter('X_offset', get_cmd='OEXP? 1', get_parser=parse_offset_get) self.add_parameter('Y_offset', get_cmd='OEXP? 2', get_parser=parse_offset_get) self.add_parameter('R_offset', get_cmd='OEXP? 3', get_parser=parse_offset_get) # Aux input/output for i in [1, 2, 3, 4]: self.add_parameter('aux_in{}'.format(i), label='Aux input {}'.format(i), get_cmd='OAUX? {}'.format(i), get_parser=float, unit='V') self.add_parameter('aux_out{}'.format(i), label='Aux output {}'.format(i), get_cmd='AUXV? {}'.format(i), get_parser=float, set_cmd='AUXV {0}, {{}}'.format(i), unit='V') # Setup self.add_parameter('output_interface', label='Output interface', get_cmd='OUTX?', set_cmd='OUTX {}', val_mapping={ 'RS232': '0\n', 'GPIB': '1\n', }) # Channel setup for ch in range(1, 3): # detailed validation and mapping performed in set/get functions self.add_parameter('ch{}_ratio'.format(ch), label='Channel {} ratio'.format(ch), get_cmd=partial(self._get_ch_ratio, ch), set_cmd=partial(self._set_ch_ratio, ch), vals=Strings()) self.add_parameter('ch{}_display'.format(ch), label='Channel {} display'.format(ch), get_cmd=partial(self._get_ch_display, ch), set_cmd=partial(self._set_ch_display, ch), vals=Strings()) self.add_parameter('ch{}_databuffer'.format(ch), channel=ch, parameter_class=ChannelBuffer) # Data transfer self.add_parameter('X', get_cmd='OUTP? 1', get_parser=float, unit='V') self.add_parameter('Y', get_cmd='OUTP? 2', get_parser=float, unit='V') self.add_parameter('R', get_cmd='OUTP? 3', get_parser=float, unit='V') self.add_parameter('P', get_cmd='OUTP? 4', get_parser=float, unit='deg') # Data buffer settings self.add_parameter('buffer_SR', label='Buffer sample rate', get_cmd='SRAT ?', set_cmd=self._set_buffer_SR, unit='Hz', val_mapping={62.5e-3: 0, 0.125: 1, 0.250: 2, 0.5: 3, 1: 4, 2: 5, 4: 6, 8: 7, 16: 8, 32: 9, 64: 10, 128: 11, 256: 12, 512: 13, 'Trigger': 14}, get_parser=int ) self.add_parameter('buffer_acq_mode', label='Buffer acquistion mode', get_cmd='SEND ?', set_cmd='SEND {}', val_mapping={'single shot': 0, 'loop': 1}, get_parser=int) self.add_parameter('buffer_trig_mode', label='Buffer trigger start mode', get_cmd='TSTR ?', set_cmd='TSTR {}', val_mapping={'ON': 1, 'OFF': 0}, get_parser=int) self.add_parameter('buffer_npts', label='Buffer number of stored points', get_cmd='SPTS ?', get_parser=int) # Auto functions self.add_function('auto_gain', call_cmd='AGAN') self.add_function('auto_reserve', call_cmd='ARSV') self.add_function('auto_phase', call_cmd='APHS') self.add_function('auto_offset', call_cmd='AOFF {0}', args=[Enum(1, 2, 3)]) # Interface self.add_function('reset', call_cmd='*RST') self.add_function('disable_front_panel', call_cmd='OVRM 0') self.add_function('enable_front_panel', call_cmd='OVRM 1') self.add_function('send_trigger', call_cmd='TRIG', docstring=("Send a software trigger. " "This command has the same effect as a " "trigger at the rear panel trigger" " input.")) self.add_function('buffer_start', call_cmd='STRT', docstring=("The buffer_start command starts or " "resumes data storage. buffer_start" " is ignored if storage is already in" " progress.")) self.add_function('buffer_pause', call_cmd='PAUS', docstring=("The buffer_pause command pauses data " "storage. If storage is already paused " "or reset then this command is ignored.")) self.add_function('buffer_reset', call_cmd='REST', docstring=("The buffer_reset command resets the data" " buffers. The buffer_reset command can " "be sent at any time - any storage in " "progress, paused or not, will be reset." " This command will erase the data " "buffer.")) # Initialize the proper units of the outputs and sensitivities self.input_config() # start keeping track of buffer setpoints self._buffer1_ready = False self._buffer2_ready = False self.connect_message()
def __init__(self, name, chassis, slot, channels, triggers, **kwargs): """ Initialises a generic Signadyne digitizer and its parameters Args: name (str) : the name of the digitizer card channels (int) : the number of input channels the specified card has triggers (int) : the number of trigger inputs the specified card has """ super().__init__(name, chassis, slot, **kwargs) # Create instance of keysight SD_AIN class self.SD_AIN = keysightSD1.SD_AIN() # store card-specifics self.n_channels = channels self.n_triggers = triggers # Open the device, using the specified chassis and slot number dig_name = self.SD_AIN.getProductNameBySlot(chassis, slot) if isinstance(dig_name, str): result_code = self.SD_AIN.openWithSlot(dig_name, chassis, slot) if result_code <= 0: raise Exception('Could not open SD_DIG ' 'error code {}'.format(result_code)) else: raise Exception('No SD_DIG found at ' 'chassis {}, slot {}'.format(chassis, slot)) # # Create a set of internal variables to aid set/get cmds in params # # Create distinct parameters for each of the digitizer channels # For channelInputConfig self.__full_scale = [1 ] * self.n_channels # By default, full scale = 1V self.__impedance = [0] * self.n_channels # By default, Hi-z self.__coupling = [0] * self.n_channels # By default, DC coupling # For channelPrescalerConfig self.__prescaler = [0] * self.n_channels # By default, no prescaling # For channelTriggerConfig self.__trigger_mode = [keysightSD1.SD_AIN_TriggerMode.RISING_EDGE ] * self.n_channels self.__trigger_threshold = [ 0 ] * self.n_channels # By default, threshold at 0V # For DAQ config self.__points_per_cycle = [0] * self.n_channels self.__n_cycles = [0] * self.n_channels self.__trigger_delay = [0] * self.n_channels self.__trigger_mode = [0] * self.n_channels # For DAQ trigger Config self.__digital_trigger_mode = [0] * self.n_channels self.__digital_trigger_source = [0] * self.n_channels self.__analog_trigger_mask = [0] * self.n_channels # For DAQ trigger External Config self.__external_source = [0] * self.n_channels self.__trigger_behaviour = [0] * self.n_channels # For DAQ read self.__n_points = [0] * self.n_channels self.__timeout = [-1] * self.n_channels # # Create internal parameters # # for triggerIOconfig self.add_parameter( 'trigger_direction', label='Trigger direction for trigger port', vals=Enum(0, 1), set_cmd=self.SD_AIN.triggerIOconfig, docstring='The trigger direction for digitizer trigger port') # for clockSetFrequency self.add_parameter('sys_frequency', label='CLKsys frequency', vals=Ints(), set_cmd=self.SD_AIN.clockSetFrequency, get_cmd=self.SD_AIN.clockGetFrequency, docstring='The frequency of internal CLKsys in Hz') # for clockGetSyncFrequency self.add_parameter('sync_frequency', label='CLKsync frequency', vals=Ints(), get_cmd=self.SD_AIN.clockGetSyncFrequency, docstring='The frequency of internal CLKsync in Hz') self.add_parameter( 'trigger_io', label='trigger io', get_cmd=self.get_trigger_io, set_cmd=self.set_trigger_io, docstring='The trigger input value, 0 (OFF) or 1 (ON)', vals=Enum(0, 1)) for n in range(self.n_channels): # For channelInputConfig self.add_parameter( f'full_scale_{n}', label=f'Full scale range for channel {n}', # TODO: validator must be set after device opened # vals=Numbers(self.SD_AIN.channelMinFullScale(), self.SD_AIN.channelMaxFullScale()) set_cmd=partial(self.set_full_scale, channel=n), get_cmd=partial(self.get_full_scale, channel=n), docstring=f'The full scale voltage for channel {n}') # For channelTriggerConfig self.add_parameter(f'impedance_{n}', label=f'Impedance for channel {n}', vals=Enum(0, 1), set_cmd=partial(self.set_impedance, channel=n), get_cmd=partial(self.get_impedance, channel=n), docstring=f'The input impedance of channel {n}') self.add_parameter(f'coupling_{n}', label=f'Coupling for channel {n}', vals=Enum(0, 1), set_cmd=partial(self.set_coupling, channel=n), get_cmd=partial(self.get_coupling, channel=n), docstring=f'The coupling of channel {n}') # For channelPrescalerConfig self.add_parameter( f'prescaler_{n}', label=f'Prescaler for channel {n}', vals=Ints(0, 4095), set_cmd=partial(self.set_prescaler, channel=n), get_cmd=partial(self.get_prescaler, channel=n), docstring=f'The sampling frequency prescaler for channel {n}') # For channelTriggerConfig self.add_parameter(f'trigger_mode_{n}', label=f'Trigger mode for channel {n}', vals=Enum(0, 1, 2, 3, 4, 5, 6, 7), set_cmd=partial(self.set_trigger_mode, channel=n), docstring=f'The trigger mode for channel {n}') self.add_parameter( f'trigger_threshold_{n}', label=f'Trigger threshold for channel {n}', vals=Numbers(-3, 3), set_cmd=partial(self.set_trigger_threshold, channel=n), docstring=f'The trigger threshold for channel {n}') # For DAQ config self.add_parameter( f'points_per_cycle_{n}', label=f'Points per cycle for channel {n}', vals=Ints(), set_cmd=partial(self.set_points_per_cycle, channel=n), docstring=f'The number of points per cycle for DAQ {n}') self.add_parameter( f'n_cycles_{n}', label=f'n cycles for DAQ {n}', vals=Ints(), set_cmd=partial(self.set_n_cycles, channel=n), docstring=f'The number of cycles to collect on DAQ {n}') self.add_parameter(f'DAQ_trigger_delay_{n}', label=f'Trigger delay for for DAQ {n}', vals=Ints(), set_cmd=partial(self.set_daq_trigger_delay, channel=n), docstring=f'The trigger delay for DAQ {n}') self.add_parameter(f'DAQ_trigger_mode_{n}', label=f'Trigger mode for for DAQ {n}', vals=Ints(), set_cmd=partial(self.set_daq_trigger_mode, channel=n), docstring=f'The trigger mode for DAQ {n}') # For DAQ trigger Config self.add_parameter( f'digital_trigger_mode_{n}', label=f'Digital trigger mode for DAQ {n}', vals=Ints(), set_cmd=partial(self.set_digital_trigger_mode, channel=n), docstring=f'The digital trigger mode for DAQ {n}') self.add_parameter( f'digital_trigger_source_{n}', label=f'Digital trigger source for DAQ {n}', vals=Ints(), set_cmd=partial(self.set_digital_trigger_source, channel=n), docstring=f'The digital trigger source for DAQ {n}') self.add_parameter( f'analog_trigger_mask_{n}', label=f'Analog trigger mask for DAQ {n}', vals=Ints(), set_cmd=partial(self.set_analog_trigger_mask, channel=n), docstring=f'The analog trigger mask for DAQ {n}') # For DAQ trigger External Config self.add_parameter(f'ext_trigger_source_{n}', label=f'External trigger source for DAQ {n}', vals=Ints(), set_cmd=partial(self.set_ext_trigger_source, channel=n), docstring=f'The trigger source for DAQ {n}') self.add_parameter(f'ext_trigger_behaviour_{n}', label=f'External trigger behaviour for DAQ {n}', vals=Ints(), set_cmd=partial(self.set_ext_trigger_behaviour, channel=n), docstring=f'The trigger behaviour for DAQ {n}') # For DAQ read self.add_parameter( f'n_points_{n}', label=f'n points for DAQ {n}', vals=Ints(), set_cmd=partial(self.set_n_points, channel=n), docstring= f'The number of points to be read using daq_read on DAQ {n}') self.add_parameter(f'timeout_{n}', label=f'timeout for DAQ {n}', vals=Ints(), set_cmd=partial(self.set_timeout, channel=n), docstring=f'The read timeout for DAQ {n}')
def __init__(self, name, address, **kwargs): super().__init__(name, address, terminator='\n', **kwargs) self.add_parameter('rangev', get_cmd='SENS:VOLT:RANG?', get_parser=float, set_cmd='SOUR:VOLT:RANG {:f}', label='Voltage range') self.add_parameter('rangei', get_cmd='SENS:CURR:RANG?', get_parser=float, set_cmd='SOUR:CURR:RANG {:f}', label='Current range') self.add_parameter('compliancev', get_cmd='SENS:VOLT:PROT?', get_parser=float, set_cmd='SENS:VOLT:PROT {:f}', label='Voltage Compliance') self.add_parameter('compliancei', get_cmd='SENS:CURR:PROT?', get_parser=float, set_cmd='SENS:CURR:PROT {:f}', label='Current Compliance') self.add_parameter('volt', get_cmd=':READ?', get_parser=self._volt_parser, set_cmd=':SOUR:VOLT:LEV {:.8f}', label='Voltage', unit='V') self.add_parameter('curr', get_cmd=':READ?', get_parser=self._curr_parser, set_cmd=':SOUR:CURR:LEV {:.8f}', label='Current', unit='A') self.add_parameter('mode', vals=Enum('VOLT', 'CURR'), get_cmd=':SOUR:FUNC?', set_cmd=self._set_mode_and_sense, label='Mode') self.add_parameter('sense', vals=Strings(), get_cmd=':SENS:FUNC?', set_cmd=':SENS:FUNC "{:s}"', label='Sense mode') self.add_parameter('output', get_parser=int, set_cmd=':OUTP:STAT {:d}', get_cmd=':OUTP:STAT?') self.add_parameter('nplcv', get_cmd='SENS:VOLT:NPLC?', get_parser=float, set_cmd='SENS:VOLT:NPLC {:f}', label='Voltage integration time') self.add_parameter('nplci', get_cmd='SENS:CURR:NPLC?', get_parser=float, set_cmd='SENS:CURR:NPLC {:f}', label='Current integration time') self.add_parameter('resistance', get_cmd=':READ?', get_parser=self._resistance_parser, label='Resistance', unit='Ohm')
def __init__(self, name, address, reset_device=False, **kwargs): """ Driver for the Keithley 6500 multimeter. Based on the Keithley 2000 driver, commands have been adapted for the Keithley 6500. This driver does not contain all commands available, but only the ones most commonly used. Status: beta-version. Args: name (str): The name used internally by QCoDeS in the DataSet. address (str): The VISA device address. reset_device (bool): Reset the device on startup if true. """ super().__init__(name, address, terminator='\n', **kwargs) self._trigger_sent = False self._mode_map = { 'ac current': 'CURR:AC', 'dc current': 'CURR:DC', 'ac voltage': 'VOLT:AC', 'dc voltage': 'VOLT:DC', '2w resistance': 'RES', '4w resistance': 'FRES', 'temperature': 'TEMP', 'frequency': 'FREQ' } self.add_parameter('mode', get_cmd='SENS:FUNC?', set_cmd="SENS:FUNC {}", val_mapping=self._mode_map) self.add_parameter('nplc', get_cmd=partial(self._get_mode_param, 'NPLC', float), set_cmd=partial(self._set_mode_param, 'NPLC'), vals=Numbers(min_value=0.01, max_value=10)) # TODO: validator, this one is more difficult since different modes # require different validation ranges. self.add_parameter('range', get_cmd=partial(self._get_mode_param, 'RANG', float), set_cmd=partial(self._set_mode_param, 'RANG'), vals=Numbers()) self.add_parameter('auto_range_enabled', get_cmd=partial(self._get_mode_param, 'RANG:AUTO', _parse_output_bool), set_cmd=partial(self._set_mode_param, 'RANG:AUTO'), vals=Bool()) self.add_parameter('digits', get_cmd='DISP:VOLT:DC:DIG?', get_parser=int, set_cmd='DISP:VOLT:DC:DIG? {}', vals=Ints(min_value=4, max_value=7)) self.add_parameter('averaging_type', get_cmd=partial(self._get_mode_param, 'AVER:TCON', _parse_output_string), set_cmd=partial(self._set_mode_param, 'AVER:TCON'), vals=Enum('moving', 'repeat')) self.add_parameter('averaging_count', get_cmd=partial(self._get_mode_param, 'AVER:COUN', int), set_cmd=partial(self._set_mode_param, 'AVER:COUN'), vals=Ints(min_value=1, max_value=100)) self.add_parameter('averaging_enabled', get_cmd=partial(self._get_mode_param, 'AVER:STAT', _parse_output_bool), set_cmd=partial(self._set_mode_param, 'AVER:STAT'), vals=Bool()) # Global parameters self.add_parameter('display_enabled', get_parser=_parse_output_bool, get_cmd='DISP:ENAB?', set_cmd='DISP:ENAB {}', set_parser=int, vals=Bool()) self.add_parameter('trigger_count', get_parser=int, get_cmd='ROUT:SCAN:COUN:SCAN?', set_cmd='ROUT:SCAN:COUN:SCAN {}', vals=MultiType( Ints(min_value=1, max_value=9999), Enum('inf', 'default', 'minimum', 'maximum'))) self.add_parameter('trigger_delay', get_parser=float, get_cmd='TRIG:DEL?', set_cmd='TRIG:DEL {}', unit='s', vals=Numbers(min_value=0, max_value=999999.999)) self.add_parameter('trigger_source', get_cmd='TRIG:SOUR?', set_cmd='TRIG:SOUR {}', val_mapping={ 'immediate': 'NONE', 'timer': 'TIM', 'manual': 'MAN', 'bus': 'BUS', 'external': 'EXT' }) self.add_parameter('trigger_timer', get_parser=float, get_cmd='ROUT:SCAN:INT?', set_cmd='ROUT:SCAN:INT {}', unit='s', vals=Numbers(min_value=0.001, max_value=999999.999)) self.add_parameter('amplitude', get_cmd=self._read_next_value, set_cmd=False, unit='a.u.') if reset_device: self.reset() self.write('FORM:DATA ASCII') self.connect_message()
def __init__(self, name: str, address: str, terminator: str = "\n\r", **kwargs) -> None: super().__init__(name, address, terminator=terminator, **kwargs) # self.write('DL1') self.add_parameter('output', label='Output State', get_cmd=self.state, set_cmd=lambda x: self.on() if x else self.off(), val_mapping={ 'off': 0, 'on': 1, }) self.add_parameter('source_mode', label='Source Mode', get_cmd=self._get_source_mode, set_cmd=self._set_source_mode, vals=Enum('VOLT', 'CURR')) # When getting the mode internally in the driver, look up the mode as recorded by the _cached_mode property, # instead of calling source_mode(). This will prevent frequent VISA calls to the instrument. Calling # _set_source_mode will change the chased value. self._cached_mode = "VOLT" # We want to cache the range value so communication with the instrument only happens when the set the # range. Getting the range always returns the cached value. This value is adjusted when calling # self._set_range self._cached_range_value = None # type: Optional[float] self.add_parameter('voltage_range', label='Voltage Source Range', unit='V', get_cmd=partial(self._get_range, "VOLT"), set_cmd=partial(self._set_range, "VOLT"), vals=Enum(10e-3, 100e-3, 1e0, 10e0, 30e0)) self.add_parameter('current_range', label='Current Source Range', unit='I', get_cmd=partial(self._get_range, "CURR"), set_cmd=partial(self._set_range, "CURR"), vals=Enum(1e-3, 10e-3, 100e-3, 200e-3)) # This is changed through the source_mode interface self.range = self.voltage_range self._auto_range = False self.add_parameter('auto_range', label='Auto Range', set_cmd=self._set_auto_range, get_cmd=lambda: self._auto_range, vals=Bool()) self.add_parameter('voltage', label='Voltage', unit='V', set_cmd=partial(self._get_set_output, "VOLT"), get_cmd=partial(self._get_set_output, "VOLT")) self.add_parameter('current', label='Current', unit='I', set_cmd=partial(self._get_set_output, "CURR"), get_cmd=partial(self._get_set_output, "CURR")) # This is changed through the source_mode interface self.output_level = self.voltage self.add_parameter('voltage_limit', label='Voltage Protection Limit', unit='V', vals=Ints(1, 30), get_cmd=":SOUR:PROT:VOLT?", set_cmd=":SOUR:PROT:VOLT {}", get_parser=float_round, set_parser=int) self.add_parameter('current_limit', label='Current Protection Limit', unit='I', vals=Numbers(1e-3, 200e-3), get_cmd=":SOUR:PROT:CURR?", set_cmd=":SOUR:PROT:CURR {:.3f}", get_parser=float, set_parser=float) self.add_parameter('four_wire', label='Four Wire Sensing', get_cmd=':SENS:REM?', set_cmd=':SENS:REM {}', val_mapping={ 'off': 0, 'on': 1, }) # Note: The guard feature can be used to remove common mode noise. # Read the manual to see if you would like to use it self.add_parameter('guard', label='Guard Terminal', get_cmd=':SENS:GUAR?', set_cmd=':SENS:GUAR {}', val_mapping={ 'off': 0, 'on': 1, }) # Return measured line frequency self.add_parameter("line_freq", label='Line Frequency', unit="Hz", get_cmd="SYST:LFR?", get_parser=int) # Reset function # self.add_function('reset', call_cmd='*RST') self.connect_message()
def test_bad(self): for enum in self.not_enums: with self.assertRaises(TypeError): Enum(*enum)
def __init__(self, name, device, ai_channels=None): super().__init__(name) self._ai_task = None time_constant = 0.0000000001 rate = 100e3 self._device = device if ai_channels is None: ai_channels = { 0: { 'range': 10, 'mode': 'diff' }, 1: { 'range': 10, 'mode': 'diff' }, 2: { 'range': 10, 'mode': 'diff' }, 3: { 'range': 10, 'mode': 'diff' } } self._make_ai_task(ai_channels, time_constant, rate) self.add_parameter(name='time_constant', label='Time constant', get_cmd=self._ai_task.time_constant, set_cmd=self._ai_task.time_constant, set_parser=float, unit='s', vals=Numbers(min_value=0.0001)) self.add_parameter(name='sample_rate', label='Sample rate', get_cmd=self._ai_task.sample_rate, set_cmd=self._ai_task.sample_rate, set_parser=int, unit='S/s', vals=Ints(max_value=int(1e6))) self.add_parameter( name='input_range', label='Input rate', # get_cmd=self._ai_task.input_range, set_cmd=self._ai_task.input_range, set_parser=float, unit='V', vals=Enum(0.316, 1.00, 3.16, 10.0, 31.6, 42.4)) self.add_parameter( 'ai', get_cmd=self._ai_task.read, # get_parser=float, names=['ai%d' % ch for ch in ai_channels], units=['V'] * len(ai_channels), parameter_class=ParameterArray) for ch in ai_channels: self.add_parameter('ai%d' % ch, get_cmd=partial(self._get_ai_ch, ch), unit='V') self.add_parameter('ai%d_range' % ch, label='Range ai%d' % ch, set_cmd=partial(self._ai_range, ch), get_cmd=partial(self._ai_range, ch), set_parser=float, unit='V', vals=Enum(0.316, 1.00, 3.16, 10.0, 31.6, 42.4)) self.add_parameter('ai%d_mode' % ch, label='Mode ai%d' % ch, set_cmd=partial(self._ai_mode, ch), get_cmd=partial(self._ai_mode, ch), vals=Enum('diff', 'pseudo_diff', 'nrse', 'rse'))
def __init__( self, parent: "PNABase", name: str, trace_name: str, trace_num: int, **kwargs: Any, ) -> None: super().__init__(parent, name, **kwargs) self.trace_name = trace_name self.trace_num = trace_num # Name of parameter (i.e. S11, S21 ...) self.add_parameter('trace', label='Trace', get_cmd=self._Sparam, set_cmd=self._set_Sparam) # Format # Note: Currently parameters that return complex values are not # supported as there isn't really a good way of saving them into the # dataset self.add_parameter('format', label='Format', get_cmd='CALC:FORM?', set_cmd='CALC:FORM {}', vals=Enum('MLIN', 'MLOG', 'PHAS', 'UPH', 'IMAG', 'REAL')) # And a list of individual formats self.add_parameter('magnitude', sweep_format='MLOG', label='Magnitude', unit='dB', parameter_class=FormattedSweep, vals=Arrays(shape=(self.parent.points,))) self.add_parameter('linear_magnitude', sweep_format='MLIN', label='Magnitude', unit='ratio', parameter_class=FormattedSweep, vals=Arrays(shape=(self.parent.points,))) self.add_parameter('phase', sweep_format='PHAS', label='Phase', unit='deg', parameter_class=FormattedSweep, vals=Arrays(shape=(self.parent.points,))) self.add_parameter('unwrapped_phase', sweep_format='UPH', label='Phase', unit='deg', parameter_class=FormattedSweep, vals=Arrays(shape=(self.parent.points,))) self.add_parameter("group_delay", sweep_format='GDEL', label='Group Delay', unit='s', parameter_class=FormattedSweep, vals=Arrays(shape=(self.parent.points,))) self.add_parameter('real', sweep_format='REAL', label='Real', unit='LinMag', parameter_class=FormattedSweep, vals=Arrays(shape=(self.parent.points,))) self.add_parameter('imaginary', sweep_format='IMAG', label='Imaginary', unit='LinMag', parameter_class=FormattedSweep, vals=Arrays(shape=(self.parent.points,)))
def __init__(self, name, address, reset_device=False, **kwargs): """ Driver for the Keithley 6500 multimeter. Based on the Keithley 2000 driver, commands have been adapted for the Keithley 6500. This driver does not contain all commands available, but only the ones most commonly used. Status: beta-version. Args: name (str): The name used internally by QCoDeS in the DataSet. address (str): The VISA device address. reset_device (bool): Reset the device on startup if true. """ super().__init__(name, address, terminator='\n', **kwargs) command_set = self.ask('*LANG?') if command_set != 'SCPI': error_msg = "This driver only compatible with the 'SCPI' command " \ "set, not '{}' set".format(command_set) raise CommandSetError(error_msg) self._trigger_sent = False self._mode_map = { 'ac current': 'CURR:AC', 'dc current': 'CURR:DC', 'ac voltage': 'VOLT:AC', 'dc voltage': 'VOLT:DC', '2w resistance': 'RES', '4w resistance': 'FRES', 'temperature': 'TEMP', 'frequency': 'FREQ' } self.add_parameter('mode', get_cmd='SENS:FUNC?', set_cmd="SENS:FUNC {}", val_mapping=self._mode_map) self.add_parameter('nplc', get_cmd=partial(self._get_mode_param, 'NPLC', float), set_cmd=partial(self._set_mode_param, 'NPLC'), vals=Numbers(min_value=0.01, max_value=10)) # TODO: validator, this one is more difficult since different modes # require different validation ranges. self.add_parameter('range', get_cmd=partial(self._get_mode_param, 'RANG', float), set_cmd=partial(self._set_mode_param, 'RANG'), vals=Numbers()) self.add_parameter('auto_range_enabled', get_cmd=partial(self._get_mode_param, 'RANG:AUTO', _parse_output_bool), set_cmd=partial(self._set_mode_param, 'RANG:AUTO'), vals=Bool()) self.add_parameter('digits', get_cmd='DISP:VOLT:DC:DIG?', get_parser=int, set_cmd='DISP:VOLT:DC:DIG? {}', vals=Ints(min_value=4, max_value=7)) self.add_parameter('averaging_type', get_cmd=partial(self._get_mode_param, 'AVER:TCON', _parse_output_string), set_cmd=partial(self._set_mode_param, 'AVER:TCON'), vals=Enum('moving', 'repeat')) self.add_parameter('averaging_count', get_cmd=partial(self._get_mode_param, 'AVER:COUN', int), set_cmd=partial(self._set_mode_param, 'AVER:COUN'), vals=Ints(min_value=1, max_value=100)) self.add_parameter('averaging_enabled', get_cmd=partial(self._get_mode_param, 'AVER:STAT', _parse_output_bool), set_cmd=partial(self._set_mode_param, 'AVER:STAT'), vals=Bool()) # Global parameters self.add_parameter('display_backlight', docstring='Control the brightness of the display ' 'backligt. Off turns the display off and' 'Blackout also turns off indicators and ' 'key lights on the device.', get_cmd='DISP:LIGH:STAT?', set_cmd='DISP:LIGH:STAT {}', val_mapping={ 'On 100': 'ON100', 'On 75': 'ON75', 'On 50': 'ON50', 'On 25': 'ON25', 'Off': 'OFF', 'Blackout': 'BLACkout' }) self.add_parameter('trigger_count', get_parser=int, get_cmd='ROUT:SCAN:COUN:SCAN?', set_cmd='ROUT:SCAN:COUN:SCAN {}', vals=MultiType( Ints(min_value=1, max_value=9999), Enum('inf', 'default', 'minimum', 'maximum'))) for trigger in range(1, 5): self.add_parameter('trigger%i_delay' % trigger, docstring='Set and read trigger delay for ' 'timer %i.' % trigger, get_parser=float, get_cmd='TRIG:TIM%i:DEL?' % trigger, set_cmd='TRIG:TIM%i:DEL {}' % trigger, unit='s', vals=Numbers(min_value=0, max_value=999999.999)) self.add_parameter('trigger%i_source' % trigger, docstring='Set the trigger source for ' 'timer %i.' % trigger, get_cmd='TRIG:TIM%i:STAR:STIM?' % trigger, set_cmd='TRIG:TIM%i:STAR:STIM {}' % trigger, val_mapping={ 'immediate': 'NONE', 'timer1': 'TIM1', 'timer2': 'TIM2', 'timer3': 'TIM3', 'timer4': 'TIM4', 'notify1': 'NOT1', 'notify2': 'NOT2', 'notify3': 'NOT3', 'front-panel': 'DISP', 'bus': 'COMM', 'external': 'EXT' }) self.add_parameter('trigger_timer', get_parser=float, get_cmd='ROUT:SCAN:INT?', set_cmd='ROUT:SCAN:INT {}', unit='s', vals=Numbers(min_value=0.001, max_value=999999.999)) self.add_parameter('amplitude', get_cmd=self._read_next_value, set_cmd=False, unit='a.u.') if reset_device: self.reset() self.write('FORM:DATA ASCII') self.connect_message()
def __init__(self, name, cardid='spcm0', **kwargs): """Driver for the Spectrum M4i.44xx-x8 cards. For more information see: http://spectrum-instrumentation.com/en/m4i-platform-overview Example: Example usage for acquisition with channel 2 using an external trigger that triggers multiple times with trigger mode HIGH:: m4 = M4i(name='M4i', server_name=None) m4.enable_channels(pyspcm.CHANNEL2) m4.set_channel_settings(2,mV_range, input_path, termination, coupling, compensation) m4.set_ext0_OR_trigger_settings(pyspcm.SPC_TM_HIGH,termination,coupling,level0) calc = m4.multiple_trigger_acquisition(mV_range,memsize,seg_size,posttrigger_size) Todo: Whenever an error occurs (including validation errors) the python console needs to be restarted """ super().__init__(name, **kwargs) self.hCard = pyspcm.spcm_hOpen(cardid) if self.hCard is None: logging.warning("M4i: no card found\n") # add parameters for getting self.add_parameter('card_id', label='card id', parameter_class=ManualParameter, initial_value=cardid, vals=Anything(), docstring='The card ID') self.add_parameter('max_sample_rate', label='max sample rate', unit='Hz', get_cmd=self.get_max_sample_rate, docstring='The maximumum sample rate') self.add_parameter('memory', label='memory', unit='bytes', get_cmd=self.get_card_memory, docstring='Amount of memory on card') self.add_parameter('resolution', label='resolution', unit='bits', get_cmd=partial(self._param32bit, pyspcm.SPC_MIINST_BITSPERSAMPLE), docstring='Resolution of the card') self.add_parameter('pcidate', label='pcidate', get_cmd=partial(self._param32bit, pyspcm.SPC_PCIDATE), docstring='The PCI date') self.add_parameter('serial_number', label='serial number', get_cmd=partial(self._param32bit, pyspcm.SPC_PCISERIALNO), docstring='The serial number of the board') self.add_parameter('channel_count', label='channel count', get_cmd=partial(self._param32bit, pyspcm.SPC_CHCOUNT), docstring='Return number of enabled channels') self.add_parameter('input_path_count', label='input path count', get_cmd=partial(self._param32bit, pyspcm.SPC_READAIPATHCOUNT), docstring='Return number of analog input paths') self.add_parameter('input_ranges_count', label='input ranges count', get_cmd=partial(self._param32bit, pyspcm.SPC_READIRCOUNT), docstring='Return number of input ranges for the current input path') self.add_parameter('input_path_features', label='input path features', get_cmd=partial(self._param32bit, pyspcm.SPC_READAIFEATURES), docstring='Return a bitmap of features for current input path') self.add_parameter('available_card_modes', label='available card modes', get_cmd=partial(self._param32bit, pyspcm.SPC_AVAILCARDMODES), docstring='Return a bitmap of available card modes') self.add_parameter('card_status', label='card status', get_cmd=partial(self._param32bit, pyspcm.SPC_M2STATUS), docstring='Return a bitmap for the status information') self.add_parameter('read_range_min_0', label='read range min 0', unit='mV', get_cmd=partial(self._param32bit, pyspcm.SPC_READRANGEMIN0), docstring='Return the lower border of input range 0') # buffer handling self.add_parameter('user_available_length', label='user available length', get_cmd=partial(self._param32bit, pyspcm.SPC_DATA_AVAIL_USER_LEN), docstring='returns the number of currently to the user available bytes inside a sample data transfer') self.add_parameter('user_available_position', label='user available position', get_cmd=partial(self._param32bit, pyspcm.SPC_DATA_AVAIL_USER_POS), docstring='returns the position as byte index where the currently available data samles start') self.add_parameter('buffer_fill_size', label='buffer fill size', get_cmd=partial(self._param32bit, pyspcm.SPC_FILLSIZEPROMILLE), docstring='returns the current fill size of the on-board memory (FIFO buffer) in promille (1/1000)') # triggering self.add_parameter('available_trigger_or_mask', label='available trigger or mask', get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_AVAILORMASK), docstring='bitmask, in which all bits of sources for the OR mask are set, if available') self.add_parameter('available_channel_or_mask', label='available channel or mask', get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_CH_AVAILORMASK0), docstring='bitmask, in which all bits of sources/channels (0-31) for the OR mask are set, if available') self.add_parameter('available_trigger_and_mask', label='available trigger and mask', get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_AVAILANDMASK), docstring='bitmask, in which all bits of sources for the AND mask are set, if available') self.add_parameter('available_channel_and_mask', label='available channel and mask', get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_CH_AVAILANDMASK0), docstring='bitmask, in which all bits of sources/channels (0-31) for the AND mask are set, if available') self.add_parameter('available_trigger_delay', label='available trigger delay', get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_AVAILDELAY), docstring='contains the maximum available delay as decimal integer value') self.add_parameter('available_external_trigger_modes', label='available external trigger modes', get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_EXT0_AVAILMODES), docstring='bitmask showing all available trigger modes for external 0 (main analog trigger input)') self.add_parameter('external_trigger_min_level', label='external trigger min level', unit='mV', get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_EXT_AVAIL0_MIN), docstring='returns the minimum trigger level') self.add_parameter('external_trigger_max_level', label='external trigger max level', unit='mV', get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_EXT_AVAIL0_MAX), docstring='returns the maximum trigger level') self.add_parameter('external_trigger_level_step_size', label='external trigger level step size', unit='mV', get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_EXT_AVAIL0_STEP), docstring='returns the step size of the trigger level') self.add_parameter('available_channel_trigger_modes', label='available channel trigger modes', get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_CH_AVAILMODES), docstring='bitmask, in which all bits of the modes for the channel trigger are set') self.add_parameter('trigger_counter', label='trigger counter', get_cmd=partial(self._param32bit, pyspcm.SPC_TRIGGERCOUNTER), docstring='returns the number of triger events since acquisition start') # data per sample self.add_parameter('bytes_per_sample', label='bytes per sample', get_cmd=partial(self._param32bit, pyspcm.SPC_MIINST_BYTESPERSAMPLE), docstring='returns the number of bytes per sample') self.add_parameter('bits_per_sample', label='bits per sample', get_cmd=partial(self._param32bit, pyspcm.SPC_MIINST_BITSPERSAMPLE), docstring='returns the number of bits per sample') # available clock modes self.add_parameter('available_clock_modes', label='available clock modes', get_cmd=partial(self._param32bit, pyspcm.SPC_AVAILCLOCKMODES), docstring='returns a bitmask in which the bits of the clock modes are set, if available') # converting ADC samples to voltage values self.add_parameter('ADC_to_voltage', label='ADC to voltage', get_cmd=partial(self._param32bit, pyspcm.SPC_MIINST_MAXADCVALUE), docstring='contains the decimal code (in LSB) of the ADC full scale value') self.add_parameter('oversampling_factor', label='oversampling factor', get_cmd=partial(self._param32bit, pyspcm.SPC_OVERSAMPLINGFACTOR), docstring='Reads the oversampling factor') # add parameters for setting and getting (read/write direction # registers) self.add_parameter('enable_channels', label='Channels enabled', get_cmd=partial(self._param32bit, pyspcm.SPC_CHENABLE), set_cmd=partial(self._set_param32bit, pyspcm.SPC_CHENABLE), vals=Enum(1, 2, 4, 8, 3, 5, 9, 6, 10, 12, 15), docstring='Set and get enabled channels') # analog input path functions # TODO: change Enum validator to set_parser for the numbered functions # if we want string inputs self.add_parameter('read_input_path', label='read input path', get_cmd=partial(self._param32bit, pyspcm.SPC_READAIPATH), set_cmd=partial(self._set_param32bit, pyspcm.SPC_READAIPATH), vals=Enum(0, 1, 2, 3), docstring='Select the input path which is used to read out the features') for i in [0, 1, 2, 3]: self.add_parameter('input_path_{}'.format(i), label='input path {}'.format(i), get_cmd=partial(self._param32bit, getattr( pyspcm, 'SPC_PATH{}'.format(i))), set_cmd=partial(self._set_param32bit, getattr( pyspcm, 'SPC_PATH{}'.format(i))), vals=Enum(0, 1), docstring='Set and get analog input path for channel {}'.format(i)) # channel range functions # TODO: check the input path to set the right validator (either by # directly calling input_path_x() or by storing a variable) self.add_parameter('range_channel_{}'.format(i), label='range channel {}'.format(i), get_cmd=partial(self._param32bit, getattr( pyspcm, 'SPC_AMP{}'.format(i))), set_cmd=partial(self._set_param32bit, getattr( pyspcm, 'SPC_AMP{}'.format(i))), vals=Enum(200, 500, 1000, 2000, 2500, 5000, 10000), docstring='Set and get input range of channel {}'.format(i)) # input termination functions self.add_parameter('termination_{}'.format(i), label='termination {}'.format(i), get_cmd=partial(self._param32bit, getattr( pyspcm, 'SPC_50OHM{}'.format(i))), set_cmd=partial(self._set_param32bit, getattr( pyspcm, 'SPC_50OHM{}'.format(i))), vals=Enum(0, 1), docstring='if 1 sets termination to 50 Ohm, otherwise 1 MOhm for channel {}'.format(i)) # input coupling self.add_parameter('ACDC_coupling_{}'.format(i), label='ACDC coupling {}'.format(i), get_cmd=partial(self._param32bit, getattr( pyspcm, 'SPC_ACDC{}'.format(i))), set_cmd=partial(self._set_param32bit, getattr( pyspcm, 'SPC_ACDC{}'.format(i))), vals=Enum(0, 1), docstring='if 1 sets the AC coupling, otherwise sets the DC coupling for channel {}'.format(i)) # AC/DC offset compensation self.add_parameter('ACDC_offs_compensation_{}'.format(i), label='ACDC offs compensation {}'.format(i), get_cmd=partial(self._get_compensation, i), set_cmd=partial(self._set_compensation, i), vals=Enum(0, 1), docstring='if 1 enables compensation, if 0 disables compensation for channel {}'.format(i)) # anti aliasing filter (Bandwidth limit) self.add_parameter('anti_aliasing_filter_{}'.format(i), label='anti aliasing filter {}'.format(i), get_cmd=partial(self._param32bit, getattr( pyspcm, 'SPC_FILTER{}'.format(i))), set_cmd=partial(self._set_param32bit, getattr( pyspcm, 'SPC_FILTER{}'.format(i))), vals=Enum(0, 1), docstring='if 1 selects bandwidth limit, if 0 sets to full bandwidth for channel {}'.format(i)) self.add_parameter('channel_{}'.format(i), label='channel {}'.format(i), unit='a.u.', get_cmd=partial(self._read_channel, i)) # acquisition modes # TODO: If required, the other acquisition modes can be added to the # validator self.add_parameter('card_mode', label='card mode', get_cmd=partial(self._param32bit, pyspcm.SPC_CARDMODE), set_cmd=partial(self._set_param32bit, pyspcm.SPC_CARDMODE), vals=Enum(pyspcm.SPC_REC_STD_SINGLE, pyspcm.SPC_REC_STD_MULTI, pyspcm.SPC_REC_STD_GATE, pyspcm.SPC_REC_STD_ABA, pyspcm.SPC_REC_FIFO_SINGLE, pyspcm.SPC_REC_FIFO_MULTI, pyspcm.SPC_REC_FIFO_GATE, pyspcm.SPC_REC_FIFO_ABA, pyspcm.SPC_REC_STD_AVERAGE), docstring='defines the used operating mode') # wait command self.add_parameter('timeout', label='timeout', get_cmd=partial(self._param32bit, pyspcm.SPC_TIMEOUT), unit='ms', set_cmd=partial(self._set_param32bit, pyspcm.SPC_TIMEOUT), docstring='defines the timeout for wait commands') # Single acquisition mode memory, pre- and posttrigger (pretrigger = memory size - posttrigger) # TODO: improve the validators to make them take into account the # current state of the instrument self.add_parameter('data_memory_size', label='data memory size', get_cmd=partial(self._param32bit, pyspcm.SPC_MEMSIZE), set_cmd=partial(self._set_param32bit, pyspcm.SPC_MEMSIZE), vals=Numbers(min_value=16), docstring='sets the memory size in samples per channel') self.add_parameter('posttrigger_memory_size', label='posttrigger memory size', get_cmd=partial(self._param32bit, pyspcm.SPC_POSTTRIGGER), set_cmd=partial(self._set_param32bit, pyspcm.SPC_POSTTRIGGER), docstring='sets the number of samples to be recorded after trigger event') # FIFO single acquisition length and pretrigger self.add_parameter('pretrigger_memory_size', label='pretrigger memory size', get_cmd=partial(self._param32bit, pyspcm.SPC_PRETRIGGER), set_cmd=partial(self._set_param32bit, pyspcm.SPC_PRETRIGGER), docstring='sets the number of samples to be recorded before trigger event') self.add_parameter('segment_size', label='segment size', get_cmd=partial(self._param32bit, pyspcm.SPC_SEGMENTSIZE), set_cmd=partial(self._set_param32bit, pyspcm.SPC_SEGMENTSIZE), docstring='length of segments to acquire') self.add_parameter('total_segments', label='total segments', get_cmd=partial(self._param32bit, pyspcm.SPC_LOOPS), set_cmd=partial(self._set_param32bit, pyspcm.SPC_LOOPS), docstring='number of segments to acquire in total. Setting 0 makes it run until stopped by user') # clock generation self.add_parameter('clock_mode', label='clock mode', get_cmd=partial(self._param32bit, pyspcm.SPC_CLOCKMODE), set_cmd=partial(self._set_param32bit, pyspcm.SPC_CLOCKMODE), vals=Enum(pyspcm.SPC_CM_INTPLL, pyspcm.SPC_CM_QUARTZ2, pyspcm.SPC_CM_EXTREFCLOCK, pyspcm.SPC_CM_PXIREFCLOCK), docstring='defines the used clock mode or reads out the actual selected one') self.add_parameter('sample_rate', label='sample rate', get_cmd=partial(self._param32bit, pyspcm.SPC_SAMPLERATE), unit='Hz', set_cmd=partial(self._set_param32bit, pyspcm.SPC_SAMPLERATE), docstring='write the sample rate for internal sample generation or read rate nearest to desired') self.add_parameter('special_clock', label='special clock', get_cmd=partial(self._param32bit, pyspcm.SPC_SPECIALCLOCK), unit='Hz', set_cmd=partial(self._set_param32bit, pyspcm.SPC_SPECIALCLOCK), docstring='Activate/Deactivate the special clock mode (lower and more sampling clock rates)') # triggering self.add_parameter('trigger_or_mask', label='trigger or mask', get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_ORMASK), set_cmd=partial(self._set_param32bit, pyspcm.SPC_TRIG_ORMASK), vals=Enum(pyspcm.SPC_TMASK_NONE, pyspcm.SPC_TMASK_SOFTWARE, pyspcm.SPC_TMASK_EXT0, pyspcm.SPC_TMASK_EXT1), docstring='defines the events included within the trigger OR mask card') self.add_parameter('channel_or_mask', label='channel or mask', get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_CH_ORMASK0), set_cmd=partial(self._set_param32bit, pyspcm.SPC_TRIG_CH_ORMASK0), docstring='includes the channels (0-31) within the channel trigger OR mask of the card') self.add_parameter('trigger_and_mask', label='trigger and mask', get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_ANDMASK), set_cmd=partial(self._set_param32bit, pyspcm.SPC_TRIG_ANDMASK), vals=Enum(pyspcm.SPC_TMASK_NONE, pyspcm.SPC_TMASK_EXT0, pyspcm.SPC_TMASK_EXT1), docstring='defines the events included within the trigger AND mask card') self.add_parameter('channel_and_mask', label='channel and mask', get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_CH_ANDMASK0), set_cmd=partial(self._set_param32bit, pyspcm.SPC_TRIG_CH_ANDMASK0), docstring='includes the channels (0-31) within the channel trigger AND mask of the card') self.add_parameter('trigger_delay', label='trigger delay', get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_DELAY), set_cmd=partial(self._set_param32bit, pyspcm.SPC_TRIG_DELAY), docstring='defines the delay for the detected trigger events') self.add_parameter('external_trigger_mode', label='external trigger mode', get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_EXT0_MODE), set_cmd=partial(self._set_param32bit, pyspcm.SPC_TRIG_EXT0_MODE), docstring='defines the external trigger mode for the external SMA connector trigger input') self.add_parameter('external_trigger_termination', label='external trigger termination', get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_TERM), set_cmd=partial(self._set_param32bit, pyspcm.SPC_TRIG_TERM), vals=Enum(0, 1), docstring='A 1 sets the 50 Ohm termination, a 0 sets high impedance termination') self.add_parameter('external_trigger_input_coupling', label='external trigger input coupling', get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_EXT0_ACDC), set_cmd=partial(self._set_param32bit, pyspcm.SPC_TRIG_EXT0_ACDC), vals=Enum(0, 1), docstring='A 1 sets the AC coupling for the external trigger, a 0 sets DC') for l in [0, 1]: self.add_parameter('external_trigger_level_{}'.format(l), label='external trigger level {}'.format(l), get_cmd=partial(self._param32bit, getattr( pyspcm, 'SPC_TRIG_EXT0_LEVEL{}'.format(l))), set_cmd=partial(self._set_param32bit, getattr( pyspcm, 'SPC_TRIG_EXT0_LEVEL{}'.format(l))), docstring='trigger level {} for external trigger'.format(l)) for i in [0, 1, 2, 3]: self.add_parameter('trigger_mode_channel_{}'.format(i), label='trigger mode channel {}'.format(i), get_cmd=partial(self._param32bit, getattr( pyspcm, 'SPC_TRIG_CH{}_MODE'.format(i))), set_cmd=partial(self._set_param32bit, getattr( pyspcm, 'SPC_TRIG_CH{}_MODE'.format(i))), docstring='sets the trigger mode for channel {}'.format(i)) for l in [0, 1]: self.add_parameter('trigger_channel_{}_level_{}'.format(i, l), label='trigger channel {} level {}'.format( i, l), get_cmd=partial(self._param32bit, getattr( pyspcm, 'SPC_TRIG_CH{}_LEVEL{}'.format(i, l))), set_cmd=partial(self._set_param32bit, getattr( pyspcm, 'SPC_TRIG_CH{}_LEVEL{}'.format(i, l))), docstring='trigger level {} channel {}'.format(l, i)) # add parameters for setting (write only registers) # Buffer handling self.add_parameter('card_available_length', label='card available length', set_cmd=partial(self._set_param32bit, pyspcm.SPC_DATA_AVAIL_CARD_LEN), docstring='writes the number of bytes that the card can now use for sample data transfer again') # General self.add_parameter('general_command', label='general command', set_cmd=partial(self._set_param32bit, pyspcm.SPC_M2CMD), docstring='executes a command for the card or data transfer') # memsize used for simple channel read-out self._channel_memsize = 2**12
class SR86x(VisaInstrument): """ This is the code for Stanford_SR865 Lock-in Amplifier """ _VOLT_TO_N = { 1: 0, 500e-3: 1, 200e-3: 2, 100e-3: 3, 50e-3: 4, 20e-3: 5, 10e-3: 6, 5e-3: 7, 2e-3: 8, 1e-3: 9, 500e-6: 10, 200e-6: 11, 100e-6: 12, 50e-6: 13, 20e-6: 14, 10e-6: 15, 5e-6: 16, 2e-6: 17, 1e-6: 18, 500e-9: 19, 200e-9: 20, 100e-9: 21, 50e-9: 22, 20e-9: 23, 10e-9: 24, 5e-9: 25, 2e-9: 26, 1e-9: 27 } _N_TO_VOLT = {v: k for k, v in _VOLT_TO_N.items()} _CURR_TO_N = { 1e-6: 0, 500e-9: 1, 200e-9: 2, 100e-9: 3, 50e-9: 4, 20e-9: 5, 10e-9: 6, 5e-9: 7, 2e-9: 8, 1e-9: 9, 500e-12: 10, 200e-12: 11, 100e-12: 12, 50e-12: 13, 20e-12: 14, 10e-12: 15, 5e-12: 16, 2e-12: 17, 1e-12: 18, 500e-15: 19, 200e-15: 20, 100e-15: 21, 50e-15: 22, 20e-15: 23, 10e-15: 24, 5e-15: 25, 2e-15: 26, 1e-15: 27 } _N_TO_CURR = {v: k for k, v in _CURR_TO_N.items()} _VOLT_ENUM = Enum(*_VOLT_TO_N.keys()) _CURR_ENUM = Enum(*_CURR_TO_N.keys()) _INPUT_SIGNAL_TO_N = { 'voltage': 0, 'current': 1, } _N_TO_INPUT_SIGNAL = {v: k for k, v in _INPUT_SIGNAL_TO_N.items()} PARAMETER_NAMES = { 'X': '0', # X output, 'X' 'Y': '1', # Y output, 'Y' 'R': '2', # R output, 'R' 'P': '3', # theta output, 'THeta' 'aux_in1': '4', # Aux In 1, 'IN1' 'aux_in2': '5', # Aux In 2, 'IN2' 'aux_in3': '6', # Aux In 3, 'IN3' 'aux_in4': '7', # Aux In 4, 'IN4' 'Xnoise': '8', # X noise, 'XNOise' 'Ynoise': '9', # Y noise, 'YNOise' 'aux_out1': '10', # Aux Out 1, 'OUT1' 'aux_out2': '11', # Aux Out 2, 'OUT2' 'phase': '12', # Reference Phase, 'PHAse' 'amplitude': '13', # Sine Out Amplitude, 'SAMp' 'sine_outdc': '14', # DC Level, 'LEVel' 'frequency': '15', # Int. Ref. Frequency, 'FInt' 'frequency_ext': '16', # Ext. Ref. Frequency, 'FExt' } _N_DATA_CHANNELS = 4 def __init__(self, name: str, address: str, max_frequency: float, reset: bool = False, **kwargs: Any): super().__init__(name, address, terminator='\n', **kwargs) self._max_frequency = max_frequency # Reference commands self.add_parameter(name='frequency', label='Frequency', unit='Hz', get_cmd='FREQ?', set_cmd='FREQ {}', get_parser=float, vals=Numbers(min_value=1e-3, max_value=self._max_frequency)) self.add_parameter(name='sine_outdc', label='Sine out dc level', unit='V', get_cmd='SOFF?', set_cmd='SOFF {}', get_parser=float, vals=Numbers(min_value=-5, max_value=5)) self.add_parameter(name='amplitude', label='Amplitude', unit='V', get_cmd='SLVL?', set_cmd='SLVL {}', get_parser=float, vals=Numbers(min_value=0, max_value=2)) self.add_parameter(name='harmonic', label='Harmonic', get_cmd='HARM?', get_parser=int, set_cmd='HARM {:d}', vals=Ints(min_value=1, max_value=99)) self.add_parameter(name='phase', label='Phase', unit='deg', get_cmd='PHAS?', set_cmd='PHAS {}', get_parser=float, vals=Numbers(min_value=-3.6e5, max_value=3.6e5)) # Signal commands self.add_parameter(name='sensitivity', label='Sensitivity', get_cmd='SCAL?', set_cmd='SCAL {:d}', get_parser=self._get_sensitivity, set_parser=self._set_sensitivity) self.add_parameter(name='filter_slope', label='Filter slope', unit='dB/oct', get_cmd='OFSL?', set_cmd='OFSL {}', val_mapping={ 6: 0, 12: 1, 18: 2, 24: 3 }) self.add_parameter(name='sync_filter', label='Sync filter', get_cmd='SYNC?', set_cmd='SYNC {}', val_mapping={ 'OFF': 0, 'ON': 1 }) self.add_parameter(name='noise_bandwidth', label='Noise bandwidth', unit='Hz', get_cmd='ENBW?', get_parser=float) self.add_parameter(name='signal_strength', label='Signal strength indicator', get_cmd='ILVL?', get_parser=int) self.add_parameter(name='signal_input', label='Signal input', get_cmd='IVMD?', get_parser=self._get_input_config, set_cmd='IVMD {}', set_parser=self._set_input_config, vals=Enum(*self._INPUT_SIGNAL_TO_N.keys())) self.add_parameter(name='input_range', label='Input range', unit='V', get_cmd='IRNG?', set_cmd='IRNG {}', val_mapping={ 1: 0, 300e-3: 1, 100e-3: 2, 30e-3: 3, 10e-3: 4 }) self.add_parameter(name='input_config', label='Input configuration', get_cmd='ISRC?', set_cmd='ISRC {}', val_mapping={ 'a': 0, 'a-b': 1 }) self.add_parameter(name='input_shield', label='Input shield', get_cmd='IGND?', set_cmd='IGND {}', val_mapping={ 'float': 0, 'ground': 1 }) self.add_parameter(name='input_gain', label='Input gain', unit='ohm', get_cmd='ICUR?', set_cmd='ICUR {}', val_mapping={ 1e6: 0, 100e6: 1 }) self.add_parameter(name='adv_filter', label='Advanced filter', get_cmd='ADVFILT?', set_cmd='ADVFILT {}', val_mapping={ 'OFF': 0, 'ON': 1 }) self.add_parameter(name='input_coupling', label='Input coupling', get_cmd='ICPL?', set_cmd='ICPL {}', val_mapping={ 'ac': 0, 'dc': 1 }) self.add_parameter(name='time_constant', label='Time constant', unit='s', get_cmd='OFLT?', set_cmd='OFLT {}', val_mapping={ 1e-6: 0, 3e-6: 1, 10e-6: 2, 30e-6: 3, 100e-6: 4, 300e-6: 5, 1e-3: 6, 3e-3: 7, 10e-3: 8, 30e-3: 9, 100e-3: 10, 300e-3: 11, 1: 12, 3: 13, 10: 14, 30: 15, 100: 16, 300: 17, 1e3: 18, 3e3: 19, 10e3: 20, 30e3: 21 }) self.add_parameter( name="external_reference_trigger", label="External reference trigger mode", get_cmd="RTRG?", set_cmd="RTRG {}", val_mapping={ "SIN": 0, "POS": 1, "POSTTL": 1, "NEG": 2, "NEGTTL": 2, }, docstring="The triggering mode for synchronization of the " "internal reference signal with the externally provided " "one") self.add_parameter(name="reference_source", label="Reference source", get_cmd="RSRC?", set_cmd="RSRC {}", val_mapping={ "INT": 0, "EXT": 1, "DUAL": 2, "CHOP": 3 }, docstring="The source of the reference signal") self.add_parameter( name="external_reference_trigger_input_resistance", label="External reference trigger input resistance", get_cmd="REFZ?", set_cmd="REFZ {}", val_mapping={ "50": 0, "50OHMS": 0, 0: 0, "1M": 1, "1MEG": 1, 1: 1, }, docstring="Input resistance of the input for the external " "reference signal") # Auto functions self.add_function('auto_range', call_cmd='ARNG') self.add_function('auto_scale', call_cmd='ASCL') self.add_function('auto_phase', call_cmd='APHS') # Data transfer # first 4 parameters from a list of 16 below. self.add_parameter('X', label='In-phase Magnitude', get_cmd='OUTP? 0', get_parser=float, unit='V') self.add_parameter('Y', label='Out-phase Magnitude', get_cmd='OUTP? 1', get_parser=float, unit='V') self.add_parameter('R', label='Magnitude', get_cmd='OUTP? 2', get_parser=float, unit='V') self.add_parameter('P', label='Phase', get_cmd='OUTP? 3', get_parser=float, unit='deg') # CH1/CH2 Output Commands self.add_parameter('X_offset', label='X offset ', unit='%', get_cmd='COFP? 0', set_cmd='COFP 0, {}', get_parser=float, vals=Numbers(min_value=-999.99, max_value=999.99)) self.add_parameter('Y_offset', label='Y offset', unit='%', get_cmd='COFP? 1', set_cmd='COFP 1, {}', get_parser=float, vals=Numbers(min_value=-999.99, max_value=999.99)) self.add_parameter('R_offset', label='R offset', unit='%', get_cmd='COFP? 2', set_cmd='COFP 2, {}', get_parser=float, vals=Numbers(min_value=-999.99, max_value=999.99)) self.add_parameter('X_expand', label='X expand multiplier', get_cmd='CEXP? 0', set_cmd='CEXP 0, {}', val_mapping={ 'OFF': '0', 'X10': '1', 'X100': '2' }) self.add_parameter('Y_expand', label='Y expand multiplier', get_cmd='CEXP? 1', set_cmd='CEXP 1, {}', val_mapping={ 'OFF': 0, 'X10': 1, 'X100': 2 }) self.add_parameter('R_expand', label='R expand multiplier', get_cmd='CEXP? 2', set_cmd='CEXP 2, {}', val_mapping={ 'OFF': 0, 'X10': 1, 'X100': 2 }) # Aux input/output for i in [0, 1, 2, 3]: self.add_parameter(f'aux_in{i}', label=f'Aux input {i}', get_cmd=f'OAUX? {i}', get_parser=float, unit='V') self.add_parameter(f'aux_out{i}', label=f'Aux output {i}', get_cmd=f'AUXV? {i}', get_parser=float, set_cmd=f'AUXV {i}, {{}}', unit='V') # Data channels: # 'DAT1' (green), 'DAT2' (blue), 'DAT3' (yellow), 'DAT4' (orange) data_channels = ChannelList(self, "data_channels", SR86xDataChannel, snapshotable=False) for num, color in zip(range(self._N_DATA_CHANNELS), ('green', 'blue', 'yellow', 'orange')): cmd_id = f"{num}" cmd_id_name = f"DAT{num + 1}" ch_name = f"data_channel_{num + 1}" data_channel = SR86xDataChannel(self, ch_name, cmd_id, cmd_id_name, color) data_channels.append(data_channel) self.add_submodule(ch_name, data_channel) data_channels.lock() self.add_submodule("data_channels", data_channels) # Interface self.add_function('reset', call_cmd='*RST') self.add_function('disable_front_panel', call_cmd='OVRM 0') self.add_function('enable_front_panel', call_cmd='OVRM 1') buffer = SR86xBuffer(self, f"{self.name}_buffer") self.add_submodule("buffer", buffer) self.input_config() self.connect_message() def _set_units(self, unit: str) -> None: for param in [self.X, self.Y, self.R, self.sensitivity]: param.unit = unit def _get_input_config(self, s: int) -> str: mode = self._N_TO_INPUT_SIGNAL[int(s)] if mode == 'voltage': self.sensitivity.vals = self._VOLT_ENUM self._set_units('V') else: self.sensitivity.vals = self._CURR_ENUM self._set_units('A') return mode def _set_input_config(self, s: str) -> int: if s == 'voltage': self.sensitivity.vals = self._VOLT_ENUM self._set_units('V') else: self.sensitivity.vals = self._CURR_ENUM self._set_units('A') return self._INPUT_SIGNAL_TO_N[s] def _get_sensitivity(self, s: int) -> float: if self.signal_input() == 'voltage': return self._N_TO_VOLT[int(s)] else: return self._N_TO_CURR[int(s)] def _set_sensitivity(self, s: float) -> int: if self.signal_input() == 'voltage': return self._VOLT_TO_N[s] else: return self._CURR_TO_N[s] def get_values(self, *parameter_names: str) -> Tuple[float, ...]: """ Get values of 2 or 3 parameters that are measured by the lock-in amplifier. These values are guaranteed to come from the same measurement cycle as opposed to getting values of parameters one by one (for example, by calling `sr.X()`, and then `sr.Y()`. Args: *parameter_names: 2 or 3 names of parameters for which the values are requested; valid names can be found in `PARAMETER_NAMES` attribute of the driver class Returns: a tuple of 2 or 3 floating point values """ if not 2 <= len(parameter_names) <= 3: raise KeyError( 'It is only possible to request values of 2 or 3 parameters ' 'at a time.') for name in parameter_names: if name not in self.PARAMETER_NAMES: raise KeyError(f'{name} is not a valid parameter name. Refer ' f'to `PARAMETER_NAMES` for a list of valid ' f'parameter names') p_ids = [self.PARAMETER_NAMES[name] for name in parameter_names] output = self.ask(f'SNAP? {",".join(p_ids)}') return tuple(float(val) for val in output.split(',')) def get_data_channels_values(self) -> Tuple[float, ...]: """ Queries the current values of the data channels Returns: tuple of 4 values of the data channels """ output = self.ask('SNAPD?') return tuple(float(val) for val in output.split(',')) def get_data_channels_parameters(self, query_instrument: bool = True ) -> Tuple[str, ...]: """ Convenience method to query a list of parameters which the data channels are currently assigned to. Args: query_instrument: If set to False, the internally cashed names of the parameters will be returned; if True, then the names will be queried through the instrument Returns: a tuple of 4 strings of parameter names """ if query_instrument: method_name = 'get' else: method_name = 'get_latest' return tuple( getattr(getattr(self.data_channels[i], 'assigned_parameter'), method_name)() for i in range(self._N_DATA_CHANNELS)) def get_data_channels_dict(self, requery_names: bool = False ) -> Dict[str, float]: """ Returns a dictionary where the keys are parameter names currently assigned to the data channels, and values are the values of those parameters. Args: requery_names: if False, the currently assigned parameter names will not be queries from the instrument in order to save time on communication, in this case the cached assigned parameter names will be used for the keys of the dicitonary; if True, the assigned parameter names will be queried from the instrument Returns: a dictionary where keys are names of parameters assigned to the data channels, and values are the values of those parameters """ parameter_names = self.get_data_channels_parameters(requery_names) parameter_values = self.get_data_channels_values() return dict(zip(parameter_names, parameter_values))
def test_bad(): for enum in not_enums: with pytest.raises(TypeError): Enum(*enum)
def __init__(self, name: str, address: str, max_frequency: float, reset: bool = False, **kwargs: Any): super().__init__(name, address, terminator='\n', **kwargs) self._max_frequency = max_frequency # Reference commands self.add_parameter(name='frequency', label='Frequency', unit='Hz', get_cmd='FREQ?', set_cmd='FREQ {}', get_parser=float, vals=Numbers(min_value=1e-3, max_value=self._max_frequency)) self.add_parameter(name='sine_outdc', label='Sine out dc level', unit='V', get_cmd='SOFF?', set_cmd='SOFF {}', get_parser=float, vals=Numbers(min_value=-5, max_value=5)) self.add_parameter(name='amplitude', label='Amplitude', unit='V', get_cmd='SLVL?', set_cmd='SLVL {}', get_parser=float, vals=Numbers(min_value=0, max_value=2)) self.add_parameter(name='harmonic', label='Harmonic', get_cmd='HARM?', get_parser=int, set_cmd='HARM {:d}', vals=Ints(min_value=1, max_value=99)) self.add_parameter(name='phase', label='Phase', unit='deg', get_cmd='PHAS?', set_cmd='PHAS {}', get_parser=float, vals=Numbers(min_value=-3.6e5, max_value=3.6e5)) # Signal commands self.add_parameter(name='sensitivity', label='Sensitivity', get_cmd='SCAL?', set_cmd='SCAL {:d}', get_parser=self._get_sensitivity, set_parser=self._set_sensitivity) self.add_parameter(name='filter_slope', label='Filter slope', unit='dB/oct', get_cmd='OFSL?', set_cmd='OFSL {}', val_mapping={ 6: 0, 12: 1, 18: 2, 24: 3 }) self.add_parameter(name='sync_filter', label='Sync filter', get_cmd='SYNC?', set_cmd='SYNC {}', val_mapping={ 'OFF': 0, 'ON': 1 }) self.add_parameter(name='noise_bandwidth', label='Noise bandwidth', unit='Hz', get_cmd='ENBW?', get_parser=float) self.add_parameter(name='signal_strength', label='Signal strength indicator', get_cmd='ILVL?', get_parser=int) self.add_parameter(name='signal_input', label='Signal input', get_cmd='IVMD?', get_parser=self._get_input_config, set_cmd='IVMD {}', set_parser=self._set_input_config, vals=Enum(*self._INPUT_SIGNAL_TO_N.keys())) self.add_parameter(name='input_range', label='Input range', unit='V', get_cmd='IRNG?', set_cmd='IRNG {}', val_mapping={ 1: 0, 300e-3: 1, 100e-3: 2, 30e-3: 3, 10e-3: 4 }) self.add_parameter(name='input_config', label='Input configuration', get_cmd='ISRC?', set_cmd='ISRC {}', val_mapping={ 'a': 0, 'a-b': 1 }) self.add_parameter(name='input_shield', label='Input shield', get_cmd='IGND?', set_cmd='IGND {}', val_mapping={ 'float': 0, 'ground': 1 }) self.add_parameter(name='input_gain', label='Input gain', unit='ohm', get_cmd='ICUR?', set_cmd='ICUR {}', val_mapping={ 1e6: 0, 100e6: 1 }) self.add_parameter(name='adv_filter', label='Advanced filter', get_cmd='ADVFILT?', set_cmd='ADVFILT {}', val_mapping={ 'OFF': 0, 'ON': 1 }) self.add_parameter(name='input_coupling', label='Input coupling', get_cmd='ICPL?', set_cmd='ICPL {}', val_mapping={ 'ac': 0, 'dc': 1 }) self.add_parameter(name='time_constant', label='Time constant', unit='s', get_cmd='OFLT?', set_cmd='OFLT {}', val_mapping={ 1e-6: 0, 3e-6: 1, 10e-6: 2, 30e-6: 3, 100e-6: 4, 300e-6: 5, 1e-3: 6, 3e-3: 7, 10e-3: 8, 30e-3: 9, 100e-3: 10, 300e-3: 11, 1: 12, 3: 13, 10: 14, 30: 15, 100: 16, 300: 17, 1e3: 18, 3e3: 19, 10e3: 20, 30e3: 21 }) self.add_parameter( name="external_reference_trigger", label="External reference trigger mode", get_cmd="RTRG?", set_cmd="RTRG {}", val_mapping={ "SIN": 0, "POS": 1, "POSTTL": 1, "NEG": 2, "NEGTTL": 2, }, docstring="The triggering mode for synchronization of the " "internal reference signal with the externally provided " "one") self.add_parameter(name="reference_source", label="Reference source", get_cmd="RSRC?", set_cmd="RSRC {}", val_mapping={ "INT": 0, "EXT": 1, "DUAL": 2, "CHOP": 3 }, docstring="The source of the reference signal") self.add_parameter( name="external_reference_trigger_input_resistance", label="External reference trigger input resistance", get_cmd="REFZ?", set_cmd="REFZ {}", val_mapping={ "50": 0, "50OHMS": 0, 0: 0, "1M": 1, "1MEG": 1, 1: 1, }, docstring="Input resistance of the input for the external " "reference signal") # Auto functions self.add_function('auto_range', call_cmd='ARNG') self.add_function('auto_scale', call_cmd='ASCL') self.add_function('auto_phase', call_cmd='APHS') # Data transfer # first 4 parameters from a list of 16 below. self.add_parameter('X', label='In-phase Magnitude', get_cmd='OUTP? 0', get_parser=float, unit='V') self.add_parameter('Y', label='Out-phase Magnitude', get_cmd='OUTP? 1', get_parser=float, unit='V') self.add_parameter('R', label='Magnitude', get_cmd='OUTP? 2', get_parser=float, unit='V') self.add_parameter('P', label='Phase', get_cmd='OUTP? 3', get_parser=float, unit='deg') # CH1/CH2 Output Commands self.add_parameter('X_offset', label='X offset ', unit='%', get_cmd='COFP? 0', set_cmd='COFP 0, {}', get_parser=float, vals=Numbers(min_value=-999.99, max_value=999.99)) self.add_parameter('Y_offset', label='Y offset', unit='%', get_cmd='COFP? 1', set_cmd='COFP 1, {}', get_parser=float, vals=Numbers(min_value=-999.99, max_value=999.99)) self.add_parameter('R_offset', label='R offset', unit='%', get_cmd='COFP? 2', set_cmd='COFP 2, {}', get_parser=float, vals=Numbers(min_value=-999.99, max_value=999.99)) self.add_parameter('X_expand', label='X expand multiplier', get_cmd='CEXP? 0', set_cmd='CEXP 0, {}', val_mapping={ 'OFF': '0', 'X10': '1', 'X100': '2' }) self.add_parameter('Y_expand', label='Y expand multiplier', get_cmd='CEXP? 1', set_cmd='CEXP 1, {}', val_mapping={ 'OFF': 0, 'X10': 1, 'X100': 2 }) self.add_parameter('R_expand', label='R expand multiplier', get_cmd='CEXP? 2', set_cmd='CEXP 2, {}', val_mapping={ 'OFF': 0, 'X10': 1, 'X100': 2 }) # Aux input/output for i in [0, 1, 2, 3]: self.add_parameter(f'aux_in{i}', label=f'Aux input {i}', get_cmd=f'OAUX? {i}', get_parser=float, unit='V') self.add_parameter(f'aux_out{i}', label=f'Aux output {i}', get_cmd=f'AUXV? {i}', get_parser=float, set_cmd=f'AUXV {i}, {{}}', unit='V') # Data channels: # 'DAT1' (green), 'DAT2' (blue), 'DAT3' (yellow), 'DAT4' (orange) data_channels = ChannelList(self, "data_channels", SR86xDataChannel, snapshotable=False) for num, color in zip(range(self._N_DATA_CHANNELS), ('green', 'blue', 'yellow', 'orange')): cmd_id = f"{num}" cmd_id_name = f"DAT{num + 1}" ch_name = f"data_channel_{num + 1}" data_channel = SR86xDataChannel(self, ch_name, cmd_id, cmd_id_name, color) data_channels.append(data_channel) self.add_submodule(ch_name, data_channel) data_channels.lock() self.add_submodule("data_channels", data_channels) # Interface self.add_function('reset', call_cmd='*RST') self.add_function('disable_front_panel', call_cmd='OVRM 0') self.add_function('enable_front_panel', call_cmd='OVRM 1') buffer = SR86xBuffer(self, f"{self.name}_buffer") self.add_submodule("buffer", buffer) self.input_config() self.connect_message()
def test_valid_values(): for enum in enums: e = Enum(*enum) for val in e._valid_values: e.validate(val)
def __init__( self, name: str, address: str, # Set frequency ranges min_freq: Union[int, float], max_freq: Union[int, float], # Set power ranges min_power: Union[int, float], max_power: Union[int, float], nports: int, # Number of ports on the PNA **kwargs: Any) -> None: super().__init__(name, address, terminator='\n', **kwargs) self.min_freq = min_freq self.max_freq = max_freq #Ports ports = ChannelList(self, "PNAPorts", PNAPort) for port_num in range(1, nports + 1): port = PNAPort(self, f"port{port_num}", port_num, min_power, max_power) ports.append(port) self.add_submodule(f"port{port_num}", port) ports.lock() self.add_submodule("ports", ports) # Drive power self.add_parameter('power', label='Power', get_cmd='SOUR:POW?', get_parser=float, set_cmd='SOUR:POW {:.2f}', unit='dBm', vals=Numbers(min_value=min_power, max_value=max_power)) # IF bandwidth self.add_parameter('if_bandwidth', label='IF Bandwidth', get_cmd='SENS:BAND?', get_parser=float, set_cmd='SENS:BAND {:.2f}', unit='Hz', vals=Numbers(min_value=1, max_value=15e6)) # Number of averages (also resets averages) self.add_parameter('averages_enabled', label='Averages Enabled', get_cmd="SENS:AVER?", set_cmd="SENS:AVER {}", val_mapping={ True: '1', False: '0' }) self.add_parameter('averages', label='Averages', get_cmd='SENS:AVER:COUN?', get_parser=int, set_cmd='SENS:AVER:COUN {:d}', unit='', vals=Numbers(min_value=1, max_value=65536)) # Setting frequency range self.add_parameter('start', label='Start Frequency', get_cmd='SENS:FREQ:STAR?', get_parser=float, set_cmd='SENS:FREQ:STAR {}', unit='Hz', vals=Numbers(min_value=min_freq, max_value=max_freq)) self.add_parameter('stop', label='Stop Frequency', get_cmd='SENS:FREQ:STOP?', get_parser=float, set_cmd='SENS:FREQ:STOP {}', unit='Hz', vals=Numbers(min_value=min_freq, max_value=max_freq)) self.add_parameter('center', label='Center Frequency', get_cmd='SENS:FREQ:CENT?', get_parser=float, set_cmd='SENS:FREQ:CENT {}', unit='Hz', vals=Numbers(min_value=min_freq, max_value=max_freq)) self.add_parameter('span', label='Frequency Span', get_cmd='SENS:FREQ:SPAN?', get_parser=float, set_cmd='SENS:FREQ:SPAN {}', unit='Hz', vals=Numbers(min_value=min_freq, max_value=max_freq)) # Number of points in a sweep self.add_parameter('points', label='Points', get_cmd='SENS:SWE:POIN?', get_parser=int, set_cmd='SENS:SWE:POIN {}', unit='', vals=Numbers(min_value=1, max_value=100001)) # Electrical delay self.add_parameter('electrical_delay', label='Electrical Delay', get_cmd='CALC:CORR:EDEL:TIME?', get_parser=float, set_cmd='CALC:CORR:EDEL:TIME {:.6e}', unit='s', vals=Numbers(min_value=0, max_value=100000)) # Sweep Time self.add_parameter('sweep_time', label='Time', get_cmd='SENS:SWE:TIME?', get_parser=float, unit='s', vals=Numbers(0, 1e6)) # Sweep Mode self.add_parameter('sweep_mode', label='Mode', get_cmd='SENS:SWE:MODE?', set_cmd='SENS:SWE:MODE {}', vals=Enum("HOLD", "CONT", "GRO", "SING")) # Group trigger count self.add_parameter('group_trigger_count', get_cmd="SENS:SWE:GRO:COUN?", get_parser=int, set_cmd="SENS:SWE:GRO:COUN {}", vals=Ints(1, 2000000)) # Trigger Source self.add_parameter('trigger_source', get_cmd="TRIG:SOUR?", set_cmd="TRIG:SOUR {}", vals=Enum("EXT", "IMM", "MAN")) # Traces self.add_parameter('active_trace', label='Active Trace', get_cmd="CALC:PAR:MNUM?", get_parser=int, set_cmd="CALC:PAR:MNUM {}", vals=Numbers(min_value=1, max_value=24)) # Note: Traces will be accessed through the traces property which # updates the channellist to include only active trace numbers self._traces = ChannelList(self, "PNATraces", PNATrace) self.add_submodule("traces", self._traces) # Add shortcuts to first trace trace1 = self.traces[0] params = trace1.parameters if not isinstance(params, dict): raise RuntimeError(f"Expected trace.parameters to be a dict got " f"{type(params)}") for param in params.values(): self.parameters[param.name] = param # And also add a link to run sweep self.run_sweep = trace1.run_sweep # Set this trace to be the default (it's possible to end up in a # situation where no traces are selected, causing parameter snapshots # to fail) self.active_trace(trace1.trace_num) # Set auto_sweep parameter # If we want to return multiple traces per setpoint without sweeping # multiple times, we should set this to false self.add_parameter('auto_sweep', label='Auto Sweep', set_cmd=None, get_cmd=None, vals=Bool(), initial_value=True) # A default output format on initialisation self.write('FORM REAL,32') self.write('FORM:BORD NORM') self.connect_message()
def __init__(self, name, address=None, port=None, axes=None, **kwargs): super().__init__(name, address=address, port=port, terminator='\n', **kwargs) self.axes = axes self._ATOB = [] self._latest_response = '' # for some reason the first call is always invalid?! # need some kind of init? self.ask('*IDN?') if axes is None: self._determine_magnet_axes() self._determine_current_to_field() self.add_parameter( 'setpoint', names=['B' + ax.lower() + '_setpoint' for ax in self.axes], get_cmd=partial(self._get_fld, self.axes, 'FSET'), set_cmd=partial(self._ramp_to_setpoint, self.axes, 'FSET'), units=['T' for ax in self.axes], vals=Anything()) self.add_parameter('rate', names=['rate_B' + ax.lower() for ax in self.axes], get_cmd=partial(self._get_fld, self.axes, 'RFST'), set_cmd=partial(self._ramp_to_setpoint, self.axes, 'RFST'), units=['T/m' for ax in self.axes], vals=Anything()) self.add_parameter('fld', names=['B' + ax.lower() for ax in self.axes], get_cmd=partial(self._get_fld, self.axes, 'FLD'), set_cmd=partial(self._ramp_to_setpoint, self.axes, 'FSET'), units=['T' for ax in self.axes], vals=Anything()) self.add_parameter('fldC', names=['B' + ax.lower() for ax in self.axes], get_cmd=partial(self._get_fld, self.axes, 'CURR'), set_cmd=partial(self._ramp_to_setpoint, self.axes, 'CSET'), units=['T' for ax in self.axes], vals=Anything()) self.add_parameter('rtp', names=['radius', 'theta', 'phi'], get_cmd=partial(self._get_rtp, self.axes, 'FLD'), set_cmd=partial(self._set_rtp, self.axes, 'FSET'), units=['|B|', 'rad', 'rad'], vals=Anything()) self.add_parameter('rtpC', names=['radius', 'theta', 'phi'], get_cmd=partial(self._get_rtp, self.axes, 'CURR'), set_cmd=partial(self._set_rtp, self.axes, 'CSET'), units=['|B|', 'rad', 'rad'], vals=Anything()) # so we have radius, theta and phi in buffer self.rtp.get() self.add_parameter('radius', get_cmd=self._get_r, set_cmd=self._set_r, units='|B|') self.add_parameter('theta', get_cmd=self._get_theta, set_cmd=self._set_theta, units='rad') self.add_parameter('phi', get_cmd=self._get_phi, set_cmd=self._set_phi, units='rad') for ax in self.axes: self.add_parameter(ax.lower() + '_fld', get_cmd=partial(self._get_fld, ax, 'FLD'), set_cmd=partial(self._ramp_to_setpoint, ax, 'FSET'), label='B' + ax.lower(), units='T') self.add_parameter(ax.lower() + '_fldC', get_cmd=partial(self._get_fld, ax, 'CURR'), set_cmd=partial(self._ramp_to_setpoint, ax, 'CSET'), label='B' + ax.lower(), units='T') self.add_parameter(ax.lower() + '_fld_wait', get_cmd=partial(self._get_fld, ax, 'CURR'), set_cmd=partial(self._ramp_to_setpoint_and_wait, ax, 'CSET'), label='B' + ax.lower(), units='T') self.add_parameter(ax.lower() + '_ACTN', get_cmd=partial( self._get_cmd, 'READ:DEV:GRP' + ax + ':PSU:ACTN?'), set_cmd='SET:DEV:GRP' + ax + ':PSU:ACTN:{}', vals=Enum('HOLD', 'RTOS', 'RTOZ', 'CLMP')) self.add_parameter(ax.lower() + '_setpoint', get_cmd=partial(self._get_fld, ax, 'FSET'), set_cmd=partial(self._set_fld, ax, 'FSET'), units='T') self.add_parameter(ax.lower() + '_setpointC', get_cmd=partial(self._get_fld, ax, 'CSET'), set_cmd=partial(self._set_fld, ax, 'CSET'), units='T') self.add_parameter(ax.lower() + '_rate', get_cmd=partial(self._get_fld, ax, 'RFST'), set_cmd=partial(self._set_fld, ax, 'RFST'), units='T/m') self.add_parameter(ax.lower() + '_rateC', get_cmd=partial(self._get_fld, ax, 'RCST'), set_cmd=partial(self._set_fld, ax, 'RCST'), units='T/m') self.connect_message()
def __init__(self, parent: Union[Instrument, InstrumentChannel], name: str) -> None: super().__init__(parent, name) self.add_parameter("mode", get_cmd="HORizontal:MODE?", set_cmd="HORizontal:MODE {}", vals=Enum("auto", "constant", "manual"), get_parser=str.lower, docstring=""" Auto mode attempts to keep record length constant as you change the time per division setting. Record length is read only. Constant mode attempts to keep sample rate constant as you change the time per division setting. Record length is read only. Manual mode lets you change sample mode and record length. Time per division or Horizontal scale is read only. """) self.add_parameter("unit", get_cmd="HORizontal:MAIn:UNIts?", get_parser=strip_quotes) self.add_parameter("record_length", get_cmd="HORizontal:MODE:RECOrdlength?", set_cmd=self._set_record_length, get_parser=float) self.add_parameter("sample_rate", get_cmd="HORizontal:MODE:SAMPLERate?", set_cmd="HORizontal:MODE:SAMPLERate {}", get_parser=float, unit=f"sample/{self.unit()}") self.add_parameter("scale", get_cmd="HORizontal:MODE:SCAle?", set_cmd=self._set_scale, get_parser=float, unit=f"{self.unit()}/div") self.add_parameter("position", get_cmd="HORizontal:POSition?", set_cmd="HORizontal:POSition {}", get_parser=float, unit="%", docstring=textwrap.dedent(""" The horizontal position relative to a received trigger. E.g. a value of '10' sets the trigger position of the waveform such that 10% of the display is to the left of the trigger position. """)) self.add_parameter("roll", get_cmd="HORizontal:ROLL?", set_cmd="HORizontal:ROLL {}", vals=Enum("Auto", "On", "Off"), docstring=textwrap.dedent(""" Use Roll Mode when you want to view data at very slow sweep speeds. """))
def __init__(self, name: str, address: str, **kwargs) -> None: super().__init__(name, address, terminator='\n', **kwargs) if not self._has_correct_language_mode(): self.log.warning( f"The instrument is in an unsupported language mode. " f"Please run `instrument.set_correct_language()` and try to " f"initialize the driver again after an instrument power cycle. " f"No parameters/sub modules will be available on this driver " f"instance" ) return self.add_parameter( "source_function", set_cmd=self._set_source_function, get_cmd=":SOUR:FUNC?", val_mapping={ key: value["name"] for key, value in Source2450.function_modes.items() } ) self.add_parameter( "sense_function", set_cmd=self._set_sense_function, get_cmd=":SENS:FUNC?", val_mapping={ key: value["name"] for key, value in Sense2450.function_modes.items() } ) self.add_parameter( "terminals", set_cmd="ROUTe:TERMinals {}", get_cmd="ROUTe:TERMinals?", vals=Enum("rear", "front") ) self.add_parameter( "output_enabled", initial_value="0", set_cmd=":OUTP {}", get_cmd=":OUTP?", val_mapping=create_on_off_val_mapping(on_val="1", off_val="0") ) # Make a source module for every source function ('current' and 'voltage') for proper_source_function in Source2450.function_modes: self.add_submodule( f"_source_{proper_source_function}", Source2450(self, "source", proper_source_function) ) # Make a sense module for every sense function ('current', voltage' and 'resistance') for proper_sense_function in Sense2450.function_modes: self.add_submodule( f"_sense_{proper_sense_function}", Sense2450(self, "sense", proper_sense_function) ) self.connect_message()
class SR830(VisaInstrument): """ This is the qcodes driver for the Stanford Research Systems SR830 Lock-in Amplifier """ _VOLT_TO_N = {2e-9: 0, 5e-9: 1, 10e-9: 2, 20e-9: 3, 50e-9: 4, 100e-9: 5, 200e-9: 6, 500e-9: 7, 1e-6: 8, 2e-6: 9, 5e-6: 10, 10e-6: 11, 20e-6: 12, 50e-6: 13, 100e-6: 14, 200e-6: 15, 500e-6: 16, 1e-3: 17, 2e-3: 18, 5e-3: 19, 10e-3: 20, 20e-3: 21, 50e-3: 22, 100e-3: 23, 200e-3: 24, 500e-3: 25, 1: 26} _N_TO_VOLT = {v: k for k, v in _VOLT_TO_N.items()} _CURR_TO_N = {2e-15: 0, 5e-15: 1, 10e-15: 2, 20e-15: 3, 50e-15: 4, 100e-15: 5, 200e-15: 6, 500e-15: 7, 1e-12: 8, 2e-12: 9, 5e-12: 10, 10e-12: 11, 20e-12: 12, 50e-12: 13, 100e-12: 14, 200e-12: 15, 500e-12: 16, 1e-9: 17, 2e-9: 18, 5e-9: 19, 10e-9: 20, 20e-9: 21, 50e-9: 22, 100e-9: 23, 200e-9: 24, 500e-9: 25, 1e-6: 26} _N_TO_CURR = {v: k for k, v in _CURR_TO_N.items()} _VOLT_ENUM = Enum(*_VOLT_TO_N.keys()) _CURR_ENUM = Enum(*_CURR_TO_N.keys()) _INPUT_CONFIG_TO_N = { 'a': 0, 'a-b': 1, 'I 1M': 2, 'I 100M': 3, } _N_TO_INPUT_CONFIG = {v: k for k, v in _INPUT_CONFIG_TO_N.items()} def __init__(self, name, address, **kwargs): super().__init__(name, address, **kwargs) # Reference and phase self.add_parameter('phase', label='Phase', get_cmd='PHAS?', get_parser=float, set_cmd='PHAS {:.2f}', unit='deg', vals=Numbers(min_value=-360, max_value=729.99)) self.add_parameter('reference_source', label='Reference source', get_cmd='FMOD?', set_cmd='FMOD {}', val_mapping={ 'external': 0, 'internal': 1, }, vals=Enum('external', 'internal')) self.add_parameter('frequency', label='Frequency', get_cmd='FREQ?', get_parser=float, set_cmd='FREQ {:.4f}', unit='Hz', vals=Numbers(min_value=1e-3, max_value=102e3)) self.add_parameter('ext_trigger', label='External trigger', get_cmd='RSLP?', set_cmd='RSLP {}', val_mapping={ 'sine': 0, 'TTL rising': 1, 'TTL falling': 2, }) self.add_parameter('harmonic', label='Harmonic', get_cmd='HARM?', get_parser=int, set_cmd='HARM {:d}', vals=Ints(min_value=1, max_value=19999)) self.add_parameter('amplitude', label='Amplitude', get_cmd='SLVL?', get_parser=float, set_cmd='SLVL {:.3f}', unit='V', vals=Numbers(min_value=0.004, max_value=5.000)) # Input and filter self.add_parameter('input_config', label='Input configuration', get_cmd='ISRC?', get_parser=self._get_input_config, set_cmd='ISRC {}', set_parser=self._set_input_config, vals=Enum(*self._INPUT_CONFIG_TO_N.keys())) self.add_parameter('input_shield', label='Input shield', get_cmd='IGND?', set_cmd='IGND {}', val_mapping={ 'float': 0, 'ground': 1, }) self.add_parameter('input_coupling', label='Input coupling', get_cmd='ICPL?', set_cmd='ICPL {}', val_mapping={ 'AC': 0, 'DC': 1, }) self.add_parameter('notch_filter', label='Notch filter', get_cmd='ILIN?', set_cmd='ILIN {}', val_mapping={ 'off': 0, 'line in': 1, '2x line in': 2, 'both': 3, }) # Gain and time constant self.add_parameter(name='sensitivity', label='Sensitivity', get_cmd='SENS?', set_cmd='SENS {:d}', get_parser=self._get_sensitivity, set_parser=self._set_sensitivity ) self.add_parameter('reserve', label='Reserve', get_cmd='RMOD?', set_cmd='RMOD {}', val_mapping={ 'high': 0, 'normal': 1, 'low noise': 2, }) self.add_parameter('time_constant', label='Time constant', get_cmd='OFLT?', set_cmd='OFLT {}', unit='s', val_mapping={ 10e-6: 0, 30e-6: 1, 100e-6: 2, 300e-6: 3, 1e-3: 4, 3e-3: 5, 10e-3: 6, 30e-3: 7, 100e-3: 8, 300e-3: 9, 1: 10, 3: 11, 10: 12, 30: 13, 100: 14, 300: 15, 1e3: 16, 3e3: 17, 10e3: 18, 30e3: 19, }) self.add_parameter('filter_slope', label='Filter slope', get_cmd='OFSL?', set_cmd='OFSL {}', unit='dB/oct', val_mapping={ 6: 0, 12: 1, 18: 2, 24: 3, }) self.add_parameter('sync_filter', label='Sync filter', get_cmd='SYNC?', set_cmd='SYNC {}', val_mapping={ 'off': 0, 'on': 1, }) def parse_offset_get(s): parts = s.split(',') return float(parts[0]), int(parts[1]) # TODO: Parameters that can be set with multiple arguments # For the OEXP command for example two arguments are needed self.add_parameter('X_offset', get_cmd='OEXP? 1', get_parser=parse_offset_get) self.add_parameter('Y_offset', get_cmd='OEXP? 2', get_parser=parse_offset_get) self.add_parameter('R_offset', get_cmd='OEXP? 3', get_parser=parse_offset_get) # Aux input/output for i in [1, 2, 3, 4]: self.add_parameter('aux_in{}'.format(i), label='Aux input {}'.format(i), get_cmd='OAUX? {}'.format(i), get_parser=float, unit='V') self.add_parameter('aux_out{}'.format(i), label='Aux output {}'.format(i), get_cmd='AUXV? {}'.format(i), get_parser=float, set_cmd='AUXV {0}, {{}}'.format(i), unit='V') # Setup self.add_parameter('output_interface', label='Output interface', get_cmd='OUTX?', set_cmd='OUTX {}', val_mapping={ 'RS232': '0\n', 'GPIB': '1\n', }) # Channel setup for ch in range(1, 3): # detailed validation and mapping performed in set/get functions self.add_parameter('ch{}_ratio'.format(ch), label='Channel {} ratio'.format(ch), get_cmd=partial(self._get_ch_ratio, ch), set_cmd=partial(self._set_ch_ratio, ch), vals=Strings()) self.add_parameter('ch{}_display'.format(ch), label='Channel {} display'.format(ch), get_cmd=partial(self._get_ch_display, ch), set_cmd=partial(self._set_ch_display, ch), vals=Strings()) self.add_parameter('ch{}_databuffer'.format(ch), channel=ch, parameter_class=ChannelBuffer) # Data transfer self.add_parameter('X', get_cmd='OUTP? 1', get_parser=float, unit='V') self.add_parameter('Y', get_cmd='OUTP? 2', get_parser=float, unit='V') self.add_parameter('R', get_cmd='OUTP? 3', get_parser=float, unit='V') self.add_parameter('P', get_cmd='OUTP? 4', get_parser=float, unit='deg') # Data buffer settings self.add_parameter('buffer_SR', label='Buffer sample rate', get_cmd='SRAT ?', set_cmd=self._set_buffer_SR, unit='Hz', val_mapping={62.5e-3: 0, 0.125: 1, 0.250: 2, 0.5: 3, 1: 4, 2: 5, 4: 6, 8: 7, 16: 8, 32: 9, 64: 10, 128: 11, 256: 12, 512: 13, 'Trigger': 14}, get_parser=int ) self.add_parameter('buffer_acq_mode', label='Buffer acquistion mode', get_cmd='SEND ?', set_cmd='SEND {}', val_mapping={'single shot': 0, 'loop': 1}, get_parser=int) self.add_parameter('buffer_trig_mode', label='Buffer trigger start mode', get_cmd='TSTR ?', set_cmd='TSTR {}', val_mapping={'ON': 1, 'OFF': 0}, get_parser=int) self.add_parameter('buffer_npts', label='Buffer number of stored points', get_cmd='SPTS ?', get_parser=int) # Auto functions self.add_function('auto_gain', call_cmd='AGAN') self.add_function('auto_reserve', call_cmd='ARSV') self.add_function('auto_phase', call_cmd='APHS') self.add_function('auto_offset', call_cmd='AOFF {0}', args=[Enum(1, 2, 3)]) # Interface self.add_function('reset', call_cmd='*RST') self.add_function('disable_front_panel', call_cmd='OVRM 0') self.add_function('enable_front_panel', call_cmd='OVRM 1') self.add_function('send_trigger', call_cmd='TRIG', docstring=("Send a software trigger. " "This command has the same effect as a " "trigger at the rear panel trigger" " input.")) self.add_function('buffer_start', call_cmd='STRT', docstring=("The buffer_start command starts or " "resumes data storage. buffer_start" " is ignored if storage is already in" " progress.")) self.add_function('buffer_pause', call_cmd='PAUS', docstring=("The buffer_pause command pauses data " "storage. If storage is already paused " "or reset then this command is ignored.")) self.add_function('buffer_reset', call_cmd='REST', docstring=("The buffer_reset command resets the data" " buffers. The buffer_reset command can " "be sent at any time - any storage in " "progress, paused or not, will be reset." " This command will erase the data " "buffer.")) # Initialize the proper units of the outputs and sensitivities self.input_config() # start keeping track of buffer setpoints self._buffer1_ready = False self._buffer2_ready = False self.connect_message() def _set_buffer_SR(self, SR): self.write('SRAT {}'.format(SR)) self._buffer1_ready = False self._buffer2_ready = False def _get_ch_ratio(self, channel): val_mapping = {1: {0: 'none', 1: 'Aux In 1', 2: 'Aux In 2'}, 2: {0: 'none', 1: 'Aux In 3', 2: 'Aux In 4'}} resp = int(self.ask('DDEF ? {}'.format(channel)).split(',')[1]) return val_mapping[channel][resp] def _set_ch_ratio(self, channel, ratio): val_mapping = {1: {'none': 0, 'Aux In 1': 1, 'Aux In 2': 2}, 2: {'none': 0, 'Aux In 3': 1, 'Aux In 4': 2}} vals = val_mapping[channel].keys() if ratio not in vals: raise ValueError('{} not in {}'.format(ratio, vals)) ratio = val_mapping[channel][ratio] disp_val = int(self.ask('DDEF ? {}'.format(channel)).split(',')[0]) self.write('DDEF {}, {}, {}'.format(channel, disp_val, ratio)) self._buffer_ready = False def _get_ch_display(self, channel): val_mapping = {1: {0: 'X', 1: 'R', 2: 'X Noise', 3: 'Aux In 1', 4: 'Aux In 2'}, 2: {0: 'Y', 1: 'Phase', 2: 'Y Noise', 3: 'Aux In 3', 4: 'Aux In 4'}} resp = int(self.ask('DDEF ? {}'.format(channel)).split(',')[0]) return val_mapping[channel][resp] def _set_ch_display(self, channel, disp): val_mapping = {1: {'X': 0, 'R': 1, 'X Noise': 2, 'Aux In 1': 3, 'Aux In 2': 4}, 2: {'Y': 0, 'Phase': 1, 'Y Noise': 2, 'Aux In 3': 3, 'Aux In 4': 4}} vals = val_mapping[channel].keys() if disp not in vals: raise ValueError('{} not in {}'.format(disp, vals)) disp = val_mapping[channel][disp] # Since ratio AND display are set simultaneously, # we get and then re-set the current ratio value ratio_val = int(self.ask('DDEF ? {}'.format(channel)).split(',')[1]) self.write('DDEF {}, {}, {}'.format(channel, disp, ratio_val)) self._buffer_ready = False def _set_units(self, unit): # TODO: # make a public parameter function that allows to change the units for param in [self.X, self.Y, self.R, self.sensitivity]: param.unit = unit def _get_input_config(self, s): mode = self._N_TO_INPUT_CONFIG[int(s)] if mode in ['a', 'a-b']: self.sensitivity.set_validator(self._VOLT_ENUM) self._set_units('V') else: self.sensitivity.set_validator(self._CURR_ENUM) self._set_units('A') return mode def _set_input_config(self, s): if s in ['a', 'a-b']: self.sensitivity.set_validator(self._VOLT_ENUM) self._set_units('V') else: self.sensitivity.set_validator(self._CURR_ENUM) self._set_units('A') return self._INPUT_CONFIG_TO_N[s] def _get_sensitivity(self, s): if self.input_config() in ['a', 'a-b']: return self._N_TO_VOLT[int(s)] else: return self._N_TO_CURR[int(s)] def _set_sensitivity(self, s): if self.input_config() in ['a', 'a-b']: return self._VOLT_TO_N[s] else: return self._CURR_TO_N[s]
def __init__(self, name, address=None, **kwargs): super().__init__(name, **kwargs) self.add_parameter(name='frequency', label='Frequency', unit='Hz', get_cmd=None, set_cmd=None, get_parser=float, set_parser=float, vals=Numbers(min_value=1e-6, max_value=80e6), docstring=('Command for setting the pulse frequency. Min value: 1 uHz, Max value: 80 MHz')) self.add_parameter(name='pulse_shape', label='Pulse shape', get_cmd=None, set_cmd=None, vals=Enum('SIN','SQU'), docstring=('Command for setting the desired pulse shape. Currently supported: SIN, SQU.')) self.add_parameter(name='pulse_width', label='Pulse width', get_cmd=None, set_cmd=None, get_parser=float, set_parser=float, unit='s', vals=Numbers(min_value=8e-9, max_value=2e3), docstring=('Command for setting the desired pulse width. Min value: 8 ns, Max value: 2000 s.')) self.add_parameter('pulse_period', label='Pulse period', get_cmd=None, set_cmd=None, get_parser=float, set_parser=float, unit='s', vals=Numbers(min_value=20e-9, max_value=2e3), docstring=('Command for setting the desired pulse period. Min value: 20 ns, Max value: 2000 s.')) self.add_parameter(name='amplitude', label='Amplitude', unit='Vpp', get_cmd=None, set_cmd=None, get_parser=float, set_parser=float, vals=Numbers(min_value=1e-3, max_value=20), docstring=('Command for setting the desired pulse amplitude. Min value for 50 Ohm load: 1 mVpp, Max value for 50 Ohm load: 10 Vpp. Min value for high impedance load: 2 mVpp, Max value for high impedance load: 20 Vpp.')) self.add_parameter('offset', label='Offset', unit='V', get_cmd=None, set_cmd=None, get_parser=float, set_parser=float, vals=Numbers(min_value=-10, max_value=10), docstring=('Command for setting the desired dc offset. Min value for 50 Ohm load: -10 V, Max value for 50 Ohm load: 10 V. Min value for high impedance load: -10 V, Max value for high impedance load: 10 Vpp.')) self.add_parameter(name='output', get_cmd=None, set_cmd=None, val_mapping={'OFF': 0, 'ON': 1}, docstring=('Command for switching on/off the device output.')) self.add_parameter(name='output_sync', get_cmd=None, set_cmd=None, val_mapping={'OFF': 0, 'ON': 1}, docstring='Command for switching on/off the device output synchronization.') self.add_parameter(name='load_impedance', label='Load impedance', unit='Ohm', get_cmd=None, set_cmd=None, get_parser=float, set_parser=float, vals=MultiType(Numbers(min_value=1, max_value=10e3), Enum('INF')), docstring=("Command for setting the load impedance in Ohms. Min value: 1 Ohm, Max value: 10 kOhm or 'INF'")) self.connect_message()
def __init__(self, name: str, address: str, **kwargs: Any) -> None: super().__init__(name, address, terminator='\n', **kwargs) idn = self.IDN.get() self.model = idn['model'] NPLC_list = { '34401A': [0.02, 0.2, 1, 10, 100], '34410A': [0.006, 0.02, 0.06, 0.2, 1, 2, 10, 100], '34411A': [0.001, 0.002, 0.006, 0.02, 0.06, 0.2, 1, 2, 10, 100] }[self.model] self._resolution_factor = { '34401A': [1e-4, 1e-5, 3e-6, 1e-6, 3e-7], '34410A': [6e-06, 3e-06, 1.5e-06, 7e-07, 3e-07, 2e-07, 1e-07], '34411A': [ 3e-05, 1.5e-05, 6e-06, 3e-06, 1.5e-06, 7e-07, 3e-07, 2e-07, 1e-07, 3e-08 ] }[self.model] self.add_parameter('resolution', get_cmd='VOLT:DC:RES?', get_parser=float, set_cmd=self._set_resolution, label='Resolution', unit='V') self.add_parameter('volt', get_cmd='READ?', label='Voltage', get_parser=float, unit='V') self.add_parameter('fetch', get_cmd='FETCH?', label='Voltage', get_parser=float, unit='V', snapshot_get=False, docstring=('Reads the data you asked for, i.e. ' 'after an `init_measurement()` you can ' 'read the data with fetch.\n' 'Do not call this when you did not ask ' 'for data in the first place!')) self.add_parameter('NPLC', get_cmd='VOLT:NPLC?', get_parser=float, set_cmd=self._set_nplc, vals=Enum(*NPLC_list), label='Integration time', unit='NPLC') self.add_parameter('terminals', get_cmd='ROUT:TERM?') self.add_parameter('range_auto', get_cmd='VOLT:RANG:AUTO?', set_cmd='VOLT:RANG:AUTO {:d}', val_mapping={ 'on': 1, 'off': 0 }) self.add_parameter('range', get_cmd='SENS:VOLT:DC:RANG?', get_parser=float, set_cmd='SENS:VOLT:DC:RANG {:f}', vals=Enum(0.1, 1.0, 10.0, 100.0, 1000.0)) if self.model in ['34401A']: self.add_parameter('display_text', get_cmd='DISP:TEXT?', set_cmd='DISP:TEXT "{}"', vals=Strings()) elif self.model in ['34410A', '34411A']: self.add_parameter('display_text', get_cmd='DISP:WIND1:TEXT?', set_cmd='DISP:WIND1:TEXT "{}"', vals=Strings()) self.add_parameter('display_text_2', get_cmd='DISP:WIND2:TEXT?', set_cmd='DISP:WIND2:TEXT "{}"', vals=Strings()) self.connect_message()
def __init__(self, name: str, address: Optional[str] = None, port: Optional[int] = None, terminator: str = '\r\n', tmpfile: Optional[str] = None, timeout: float = 20, pid=None, condense_tlim=1.2, tlim_safety=True, **kwargs: Any): super().__init__(name, address=address, port=port, terminator=terminator, timeout=timeout, **kwargs) self._heater_range_auto = False self._heater_range_temp = [0.0, 0.015, 0.025, 0.07, 0.2, 1.5, 40., 300] self._heater_range_curr = [0.0, 0.316, 1, 3.16, 10., 31.6, 100., 100.] self._heaterdict = dict( zip(self._heater_range_temp, self._heater_range_curr)) #self._control_channel = 5 self.add_parameter(name='turbo_status', label='turbo_status', get_cmd=partial(self._get_turbo_status), set_cmd=partial(self._set_turbo_status), val_mapping={ 'on': 'ON', 'off': 'OFF' }) self.add_parameter(name='turbo_speed', label='turbo_speed', unit='Hz', get_cmd=partial(self._get_turbo_speed)) self.add_parameter(name='autotemperature', label='autotemperature', unit='K', get_cmd=partial(self._get_autotempcontrol), set_cmd=partial(self._set_autotempcontrol)) self.add_parameter(name='time', label='System Time', get_cmd='READ:SYS:TIME', get_parser=self._parse_time) self.add_parameter(name='action', label='Current action', get_cmd='READ:SYS:DR:ACTN', get_parser=self._parse_action) self.add_parameter(name='status', label='Status', get_cmd='READ:SYS:DR:STATUS', get_parser=self._parse_status) self.add_parameter(name='pid_control_channel', label='PID control channel', get_cmd=self._get_control_channel, set_cmd=self._set_control_channel, vals=Ints(1, 16)) self.add_parameter(name='pid_mode', label='PID Mode', get_cmd=partial(self._get_control_param, 'MODE'), set_cmd=partial(self._set_control_param, 'MODE'), val_mapping={ 'on': 'ON', 'off': 'OFF' }) self.add_parameter(name='pid_ramp', label='PID ramp enabled', get_cmd=partial(self._get_control_param, 'RAMP:ENAB'), set_cmd=partial(self._set_control_param, 'RAMP:ENAB'), val_mapping={ 'on': 'ON', 'off': 'OFF' }) self.add_parameter(name='pid_setpoint', label='PID temperature setpoint', unit='K', get_cmd=partial(self._get_control_param, 'TSET'), set_cmd=partial(self._set_control_param, 'TSET'), snapshot_exclude=True) self.add_parameter(name='pid_rate', label='PID ramp rate', unit='K/min', get_cmd=partial(self._get_control_param, 'RAMP:RATE'), set_cmd=partial(self._set_control_param, 'RAMP:RATE'), snapshot_exclude=True) self.add_parameter( name='pid_range', label='PID heater range', # TODO: The units in the software are mA, how to # do this correctly? unit='mA', get_cmd=partial(self._get_control_param, 'RANGE'), set_cmd=partial(self._set_control_param, 'RANGE'), vals=Enum(*self._heater_range_curr), snapshot_exclude=True) self.add_parameter(name='magnet_status', label='Magnet status', unit='', get_cmd=partial(self._get_control_B_param, 'ACTN')) self.add_parameter( name='magnet_sweeprate', label='Magnet sweep rate', unit='T/min', get_cmd=partial(self._get_control_B_param, 'RVST:RATE'), set_cmd=partial(self._set_control_magnet_sweeprate_param)) self.add_parameter(name='magnet_sweeprate_insta', label='Instantaneous magnet sweep rate', unit='T/min', get_cmd=partial(self._get_control_B_param, 'RFST')) self.add_parameter(name='B', label='Magnetic field', unit='T', get_cmd=partial(self._get_control_B_param, 'VECT')) self.add_parameter(name='Bx', label='Magnetic field x-component', unit='T', get_cmd=partial(self._get_control_Bcomp_param, 'VECTBx'), set_cmd=partial(self._set_control_Bx_param)) self.add_parameter(name='By', label='Magnetic field y-component', unit='T', get_cmd=partial(self._get_control_Bcomp_param, 'VECTBy'), set_cmd=partial(self._set_control_By_param)) self.add_parameter(name='Bz', label='Magnetic field z-component', unit='T', get_cmd=partial(self._get_control_Bcomp_param, 'VECTBz'), set_cmd=partial(self._set_control_Bz_param)) self.add_parameter(name='magnet_sweep_time', label='Magnet sweep time', unit='T/min', get_cmd=partial(self._get_control_B_param, 'RVST:TIME')) self.chan_alias: Dict[str, str] = {} self.chan_temp_names: Dict[str, Dict[str, Optional[str]]] = {} if tmpfile is not None: self._get_temp_channel_names(tmpfile) self._get_temp_channels() self._get_pressure_channels() self._get_valve_channels() self._control_channel = None self._control_channel = self._get_control_channel() self._get_pid_channels() if pid is not None: self.pid_P.set(pid[0]) self.pid_I.set(pid[1]) self.pid_D.set(pid[2]) try: self._get_named_channels() except: logging.warning('Ignored an error in _get_named_channels\n' + format_exc()) self.condense_tlim = condense_tlim self.tlim_safety = tlim_safety self.connect_message()
def __init__(self, name: str, address: str, terminator='\n', **kwargs: Any): """ Create an instance of the instrument. Args: name: Name of the instrument instance address: Visa-resolvable instrument address """ super().__init__(name, address, terminator=terminator, **kwargs) self.add_parameter( "sense_function", set_cmd=":SENSe:FUNCtion {}", get_cmd=":SENSe:FUNCtion?", val_mapping={ key: value["name"] for key, value in Sense7510.function_modes.items() }, docstring="Add sense functions listed in the function modes." ) self.add_parameter( "digi_sense_function", set_cmd=":DIGitize:FUNCtion {}", get_cmd=":DIGitize:FUNCtion?", val_mapping={ key: value["name"] for key, value in DigitizeSense7510.function_modes.items() }, docstring="Make readings using the active digitize function." ) self.add_parameter( "buffer_name", get_cmd=None, set_cmd=None, docstring="Name of the reading buffer in use." ) self.add_parameter( "trigger_block_list", get_cmd=":TRIGger:BLOCk:LIST?", docstring="Return the settings for all trigger model blocks." ) self.add_parameter( "trigger_in_ext_clear", set_cmd=":TRIGger:EXTernal:IN:CLEar", docstring="Clear the trigger event on the external in line." ) self.add_parameter( "trigger_in_ext_edge", get_cmd=":TRIGger:EXTernal:IN:EDGE?", set_cmd=":TRIGger:EXTernal:IN:EDGE {}", vals=Enum("FALL", "RIS", "falling", "rising", "EITH", "either"), docstring="Type of edge that is detected as an input on the " "external trigger in line" ) self.add_parameter( "overrun_status", get_cmd=":TRIGger:EXTernal:IN:OVERrun?", docstring="Return the event detector overrun status." ) self.add_parameter( "digitize_trigger", get_cmd=":TRIGger:DIGitize:STIMulus?", set_cmd=":TRIGger:DIGitize:STIMulus {}", vals=Enum("EXT", "external", "NONE"), docstring="Set the instrument to digitize a measurement the next " "time it detects the specified trigger event." ) self.add_parameter( "system_errors", get_cmd=":SYSTem:ERRor?", docstring="Return the oldest unread error message from the event " "log and removes it from the log." ) for proper_sense_function in Sense7510.function_modes: self.add_submodule( f"_sense_{proper_sense_function}", Sense7510(self, "sense", proper_sense_function) ) for proper_sense_function in DigitizeSense7510.function_modes: self.add_submodule( f"_digi_sense_{proper_sense_function}", DigitizeSense7510(self, "digi_sense", proper_sense_function) ) self.buffer_name('defbuffer1') self.buffer(name=self.buffer_name()) self.connect_message()
def __init__(self, name, address=None, port=7020, axes=None, **kwargs): super().__init__(name, address=address, port=port, terminator='\n', **kwargs) self.axes = axes self._ATOB = [] self._latest_response = '' # for some reason the first call is always invalid?! # need some kind of init? self.ask('*IDN?') if axes is None: self._determine_magnet_axes() self._determine_current_to_field() self.add_parameter( 'hold_after_set', get_cmd=None, set_cmd=None, vals=Bool(), initial_value=True, docstring= 'Should the driver block while waiting for the Magnet power supply ' 'to go into hold mode.') self.add_parameter('setpoint', names=tuple('B' + ax.lower() + '_setpoint' for ax in self.axes), units=tuple('T' for ax in self.axes), get_cmd=partial(self._get_fld, self.axes, 'FSET'), set_cmd=partial(self._ramp_to_setpoint, self.axes, 'FSET'), parameter_class=MercuryiPSArray) self.add_parameter('rate', names=tuple('rate_B' + ax.lower() for ax in self.axes), units=tuple('T/m' for ax in self.axes), get_cmd=partial(self._get_fld, self.axes, 'RFST'), set_cmd=partial(self._ramp_to_setpoint, self.axes, 'RFST'), parameter_class=MercuryiPSArray) self.add_parameter('fld', names=tuple('B' + ax.lower() for ax in self.axes), units=tuple('T' for ax in self.axes), get_cmd=partial(self._get_fld, self.axes, 'FLD'), set_cmd=partial(self._ramp_to_setpoint, self.axes, 'FSET'), parameter_class=MercuryiPSArray) self.add_parameter('fldC', names=['B' + ax.lower() for ax in self.axes], units=['T' for ax in self.axes], get_cmd=partial(self._get_fld, self.axes, 'CURR'), set_cmd=partial(self._ramp_to_setpoint, self.axes, 'CSET'), parameter_class=MercuryiPSArray) self.add_parameter('rtp', names=['radius', 'theta', 'phi'], units=['|B|', 'rad', 'rad'], get_cmd=partial(self._get_rtp, self.axes, 'FLD'), set_cmd=partial(self._set_rtp, self.axes, 'FSET'), parameter_class=MercuryiPSArray) self.add_parameter('rtpC', names=['radius', 'theta', 'phi'], units=['|B|', 'rad', 'rad'], get_cmd=partial(self._get_rtp, self.axes, 'CURR'), set_cmd=partial(self._set_rtp, self.axes, 'CSET'), parameter_class=MercuryiPSArray) # so we have radius, theta and phi in buffer self.rtp.get() self.add_parameter('radius', get_cmd=self._get_r, set_cmd=self._set_r, unit='|B|') self.add_parameter('theta', get_cmd=self._get_theta, set_cmd=self._set_theta, unit='rad') self.add_parameter('phi', get_cmd=self._get_phi, set_cmd=self._set_phi, unit='rad') for ax in self.axes: self.add_parameter(ax.lower() + '_fld', get_cmd=partial(self._get_fld, ax, 'FLD'), set_cmd=partial(self._ramp_to_setpoint, ax, 'FSET'), label='B' + ax.lower(), unit='T') self.add_parameter(ax.lower() + '_fldC', get_cmd=partial(self._get_fld, ax, 'CURR'), set_cmd=partial(self._ramp_to_setpoint, ax, 'CSET'), label='B' + ax.lower(), unit='T') self.add_parameter(ax.lower() + '_fld_wait', get_cmd=partial(self._get_fld, ax, 'CURR'), set_cmd=partial(self._ramp_to_setpoint_and_wait, ax, 'CSET'), label='B' + ax.lower(), unit='T') self.add_parameter(ax.lower() + '_ACTN', get_cmd=partial( self._get_cmd, 'READ:DEV:GRP' + ax + ':PSU:ACTN?'), set_cmd='SET:DEV:GRP' + ax + ':PSU:ACTN:{}', vals=Enum('HOLD', 'RTOS', 'RTOZ', 'CLMP')) self.add_parameter(ax.lower() + '_setpoint', get_cmd=partial(self._get_fld, ax, 'FSET'), set_cmd=partial(self._set_fld, ax, 'FSET'), unit='T') self.add_parameter(ax.lower() + '_setpointC', get_cmd=partial(self._get_fld, ax, 'CSET'), set_cmd=partial(self._set_fld, ax, 'CSET'), unit='T') self.add_parameter(ax.lower() + '_rate', get_cmd=partial(self._get_fld, ax, 'RFST'), set_cmd=partial(self._set_fld, ax, 'RFST'), unit='T/m') self.add_parameter(ax.lower() + '_rateC', get_cmd=partial(self._get_fld, ax, 'RCST'), set_cmd=partial(self._set_fld, ax, 'RCST'), unit='T/m') self.connect_message()
def __init__(self, parent: VisaInstrument, name: str, proper_function: str) -> None: super().__init__(parent, name) self._proper_function = proper_function range_vals = self.function_modes[self._proper_function]["range_vals"] unit = self.function_modes[self._proper_function]["unit"] self.function = self.parent.sense_function self.add_parameter( self._proper_function, get_cmd=self._measure, get_parser=float, unit=unit, docstring="Make measurements, place them in a reading buffer, and " "return the last reading.") self.add_parameter( "auto_range", get_cmd=f":SENSe:{self._proper_function}:RANGe:AUTO?", set_cmd=f":SENSe:{self._proper_function}:RANGe:AUTO {{}}", val_mapping=create_on_off_val_mapping(on_val="1", off_val="0"), docstring="Determine if the measurement range is set manually or " "automatically for the selected measure function.") self.add_parameter( "range", get_cmd=f":SENSe:{self._proper_function}:RANGe?", set_cmd=f":SENSe:{self._proper_function}:RANGe {{}}", vals=range_vals, get_parser=float, unit=unit, docstring="Determine the positive full-scale measure range.") self.add_parameter( "nplc", get_cmd=f":SENSe:{self._proper_function}:NPLCycles?", set_cmd=f":SENSe:{self._proper_function}:NPLCycles {{}}", vals=Numbers(0.01, 10), get_parser=float, docstring="Set the time that the input signal is measured for the " "selected function.(NPLC = number of power line cycles)") self.add_parameter( "auto_delay", get_cmd=f":SENSe:{self._proper_function}:DELay:AUTO?", set_cmd=f":SENSe:{self._proper_function}:DELay:AUTO {{}}", val_mapping=create_on_off_val_mapping(on_val="ON", off_val="OFF"), docstring="Enable or disable the automatic delay that occurs " "before each measurement.") self.add_parameter( 'user_number', get_cmd=None, set_cmd=None, vals=Ints(1, 5), docstring="Set the user number for user-defined delay.") self.add_parameter( "user_delay", get_cmd=self._get_user_delay, set_cmd=self._set_user_delay, vals=Numbers(0, 1e4), unit='second', docstring="Set a user-defined delay that you can use in the " "trigger model.") self.add_parameter( "auto_zero", get_cmd=f":SENSe:{self._proper_function}:AZERo?", set_cmd=f":SENSe:{self._proper_function}:AZERo {{}}", val_mapping=create_on_off_val_mapping(on_val="1", off_val="0"), docstring="Enable or disable automatic updates to the internal " "reference measurements (autozero) of the instrument.") self.add_parameter( "auto_zero_once", set_cmd=f":SENSe:AZERo:ONCE", docstring="Cause the instrument to refresh the reference and " "zero measurements once") self.add_parameter( "average", get_cmd=f":SENSe:{self._proper_function}:AVERage?", set_cmd=f":SENSe:{self._proper_function}:AVERage {{}}", val_mapping=create_on_off_val_mapping(on_val="1", off_val="0"), docstring="Enable or disable the averaging filter for measurements " "of the selected function.") self.add_parameter( "average_count", get_cmd=f":SENSe:{self._proper_function}:AVERage:COUNt?", set_cmd=f":SENSe:{self._proper_function}:AVERage:COUNt {{}}", vals=Numbers(1, 100), docstring="Set the number of measurements that are averaged when " "filtering is enabled.") self.add_parameter( "average_type", get_cmd=f":SENSe:{self._proper_function}:AVERage:TCONtrol?", set_cmd=f":SENSe:{self._proper_function}:AVERage:TCONtrol {{}}", vals=Enum('REP', 'rep', 'MOV', 'mov'), docstring="Set the type of averaging filter that is used for the " "selected measure function when the measurement filter " "is enabled.")
def __init__(self, name, spi_rack, module, inter_delay=0.1, dac_step=10e-3, reset_voltages=False, mV=False, number_dacs=16, **kwargs): """ Create instrument for the D5a module. The D5a module works with volts as units. For backward compatibility there is the option to allow mV for the dacX parameters. The output span of the DAC module can be changed with the spanX command. Be carefull when executing this command with a sample connected as voltage jumps can occur. Args: name (str): name of the instrument. spi_rack (SPI_rack): instance of the SPI_rack class as defined in the spirack package. This class manages communication with the individual modules. module (int): module number as set on the hardware. inter_delay (float): time in seconds, passed to dac parameters of the object dac_step (float): max step size (V or mV), passed to dac parameters of the object reset_voltages (bool): passed to D5a_module constructor mV (bool): if True, then use mV as units in the dac parameters number_dacs (int): number of DACs available. This is 8 for the D5mux """ super().__init__(name, **kwargs) self.d5a = D5a_module(spi_rack, module, reset_voltages=reset_voltages) self._mV = mV self._number_dacs = number_dacs self._span_set_map = { '4v uni': 0, '4v bi': 2, '2v bi': 4, } self._span_get_map = {v: k for k, v in self._span_set_map.items()} self.add_function('set_dacs_zero', call_cmd=self._set_dacs_zero) if self._mV: self._gain = 1e3 unit = 'mV' else: self._gain = 1 unit = 'V' for i in range(self._number_dacs): validator = self._get_validator(i) self.add_parameter('dac{}'.format(i + 1), label='DAC {}'.format(i + 1), get_cmd=partial(self._get_dac, i), set_cmd=partial(self._set_dac, i), unit=unit, vals=validator, step=dac_step, inter_delay=inter_delay) self.add_parameter('stepsize{}'.format(i + 1), get_cmd=partial(self.d5a.get_stepsize, i), unit='V') self.add_parameter( 'span{}'.format(i + 1), get_cmd=partial(self._get_span, i), set_cmd=partial(self._set_span, i), vals=Enum(*self._span_set_map.keys()), docstring= 'Change the output span of the DAC. This command also updates the validator.' )