def __init__(self, name: str, address: str, num_channels: int, **kwargs: Any) -> None: super().__init__(name, address, **kwargs) self.max_current = _RohdeSchwarzHMC804x._max_currents[num_channels] self.add_parameter('state', label='Output enabled', set_cmd='OUTPut:MASTer:STATe {}', get_cmd='OUTPut:MASTer:STATe?', val_mapping={ 'ON': 1, 'OFF': 0 }, vals=vals.Enum('ON', 'OFF')) # channel-specific parameters channels = ChannelList(self, "SupplyChannel", RohdeSchwarzHMC804xChannel, snapshotable=False) for ch_num in range(1, num_channels + 1): ch_name = f"ch{ch_num}" channel = RohdeSchwarzHMC804xChannel(self, ch_name, ch_num) channels.append(channel) self.add_submodule(ch_name, channel) self.add_submodule("channels", channels.to_channel_tuple()) self.connect_message()
def __init__(self, name: str, address: str, min_val: number = -5, max_val: number = 5, **kwargs) -> None: """ Creates an instance of the Decadac instruments Args: name: What this instrument is called locally. address: The address of the DAC. For a serial port this is ASRLn::INSTR where n is replaced with the address set in the VISA control panel. Baud rate and other serial parameters must also be set in the VISA control panel. min_val: The minimum value in volts that can be output by the DAC. This value should correspond to the DAC code 0. max_val: The maximum value in volts that can be output by the DAC. This value should correspond to the DAC code 65536. """ super().__init__(name, address, **kwargs) # Do feature detection self._feature_detect() # Create channels channels = ChannelList(self, "Channels", self.DAC_CHANNEL_CLASS, snapshotable=False) slots = ChannelList(self, "Slots", self.DAC_SLOT_CLASS) for i in range(5): # Create the 6 DAC slots slots.append( self.DAC_SLOT_CLASS(self, f"Slot{i}", i, min_val, max_val)) slot_channels = slots[i].channels slot_channels = cast(ChannelList, slot_channels) channels.extend(slot_channels) self.add_submodule("slots", slots.to_channel_tuple()) self.add_submodule("channels", channels.to_channel_tuple()) self.connect_message()
def __init__(self, name: str, address: str, **kwargs: Any) -> None: super().__init__(name, address, terminator="\r\n", **kwargs) sensors = ChannelList(self, "sensor", Model_325_Sensor, snapshotable=False) for inp in ['A', 'B']: sensor = Model_325_Sensor(self, f'sensor_{inp}', inp) sensors.append(sensor) self.add_submodule(f'sensor_{inp}', sensor) self.add_submodule("sensor", sensors.to_channel_tuple()) heaters = ChannelList(self, "heater", Model_325_Heater, snapshotable=False) for loop in [1, 2]: heater = Model_325_Heater(self, f'heater_{loop}', loop) heaters.append(heater) self.add_submodule(f'heater_{loop}', heater) self.add_submodule("heater", heaters.to_channel_tuple()) curves = ChannelList(self, "curve", Model_325_Curve, snapshotable=False) for curve_index in range(1, 35): curve = Model_325_Curve(self, curve_index) curves.append(curve) self.add_submodule("curve", curves) self.connect_message()
def __init__(self, name: str, address: str, terminator: str = '\r\n', **kwargs: Any) -> None: super().__init__(name, address, terminator=terminator, **kwargs) # Allow access to channels either by referring to the channel name # or through a channel list, i.e. instr.A.temperature() and # instr.channels[0].temperature() refer to the same parameter. # Note that `snapshotable` is set to false in order to avoid duplicate # snapshotting which otherwise will happen because each channel is also # added as a submodule to the instrument. channels = ChannelList(self, "TempSensors", self.CHANNEL_CLASS, snapshotable=False) for name, command in self.channel_name_command.items(): channel = self.CHANNEL_CLASS(self, name, command) channels.append(channel) self.add_submodule(name, channel) self.add_submodule("channels", channels.to_channel_tuple()) self.connect_message()
def __init__(self, name: str, address: str, **kwargs: Any) -> None: """ Args: name: Name to use internally in QCoDeS. address: VISA resource address """ super().__init__(name, address, terminator='\n', **kwargs) channels = ChannelList(self, "Channels", AimTTiChannel, snapshotable=False) _model = self.get_idn()['model'] _numOutputChannels = { 'PL068-P': 1, 'PL155-P': 1, 'PL303-P': 1, 'PL601-P': 1, 'PL303QMD-P': 2, 'PL303QMT': 3 } if (not _model in _numOutputChannels.keys()) or (_model is None): raise NotKnownModel("Unknown model, connection cannot be " "established.") self.numOfChannels = _numOutputChannels[_model] for i in range(1, self.numOfChannels + 1): channel = AimTTiChannel(self, f'ch{i}', i) channels.append(channel) self.add_submodule(f'ch{i}', channel) self.add_submodule("channels", channels.to_channel_tuple()) self.connect_message()
def __init__(self, name: str, address: str, timeout: float = 20, **kwargs: Any): """ Initialises the TPS2012. 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 """ super().__init__(name, address, timeout=timeout, **kwargs) self.connect_message() # Scope trace boolean self.trace_ready = False # functions self.add_function('force_trigger', call_cmd='TRIGger FORce', docstring='Force trigger event') self.add_function('run', call_cmd='ACQuire:STATE RUN', docstring='Start acquisition') self.add_function('stop', call_cmd='ACQuire:STATE STOP', docstring='Stop acquisition') # general parameters self.add_parameter('trigger_type', label='Type of the trigger', get_cmd='TRIGger:MAIn:TYPe?', set_cmd='TRIGger:MAIn:TYPe {}', vals=vals.Enum('EDGE', 'VIDEO', 'PULSE')) self.add_parameter('trigger_source', label='Source for the trigger', get_cmd='TRIGger:MAIn:EDGE:SOURce?', set_cmd='TRIGger:MAIn:EDGE:SOURce {}', vals=vals.Enum('CH1', 'CH2')) self.add_parameter('trigger_edge_slope', label='Slope for edge trigger', get_cmd='TRIGger:MAIn:EDGE:SLOpe?', set_cmd='TRIGger:MAIn:EDGE:SLOpe {}', vals=vals.Enum('FALL', 'RISE')) self.add_parameter('trigger_level', label='Trigger level', unit='V', get_cmd='TRIGger:MAIn:LEVel?', set_cmd='TRIGger:MAIn:LEVel {}', vals=vals.Numbers()) self.add_parameter('data_source', label='Data source', get_cmd='DATa:SOUrce?', set_cmd='DATa:SOURce {}', vals=vals.Enum('CH1', 'CH2')) self.add_parameter('horizontal_scale', label='Horizontal scale', unit='s', get_cmd='HORizontal:SCAle?', set_cmd=self._set_timescale, get_parser=float, vals=vals.Enum(5e-9, 10e-9, 25e-9, 50e-9, 100e-9, 250e-9, 500e-9, 1e-6, 2.5e-6, 5e-6, 10e-6, 25e-6, 50e-6, 100e-6, 250e-6, 500e-6, 1e-3, 2.5e-3, 5e-3, 10e-3, 25e-3, 50e-3, 100e-3, 250e-3, 500e-3, 1, 2.5, 5, 10, 25, 50)) # channel-specific parameters channels = ChannelList(self, "ScopeChannels", TPS2012Channel, snapshotable=False) for ch_num in range(1, 3): ch_name = f"ch{ch_num}" channel = TPS2012Channel(self, ch_name, ch_num) channels.append(channel) self.add_submodule(ch_name, channel) self.add_submodule("channels", channels.to_channel_tuple()) # Necessary settings for parsing the binary curve data self.visa_handle.encoding = 'latin-1' log.info('Set VISA encoding to latin-1') self.write('DATa:ENCdg RPBinary') log.info('Set TPS2012 data encoding to RPBinary' + ' (Positive Integer Binary)') self.write('DATa:WIDTh 2') log.info('Set TPS2012 data width to 2')
def __init__(self, name: str, address: str, timeout: float = 20, **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. """ super().__init__(name, address, timeout=timeout, terminator='\n', **kwargs) self.connect_message() # Scope trace boolean self.trace_ready = False # switch the response header off, # else none of our parameters will work self.write(':SYSTem:HEADer OFF') # functions # general parameters # the parameters are in the same order as the front panel. # Beware, he list of implemented parameters is not complete. Refer to # the manual (Infiniium prog guide) for an equally infiniium list. # time base # timebase_scale is commented out for same reason as channel scale # use range instead # self.add_parameter('timebase_scale', # label='Scale of the one time devision', # unit='s/Div', # get_cmd=':TIMebase:SCALe?', # set_cmd=':TIMebase:SCALe {}', # vals=Numbers(), # get_parser=float, # ) self.add_parameter('timebase_range', label='Range of the time axis', unit='s', get_cmd=':TIMebase:RANGe?', set_cmd=':TIMebase:RANGe {}', vals=Numbers(5e-12, 20), get_parser=float, ) self.add_parameter('timebase_position', label='Offset of the time axis', unit='s', get_cmd=':TIMebase:POSition?', set_cmd=':TIMebase:POSition {}', vals=Numbers(), get_parser=float, ) self.add_parameter('timebase_roll_enabled', label='Is rolling mode enabled', get_cmd=':TIMebase:ROLL:ENABLE?', set_cmd=':TIMebase:ROLL:ENABLE {}', val_mapping={True: 1, False: 0} ) # trigger self.add_parameter('trigger_enabled', label='Is trigger enabled', get_cmd=':TRIGger:AND:ENABLe?', set_cmd=':TRIGger:AND:ENABLe {}', val_mapping={True: 1, False: 0} ) self.add_parameter('trigger_edge_source', label='Source channel for the edge trigger', get_cmd=':TRIGger:EDGE:SOURce?', set_cmd=':TRIGger:EDGE:SOURce {}', vals=Enum(*( [f'CHANnel{i}' for i in range(1, 4 + 1)] + [f'CHAN{i}' for i in range(1, 4 + 1)] + [f'DIGital{i}' for i in range(16 + 1)] + [f'DIG{i}' for i in range(16 + 1)] + ['AUX', 'LINE'])) ) # add enum for case insesitivity self.add_parameter('trigger_edge_slope', label='slope of the edge trigger', get_cmd=':TRIGger:EDGE:SLOPe?', set_cmd=':TRIGger:EDGE:SLOPe {}', vals=Enum('positive', 'negative', 'neither') ) self.add_parameter('trigger_level_aux', label='Tirgger level AUX', unit='V', get_cmd=':TRIGger:LEVel? AUX', set_cmd=':TRIGger:LEVel AUX,{}', get_parser=float, 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.add_parameter('acquire_points', label='sample points', get_cmd='ACQ:POIN?', get_parser=int, set_cmd=self._cmd_and_invalidate('ACQ:POIN {}'), unit='pts', vals=vals.Numbers(min_value=1, max_value=100e6) ) self.add_parameter('acquire_sample_rate', label='sample rate', get_cmd='ACQ:SRAT?', set_cmd=self._cmd_and_invalidate('ACQ:SRAT {}'), unit='Sa/s', get_parser=float ) # this parameter gets used internally for data aquisition. For now it # should not be used manually self.add_parameter( "data_source", label="Waveform Data source", get_cmd=":WAVeform:SOURce?", set_cmd=":WAVeform:SOURce {}", vals=Enum( *( [f"CHANnel{i}" for i in range(1, 4 + 1)] + [f"CHAN{i}" for i in range(1, 4 + 1)] + [f"DIFF{i}" for i in range(1, 2 + 1)] + [f"COMMonmode{i}" for i in range(3, 4 + 1)] + [f"COMM{i}" for i in range(3, 4 + 1)] + [f"FUNCtion{i}" for i in range(1, 16 + 1)] + [f"FUNC{i}" for i in range(1, 16 + 1)] + [f"WMEMory{i}" for i in range(1, 4 + 1)] + [f"WMEM{i}" for i in range(1, 4 + 1)] + [f"BUS{i}" for i in range(1, 4 + 1)] + ["HISTogram", "HIST", "CLOCK"] + ["MTRend", "MTR"] ) ), ) # TODO: implement as array parameter to allow for setting the other filter # ratios self.add_parameter('acquire_interpolate', get_cmd=':ACQuire:INTerpolate?', set_cmd=self._cmd_and_invalidate(':ACQuire:INTerpolate {}'), val_mapping={True: 1, False: 0} ) self.add_parameter('acquire_mode', label='Acquisition mode', get_cmd= 'ACQuire:MODE?', set_cmd='ACQuire:MODE {}', vals=Enum('ETIMe', 'RTIMe', 'PDETect', 'HRESolution', 'SEGMented', 'SEGPdetect', 'SEGHres') ) self.add_parameter('acquire_timespan', get_cmd=(lambda: self.acquire_points.get_latest() \ /self.acquire_sample_rate.get_latest()), unit='s', get_parser=float ) # time of the first point self.add_parameter('waveform_xorigin', get_cmd='WAVeform:XORigin?', unit='s', get_parser=float ) self.add_parameter('data_format', set_cmd='SAV:WAV:FORM {}', val_mapping={'csv': 'CSV', 'binary': 'BIN', 'asciixy': 'ASC'}, docstring=("Set the format for saving " "files using save_data function") ) # Channels channels = ChannelList(self, "Channels", InfiniiumChannel, snapshotable=False) for i in range(1,5): 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()) # Submodules meassubsys = MeasurementSubsystem(self, 'measure') self.add_submodule('measure', meassubsys)
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 self.log.info( "Initializing %s with power range %r-%r, freq range %r-%r.", name, min_power, max_power, min_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) self.add_submodule("ports", ports.to_channel_tuple()) # 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)) self.add_parameter('cw', label='CW Frequency', get_cmd='SENS:FREQ:CW?', get_parser=float, set_cmd='SENS:FREQ:CW {}', 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")) # Sweep Type self.add_parameter('sweep_type', label='Type', get_cmd='SENS:SWE:TYPE?', set_cmd='SENS:SWE:TYPE {}', vals=Enum('LIN', 'LOG', 'POW', 'CW', 'SEGM', 'PHAS')) # 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")) # Axis Parameters self.add_parameter('frequency_axis', unit='Hz', label="Frequency", parameter_class=PNAAxisParameter, startparam=self.start, stopparam=self.stop, pointsparam=self.points, vals=Arrays(shape=(self.points, ))) self.add_parameter('frequency_log_axis', unit='Hz', label="Frequency", parameter_class=PNALogAxisParamter, startparam=self.start, stopparam=self.stop, pointsparam=self.points, vals=Arrays(shape=(self.points, ))) self.add_parameter('time_axis', unit='s', label="Time", parameter_class=PNATimeAxisParameter, startparam=None, stopparam=self.sweep_time, pointsparam=self.points, vals=Arrays(shape=(self.points, ))) # 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()