def __init__(self, name, **kwargs): super().__init__(name, **kwargs) channels = ChannelList(self, "TempSensors", DummyChannel, snapshotable=False) for chan_name in ('A', 'B', 'C', 'D', 'E', 'F'): channel = DummyChannel(self, f'Chan{chan_name}', chan_name) channels.append(channel) self.add_submodule(chan_name, channel) self.add_submodule("channels", channels.to_channel_tuple())
def __init__(self, name, channel_names=None, **kwargs): super().__init__(name, **kwargs) channels = ChannelList(self, "TempSensors", DummyChannel, snapshotable=False) if channel_names is None: channel_ids = ("A", "B", "C", "D", "E", "F") channel_names = tuple(f"Chan{chan_name}" for chan_name in channel_ids) else: channel_ids = channel_names for chan_name, chan_id in zip(channel_names, channel_ids): channel = DummyChannel(self, chan_name, chan_id) channels.append(channel) self.add_submodule(chan_id, channel) self.add_submodule("channels", channels.to_channel_tuple())
def __init__(self, name: str = 'mdac', num_channels: int = 10, **kwargs): """ Create a dummy instrument that can be used for testing Args: name: name for the instrument gates: list of names that is used to create parameters for the instrument """ super().__init__(name, **kwargs) # make gates channels = ChannelList(self, "channels", MockDACChannel) for n in range(num_channels): num = str(n + 1).zfill(2) chan_name = f"ch{num}" channel = MockDACChannel(parent=self, name=chan_name, num=num) channels.append(channel) self.add_submodule(chan_name, channel) self.add_submodule("channels", channels.to_channel_tuple())
def __init__(self, name: str, address: str, port: int = 23): super().__init__(name, address, port) self.flush_connection() channels = ChannelList(self, "Channels", MC_channel, snapshotable=False) _chanlist = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] _max_channel_number = int(self.IDN()['model'][3]) _chanlist = _chanlist[0:_max_channel_number] for c in _chanlist: channel = MC_channel(self, f'channel_{c}', c) channels.append(channel) self.add_submodule(f"channel_{c}", channel) self.add_submodule("channels", channels.to_channel_tuple()) self.connect_message()
def add_channels(self) -> None: channels = ChannelList(self, "Channels", self.CHANNEL_CLASS, snapshotable=False) _chanlist = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] self._deprecated_attributes: Dict[str, str] = { f'channel_{k}': k for k in _chanlist } _max_channel_number = self.get_number_of_channels() _chanlist = _chanlist[0:_max_channel_number] for c in _chanlist: channel = self.CHANNEL_CLASS(self, f'channel_{c}', c) channels.append(channel) attribute_name = f'channel_{c}' self.add_submodule(attribute_name, channel) self.add_submodule(c, channel) self._deprecated_attributes[attribute_name] = c self.add_submodule("channels", channels.to_channel_tuple())
def __init__(self, name: str, address: str, timeout: float = 20, **kwargs: Any): """ Initialises the DS4000. Args: name: Name of the instrument used by QCoDeS address: Instrument address as used by VISA timeout: visa timeout, in secs. long default (180) to accommodate large waveforms """ # Init VisaInstrument. device_clear MUST NOT be issued, otherwise communications hangs # due a bug in firmware super().__init__(name, address, device_clear=False, timeout=timeout, **kwargs) self.connect_message() self._check_firmware_version() # functions self.add_function('run', call_cmd=':RUN', docstring='Start acquisition') self.add_function('stop', call_cmd=':STOP', docstring='Stop acquisition') self.add_function('single', call_cmd=':SINGle', docstring='Single trace acquisition') self.add_function('force_trigger', call_cmd='TFORce', docstring='Force trigger event') self.add_function("auto_scale", call_cmd=":AUToscale", docstring="Perform autoscale") # general parameters self.add_parameter('trigger_type', label='Type of the trigger', get_cmd=':TRIGger:MODE?', set_cmd=':TRIGger:MODE {}', vals=vals.Enum('EDGE', 'PULS', 'RUNT', 'NEDG', 'SLOP', 'VID', 'PATT', 'RS232', 'IIC', 'SPI', 'CAN', 'FLEX', 'USB')) self.add_parameter('trigger_mode', label='Mode of the trigger', get_cmd=':TRIGger:SWEep?', set_cmd=':TRIGger:SWEep {}', vals=vals.Enum('AUTO', 'NORM', 'SING')) self.add_parameter("time_base", label="Horizontal time base", get_cmd=":TIMebase:MAIN:SCALe?", set_cmd=":TIMebase:MAIN:SCALe {}", get_parser=float, unit="s/div") self.add_parameter("sample_point_count", label="Number of the waveform points", get_cmd=":WAVeform:POINts?", set_cmd=":WAVeform:POINts {}", get_parser=int, vals=Ints(min_value=1)) self.add_parameter("enable_auto_scale", label="Enable or disable autoscale", get_cmd=":SYSTem:AUToscale?", set_cmd=":SYSTem:AUToscale {}", get_parser=bool, vals=Bool()) channels = ChannelList(self, "Channels", RigolDS4000Channel, snapshotable=False) for channel_number in range(1, 5): channel = RigolDS4000Channel(self, f"ch{channel_number}", channel_number) channels.append(channel) self.add_submodule("channels", channels.to_channel_tuple())
def __init__( self, name: str, address: str, timeout: float = 20, channels: int = 4, silence_pyvisapy_warning: bool = False, **kwargs: Any, ): """ Initialises the oscilloscope. Args: name: Name of the instrument used by QCoDeS address: Instrument address as used by VISA timeout: Visa timeout, in secs. channels: The number of channels on the scope. silence_pyvisapy_warning: Don't warn about pyvisa-py at startup """ super().__init__(name, address, timeout=timeout, terminator="\n", **kwargs) self.connect_message() # Check if we are using pyvisa-py as our visa lib and warn users that # this may cause long digitize operations to fail if (self.visa_handle.visalib.library_path == "py" and not silence_pyvisapy_warning): self.log.warning( "Timeout not handled correctly in pyvisa_py. This may cause" " long acquisitions to fail. Either use ni/keysight visalib" " or set timeout to longer than longest expected acquisition" " time.") # switch the response header off else none of our parameters will work self.write(":SYSTem:HEADer OFF") # Then set up the data format used to retrieve waveforms self.write(":WAVEFORM:FORMAT WORD") self.write(":WAVEFORM:BYTEORDER LSBFirst") self.write(":WAVEFORM:STREAMING ON") # Query the oscilloscope parameters # Set sample rate, bandwidth and memory depth limits self._query_capabilities() # Number of channels can't be queried on most older scopes. Use a parameter # for now. self.no_channels = channels # Run state self.run_mode = Parameter( name="run_mode", instrument=self, label="run mode", get_cmd=":RST?", vals=vals.Enum("RUN", "STOP", "SING"), ) # Timing Parameters self.timebase_range = Parameter( name="timebase_range", instrument=self, label="Range of the time axis", unit="s", get_cmd=":TIM:RANG?", set_cmd=":TIM:RANG {}", vals=vals.Numbers(5e-12, 20), get_parser=float, ) self.timebase_position = Parameter( name="timebase_position", instrument=self, label="Offset of the time axis", unit="s", get_cmd=":TIM:POS?", set_cmd=":TIM:POS {}", vals=vals.Numbers(), get_parser=float, ) self.timebase_roll_enabled = Parameter( name="timebase_roll_enabled", instrument=self, label="Is rolling mode enabled", get_cmd=":TIM:ROLL:ENABLE?", set_cmd=":TIM:ROLL:ENABLE {}", val_mapping={ True: 1, False: 0 }, ) # Trigger self.trigger_mode = Parameter( name="trigger_mode", instrument=self, label="Trigger mode", get_cmd=":TRIG:MODE?", ) self.trigger_sweep = Parameter( name="trigger_sweep", instrument=self, label="Trigger sweep mode", get_cmd=":TRIG:SWE?", set_cmd=":TRIG:SWE {}", vals=vals.Enum("AUTO", "TRIG"), ) self.trigger_state = Parameter( name="trigger_state", instrument=self, label="Trigger state", get_cmd=":AST?", vals=vals.Enum("ARM", "TRIG", "ATRIG", "ADONE"), snapshot_value=False, ) # Edge trigger parameters # Note that for now we only support parameterized edge triggers - this may # be something worth expanding. # To set trigger level, use the "trigger_level" parameter in each channel self.trigger_edge_source = Parameter( name="trigger_edge_source", instrument=self, label="Source channel for the edge trigger", get_cmd=":TRIGger:EDGE:SOURce?", set_cmd=":TRIGger:EDGE:SOURce {}", vals=vals.Enum(*([f"CHAN{i}" for i in range(1, 4 + 1)] + [f"DIG{i}" for i in range(16 + 1)] + ["AUX", "LINE"])), ) self.trigger_edge_slope = Parameter( name="trigger_edge_slope", instrument=self, label="slope of the edge trigger", get_cmd=":TRIGger:EDGE:SLOPe?", set_cmd=":TRIGger:EDGE:SLOPe {}", vals=vals.Enum("POS", "POSITIVE", "NEG", "NEGATIVE", "EITH"), ) self.trigger_level_aux = Parameter( name="trigger_level_aux", instrument=self, label="Tirgger level AUX", unit="V", get_cmd=":TRIGger:LEVel? AUX", set_cmd=":TRIGger:LEVel AUX,{}", get_parser=float, vals=vals.Numbers(), ) # Aquisition # If sample points, rate and timebase_scale are set in an # incomensurate way, the scope only displays part of the waveform self.acquire_points = Parameter( name="acquire_points", instrument=self, label="sample points", get_cmd=":ACQ:POIN?", set_cmd=":ACQ:POIN {}", get_parser=int, vals=vals.Numbers(min_value=self.min_pts, max_value=self.max_pts), ) self.sample_rate = Parameter( name="sample_rate", instrument=self, label="sample rate", get_cmd=":ACQ:SRAT?", set_cmd=":ACQ:SRAT {}", unit="Hz", get_parser=float, vals=vals.Numbers(min_value=self.min_srat, max_value=self.max_srat), ) # Note: newer scopes allow a per-channel bandwidth. This is not implemented yet. self.bandwidth = Parameter( name="bandwidth", instrument=self, label="bandwidth", get_cmd=":ACQ:BAND?", set_cmd=":ACQ:BAND {}", unit="Hz", get_parser=float, vals=vals.Numbers(min_value=self.min_bw, max_value=self.max_bw), ) self.acquire_interpolate = Parameter( name="acquire_interpolate", instrument=self, get_cmd=":ACQ:INTerpolate?", set_cmd=":ACQuire:INTerpolate {}", vals=vals.Enum(0, 1, "INT1", "INT2", "INT4", "INT8", "INT16", "INT32"), ) self.acquire_mode = Parameter( name="acquire_mode", instrument=self, label="Acquisition mode", get_cmd="ACQuire:MODE?", set_cmd="ACQuire:MODE {}", vals=vals.Enum( "ETIMe", "RTIMe", "PDETect", "HRESolution", "SEGMented", "SEGPdetect", "SEGHres", ), ) self.average = Parameter( name="average", instrument=self, label="Averages", get_cmd=self._get_avg, set_cmd=self._set_avg, vals=vals.Ints(min_value=1, max_value=10486575), ) # Automatically digitize before acquiring a trace self.auto_digitize: Parameter = Parameter( name="auto_digitize", instrument=self, label="Auto digitize", set_cmd=None, get_cmd=None, val_mapping=create_on_off_val_mapping(), docstring=( "Digitize before each waveform download. " "If you need to acquire from multiple channels simultaneously " "or you wish to acquire with the scope running freely, " "set this value to False."), initial_value=True, ) self.cache_setpoints: Parameter = Parameter( name="cache_setpoints", instrument=self, label="Cache setpoints", set_cmd=None, get_cmd=None, val_mapping=create_on_off_val_mapping(), docstring= ("Cache setpoints. If false, the preamble is queried before each" " acquisition, which may add latency to measurements. If you" " are taking repeated measurements, set this to True and update" " setpoints manually by calling `instr.chX.update_setpoints()`."), initial_value=False, ) # Channels _channels = ChannelList(self, "channels", InfiniiumChannel, snapshotable=False) for i in range(1, self.no_channels + 1): channel = InfiniiumChannel(self, f"chan{i}", i) _channels.append(channel) self.add_submodule(f"ch{i}", channel) self.add_submodule("channels", _channels.to_channel_tuple()) # Functions _functions = ChannelList(self, "functions", InfiniiumFunction, snapshotable=False) for i in range(1, 16 + 1): function = InfiniiumFunction(self, f"func{i}", i) _functions.append(function) self.add_submodule(f"func{i}", function) # Have to call channel list "funcs" here as functions is a # reserved name in Instrument. self.add_submodule("funcs", _functions.to_channel_tuple()) # Submodules meassubsys = UnboundMeasurement(self, "measure") self.add_submodule("measure", meassubsys)
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') self.add_parameter('complex_voltage', label='Voltage', get_cmd=self._get_complex_voltage, unit='V', vals=ComplexNumbers()) # 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) self.add_submodule("data_channels", data_channels.to_channel_tuple()) # 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 __init__(self, name: str, address: str, update_currents: bool = False, **kwargs: Any): """ Instantiates the instrument. Args: name: The instrument name used by qcodes address: The VISA name of the resource update_currents: Whether to query all channels for their current sensor value on startup, which takes about 0.5 sec per channel. Default: False. Returns: QDac object """ super().__init__(name, address, **kwargs) handle = self.visa_handle self._get_status_performed = False assert isinstance(handle, SerialInstrument) # Communication setup + firmware check handle.baud_rate = 480600 handle.parity = visa.constants.Parity(0) handle.data_bits = 8 self.set_terminator('\n') handle.write_termination = '\n' self._write_response = '' firmware_version = self._get_firmware_version() if firmware_version < 1.07: LOG.warning(f"Firmware version: {firmware_version}") raise RuntimeError(''' No QDevil QDAC detected or the firmware version is obsolete. This driver only supports version 1.07 or newer. Please contact [email protected] for a firmware update. ''') # Initialse basic information and internal book keeping self.num_chans = self._get_number_of_channels() num_boards = int(self.num_chans/8) self._output_n_lines = self.num_chans + 2 self._chan_range = range(1, 1 + self.num_chans) self.channel_validator = vals.Ints(1, self.num_chans) self._reset_bookkeeping() # Add channels (and channel parameters) channels = ChannelList(self, "Channels", QDacChannel, snapshotable=False, multichan_paramclass=QDacMultiChannelParameter) for i in self._chan_range: channel = QDacChannel(self, f'chan{i:02}', i) channels.append(channel) self.add_submodule(f"ch{i:02}", channel) self.add_submodule("channels", channels.to_channel_tuple()) # Updatechannel sync port validator according to number of boards self._num_syns = max(num_boards-1, 1) for chan in self._chan_range: self.channels[chan-1].sync.vals = vals.Ints(0, self._num_syns) # Add non-channel parameters for board in range(num_boards): for sensor in range(3): label = f'Board {board}, Temperature {sensor}' self.add_parameter(name=f'temp{board}_{sensor}', label=label, unit='C', get_cmd=f'tem {board} {sensor}', get_parser=self._num_verbose) self.add_parameter(name='cal', set_cmd='cal {}', vals=vals.Ints(0, self.num_chans)) self.add_parameter(name='mode_force', label='Mode force', get_cmd=None, set_cmd=None, vals=vals.Bool(), initial_value=False) # Due to a firmware bug in 1.07 voltage ranges are always reported # vebosely. So for future compatibility we set verbose True self.write('ver 1') self._update_voltage_ranges() # The driver require verbose mode off except for the above command self.write('ver 0') self._verbose = False # Just so that the code can check the state self.connect_message() LOG.info('[*] Querying all channels for voltages and currents...') self._update_cache(update_currents=update_currents) self._update_currents = update_currents self._load_state() LOG.info('[+] Done')
def __init__(self, name: str, address: str, num_chans: int = 48, update_currents: bool = True, **kwargs: Any): """ Instantiates the instrument. Args: name: The instrument name used by qcodes address: The VISA name of the resource num_chans: Number of channels to assign. Default: 48 update_currents: Whether to query all channels for their current current value on startup. Default: True. Returns: QDac object """ super().__init__(name, address, **kwargs) self._output_n_lines = 50 handle = self.visa_handle assert isinstance(handle, SerialInstrument) self._get_status_performed = False # This is the baud rate on power-up. It can be changed later but # you must start out with this value. handle.baud_rate = 480600 handle.parity = visa.constants.Parity(0) handle.data_bits = 8 self.set_terminator('\n') # TODO: do we want a method for write termination too? handle.write_termination = '\n' # TODO: do we need a query delay for robust operation? self._write_response = '' if self._get_firmware_version() < 0.170202: raise RuntimeError(''' Obsolete QDAC Software version detected. QCoDeS only supports version 0.170202 or newer. Contact [email protected] for an update. ''') self.num_chans = num_chans # Assigned slopes. Entries will eventually be [chan, slope] self._slopes: List[Tuple[int, Union[str, float]]] = [] # Function generators (used in _set_voltage) self._fgs = set(range(1, 9)) self._assigned_fgs: Dict[int, int] = {} # {chan: fg} # Sync channels self._syncoutputs: List[Tuple[int, int]] = [ ] # Entries: [chan, syncchannel] self.chan_range = range(1, 1 + self.num_chans) self.channel_validator = vals.Ints(1, self.num_chans) channels = ChannelList(self, "Channels", QDacChannel, snapshotable=False, multichan_paramclass=QDacMultiChannelParameter) for i in self.chan_range: channel = QDacChannel(self, f'chan{i:02}', i) channels.append(channel) # Should raise valueerror if name is invalid (silently fails now) self.add_submodule(f"ch{i:02}", channel) self.add_submodule("channels", channels.to_channel_tuple()) for board in range(6): for sensor in range(3): label = f'Board {board}, Temperature {sensor}' self.add_parameter(name=f'temp{board}_{sensor}', label=label, unit='C', get_cmd=f'tem {board} {sensor}', get_parser=self._num_verbose) self.add_parameter(name='cal', set_cmd='cal {}', vals=self.channel_validator) # TO-DO: maybe it's too dangerous to have this settable. # And perhaps ON is a better verbose mode default? self.add_parameter(name='verbose', set_cmd='ver {}', val_mapping={ True: 1, False: 0 }) # Initialise the instrument, all channels DC (unbind func. generators) for chan in self.chan_range: # Note: this call does NOT change the voltage on the channel self.write(f'wav {chan} 0 1 0') self.verbose.set(False) self.connect_message() log.info('[*] Querying all channels for voltages and currents...') self._update_cache(readcurrents=update_currents) self._update_currents = update_currents log.info('[+] Done')