def __init__(self, name, address, step_attenuator=False, **kwargs): super().__init__(name, address, **kwargs) # Only listed most common spellings idealy want a # .upper val for Enum or string on_off_validator = vals.Enum('on', 'On', 'ON', 'off', 'Off', 'OFF') on_off_mapping = create_on_off_val_mapping(1, 0) self.add_parameter(name='frequency', label='Frequency', unit='Hz', get_cmd='FREQ:CW?', set_cmd='FREQ:CW' + ' {:.4f}', get_parser=float, set_parser=float, vals=vals.Numbers(1e5, 20e9), docstring='Adjust the RF output frequency') self.add_parameter(name='frequency_offset', label='Frequency offset', unit='Hz', get_cmd='FREQ:OFFS?', set_cmd='FREQ:OFFS {}', get_parser=float, vals=Numbers(min_value=-200e9, max_value=200e9)) self.add_parameter('frequency_mode', label='Frequency mode', set_cmd='FREQ:MODE {}', get_cmd='FREQ:MODE?', get_parser=lambda s: s.strip(), vals=vals.Enum('FIX', 'CW', 'SWE', 'LIST')) self.add_parameter(name='phase', label='Phase', unit='deg', get_cmd='PHASE?', set_cmd='PHASE' + ' {:.8f}', get_parser=self.rad_to_deg, set_parser=self.deg_to_rad, vals=vals.Numbers(-180, 180)) self.add_parameter(name='power', label='Power', unit='dBm', get_cmd='POW:AMPL?', set_cmd='POW:AMPL' + ' {:.4f}', get_parser=float, set_parser=float, vals=vals.Numbers(-130, 25)) self.add_parameter('status', get_cmd=':OUTP?', set_cmd='OUTP {}', get_parser=parse_on_off, vals=on_off_validator) self.add_parameter(name='modulation_rf_enabled', get_cmd='OUTP:MOD?', set_cmd='OUTP:MOD {}', val_mapping=on_off_mapping) self.add_parameter( 'IQmodulator_enabled', get_cmd='DM:STATe?', set_cmd='DM:STATe {}', val_mapping=on_off_mapping, docstring= 'Enables or disables the internal I/Q modulator. Source can be external or internal.' ) for source in [1, 2]: self.add_parameter(f'IQsource{source}', get_cmd=f'DM:SOUR{source}?', set_cmd=f'DM:SOUR{source} {{}}', get_parser=lambda s: s.strip(), vals=vals.Enum('OFF', 'EXT', 'EXT600', 'INT'), docstring=IQsource_docstring) self.connect_message()
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, parent: Instrument, name: str, channel: int) -> None: """ Args: parent: The Instrument instance to which the channel is to be attached. name: The name used in the DataSet channel: The channel number, either 1 or 2. """ super().__init__(parent, name) self.channel = channel num_channels = self._parent.num_channels fg = 'function generator' if channel not in list(range(1, num_channels + 1)): raise ValueError('Illegal channel value.') self.add_parameter('state', label='Channel {} state'.format(channel), get_cmd='OUTPut{}:STATe?'.format(channel), set_cmd='OUTPut{}:STATe {{}}'.format(channel), vals=vals.Ints(0, 1), get_parser=int) ################################################## # FGEN PARAMETERS # TODO: Setting high and low will change this parameter's value self.add_parameter( 'fgen_amplitude', label='Channel {} {} amplitude'.format(channel, fg), get_cmd='FGEN:CHANnel{}:AMPLitude?'.format(channel), set_cmd='FGEN:CHANnel{}:AMPLitude {{}}'.format(channel), unit='V', vals=vals.Numbers(0, 0.5), get_parser=float) self.add_parameter( 'fgen_offset', label='Channel {} {} offset'.format(channel, fg), get_cmd='FGEN:CHANnel{}:OFFSet?'.format(channel), set_cmd='FGEN:CHANnel{}:OFFSet {{}}'.format(channel), unit='V', vals=vals.Numbers(0, 0.250), # depends on ampl. get_parser=float) self.add_parameter('fgen_frequency', label='Channel {} {} frequency'.format(channel, fg), get_cmd='FGEN:CHANnel{}:FREQuency?'.format(channel), set_cmd=partial(self._set_fgfreq, channel), unit='Hz', get_parser=float) self.add_parameter( 'fgen_dclevel', label='Channel {} {} DC level'.format(channel, fg), get_cmd='FGEN:CHANnel{}:DCLevel?'.format(channel), set_cmd='FGEN:CHANnel{}:DCLevel {{}}'.format(channel), unit='V', vals=vals.Numbers(-0.25, 0.25), get_parser=float) self.add_parameter('fgen_signalpath', label='Channel {} {} signal path'.format( channel, fg), set_cmd='FGEN:CHANnel{}:PATH {{}}'.format(channel), get_cmd='FGEN:CHANnel{}:PATH?'.format(channel), val_mapping={ 'direct': 'DIR', 'DCamplified': 'DCAM', 'AC': 'AC' }) self.add_parameter('fgen_period', label='Channel {} {} period'.format(channel, fg), get_cmd='FGEN:CHANnel{}:PERiod?'.format(channel), unit='s', get_parser=float) self.add_parameter('fgen_phase', label='Channel {} {} phase'.format(channel, fg), get_cmd='FGEN:CHANnel{}:PHASe?'.format(channel), set_cmd='FGEN:CHANnel{}:PHASe {{}}'.format(channel), unit='degrees', vals=vals.Numbers(-180, 180), get_parser=float) self.add_parameter( 'fgen_symmetry', label='Channel {} {} symmetry'.format(channel, fg), set_cmd='FGEN:CHANnel{}:SYMMetry {{}}'.format(channel), get_cmd='FGEN:CHANnel{}:SYMMetry?'.format(channel), unit='%', vals=vals.Numbers(0, 100), get_parser=float) self.add_parameter('fgen_type', label='Channel {} {} type'.format(channel, fg), set_cmd='FGEN:CHANnel{}:TYPE {{}}'.format(channel), get_cmd='FGEN:CHANnel{}:TYPE?'.format(channel), val_mapping={ 'SINE': 'SINE', 'SQUARE': 'SQU', 'TRIANGLE': 'TRI', 'NOISE': 'NOIS', 'DC': 'DC', 'GAUSSIAN': 'GAUSS', 'EXPONENTIALRISE': 'EXPR', 'EXPONENTIALDECAY': 'EXPD', 'NONE': 'NONE' }) ################################################## # AWG PARAMETERS # this command internally uses power in dBm # the manual claims that this command only works in AC mode # (OUTPut[n]:PATH is AC), but I've tested that it does what # one would expect in DIR mode. self.add_parameter( 'awg_amplitude', label='Channel {} AWG peak-to-peak amplitude'.format(channel), set_cmd='SOURCe{}:VOLTage {{}}'.format(channel), get_cmd='SOURce{}:VOLTage?'.format(channel), unit='V', get_parser=float, vals=vals.Numbers(0.250, 0.500)) # markers for mrk in range(1, 3): self.add_parameter( 'marker{}_high'.format(mrk), label='Channel {} marker {} high level'.format(channel, mrk), set_cmd='SOURce{}:MARKer{}:VOLTage:HIGH {{}}'.format( channel, mrk), get_cmd='SOURce{}:MARKer{}:VOLTage:HIGH?'.format(channel, mrk), unit='V', vals=vals.Numbers(-1.4, 1.4), get_parser=float) self.add_parameter( 'marker{}_low'.format(mrk), label='Channel {} marker {} low level'.format(channel, mrk), set_cmd='SOURce{}:MARKer{}:VOLTage:LOW {{}}'.format( channel, mrk), get_cmd='SOURce{}:MARKer{}:VOLTage:LOW?'.format(channel, mrk), unit='V', vals=vals.Numbers(-1.4, 1.4), get_parser=float) self.add_parameter( 'marker{}_waitvalue'.format(mrk), label='Channel {} marker {} wait state'.format(channel, mrk), set_cmd='OUTPut{}:WVALue:MARKer{} {{}}'.format(channel, mrk), get_cmd='OUTPut{}:WVALue:MARKer{}?'.format(channel, mrk), vals=vals.Enum('FIRST', 'LOW', 'HIGH')) ################################################## # MISC. self.add_parameter( 'resolution', label='Channel {} bit resolution'.format(channel), get_cmd='SOURce{}:DAC:RESolution?'.format(channel), set_cmd='SOURce{}:DAC:RESolution {{}}'.format(channel), vals=vals.Enum(8, 9, 10), get_parser=int, docstring=(""" 8 bit resolution allows for two markers, 9 bit resolution allows for one, and 10 bit does NOT allow for markers"""))
def __init__(self, name, address, **kwargs): super().__init__(name, address, terminator='\n', **kwargs) self.waveform = RSWaveformGenerator(self) self.add_parameter(name='clock', label='Clock', unit='Hz', get_cmd=':SOUR:TSIG:CLOC?', set_cmd=':SOUR:TSIG:CLOC {:.3f}', get_parser=float, vals=vals.Numbers( 1e3, 600e6)) # Actually 1kHz-300MHz, or 600MHz. self.add_parameter(name='amplitude', label='Amplitude', unit='V', get_cmd='SOUR:OUTP:ANAL:BAL:AMPL?', set_cmd='SOUR:OUTP:ANAL:BAL:AMPL {:.3f}V', get_parser=float, vals=vals.Numbers(0, 0.7)) self.add_parameter('output', label='Output', get_cmd=':OUTP:STAT?', set_cmd=':OUTP:STAT {}', val_mapping=create_on_off_val_mapping(on_val='1', off_val='0')) self.add_parameter('source', label='Baseband source', get_cmd=':SOUR:STAT?', set_cmd=':SOUR:STAT {}', val_mapping=create_on_off_val_mapping(on_val='1', off_val='0')) self.add_parameter( 'activeoutput', label='Active output', get_cmd=':OUTP:AOUT?', set_cmd=':OUTP:AOUT {}', vals=vals.Enum('BBO', 'DIG')) # Ours only supports BBO, I think self.add_parameter('wvfile', label='Waveform file', get_cmd=':SOUR:WAV:SEL?', set_cmd=':SOUR:WAV:SEL \'{}\'') self.add_parameter( 'runmode', label='Trigger run mode', get_cmd=':SOUR:TRIG:MODE?', set_cmd=':SOUR:TRIG:MODE {}', vals=vals.Enum('CONT', 'SING', 'REPN')) # Continuous, Single, or Repeat N times self.add_parameter( 'repeatcount', label='Repeat count', get_cmd=':SOUR:TRIG:RCO?', set_cmd=':SOUR:TRIG:RCO {}', get_parser=int, vals=vals.Ints( 1, 100)) # Up to 100 repetitions, only for REPN runmode self.add_parameter('triggersource', label='Trigger source', get_cmd=':SOUR:TRIG:SOUR?', set_cmd=':SOUR:TRIG:SOUR {}', vals=vals.Enum('MAN', 'EXT', 'BUS', 'AUTO')) # 'MAN' trigger from front panel or bus # 'EXT' trigger from back panel input # 'BUS' trigger from remote bus (e.g. USB interface) # 'AUTO' triggers are sent repeatedly from the firmware self.add_function('reset', call_cmd='*RST') self.add_function('run_self_tests', call_cmd='*TST?') self.connect_message()
def __init__(self, parent: 'ANC300', name: str, axis: int, sn: str) -> None: """Creates a new Anc300Axis class instance. The Attocube ANC300 piezo controller has up to 7 axis. Each of them are controlled by the same class. Args: parent: the internal QCoDeS name of the instrument this axis belongs to name: the internal QCoDeS name of the axis itself axis: the Index of the axis (1..7) sn: serial number of the axis controller to change some features Attributes: frequency: Set the frequency of the output signal. The maximum is restricted by the combination of output voltage and Capacitance of the piezo actuators. amplitude: Set the maximum level of the output signal. voltage: (Readonly) Reads the current stepping voltage. offset: Add a constant voltage to the output signal. Attention: the output level is only from 0 to 150 V. filter: Set the filter frequency of the internal low pass filter. For the ANM150 this attribute is not present. For the ANM200 and ANM300 this attribute has different allowed values. mode: Setting to a certain mode typically switches other functionalities off. 'gnd': Setting to this mode diables all outputs and connects them to chassis mass. 'inp': (Not for ANM150) In this mode, AC-IN and DC-IN can be enabled using the specific attributes. Setting to inp mode disables stepping and offset modes. 'cap': Setting to cap mode starts a capacitance measurement. The axis returns to gnd mode afterwards. It is not needed to switch to gnd mode before. 'stp': This enables stepping mode. AC-IN and DC-IN functionalities are not modified, while an offset function would be turned off. 'off': This enables offset mode. AC-IN and DC-IN functionalities are not modified, while any stepping would be turned off. 'stp+': This enables additive offset + stepping mode. Stepping waveforms are added to an offset. AC-IN and DC-IN functionalities are not modified. 'stp-': This enables subtractive offset + stepping mode. Stepping waveforms are subtracted from an offset. AC-IN and DC-IN functionalities, are not modified. ac: When switching on the AC-IN feature, a voltage of up to 10 VAC can be added to the output (gain 1, no amplification) using the AC-IN BNC on the frontplate of the module. dc: When switching on the DC-IN feature, a voltage in the range -10 .. +10 V can be added to the output. The gain is 15. move: Start the movement with the given steps. For moving out use positive numbers and to move in use negative numbers. start: Start a continous movement in the given direction. triggerUp: Set/get input trigger up number on axis triggerDown: Set/get input trigger down number on axis """ super().__init__(parent, name) self._axisnr = axis if sn != 'ANM200': self.add_parameter('frequency', label='Set/get the stepping frequency', get_cmd='getf {}'.format(axis), set_cmd='setf {}'.format(axis) + ' {}', vals=vals.Ints(1, 10000), get_parser=int, unit='Hz', docstring=""" Set the frequency of the output signal. The maximum is restricted by the combination of output voltage and Capacitance of the piezo actuators. """) self.add_parameter( 'amplitude', label='Set/get the stepping amplitude', get_cmd='getv {}'.format(axis), set_cmd='setv {}'.format(axis) + ' {}', vals=vals.Numbers(0.0, 150.0), get_parser=float, unit='V', docstring="Set the maximum level of the output signal.") self.add_parameter('voltage', label='Set/get the stepping voltage', get_cmd='geto {}'.format(axis), set_cmd=False, get_parser=float, unit='V', docstring="Reads the current stepping voltage.") self.add_parameter('offset', label='Set/get the offset voltage', get_cmd='geta {}'.format(axis), set_cmd='seta {}'.format(axis) + ' {}', vals=vals.Numbers(0.0, 150.0), get_parser=float, unit='V', docstring=""" Add a constant voltage to the output signal. Attention: the output level is only from 0 to 150 V. """) if sn == 'ANM200': self.add_parameter( 'filter', label='Set/get filter setting', get_cmd='getfil {}'.format(axis), set_cmd='setfil {}'.format(axis) + ' {}', vals=vals.Enum('1.6', '16', '160', '1600'), unit='Hz', docstring= "Set the filter frequency of the internal low pass filter.") if sn == 'ANM300': self.add_parameter( 'filter', label='Set/get filter setting', get_cmd='getfil {}'.format(axis), set_cmd='setfil {}'.format(axis) + ' {}', vals=vals.Enum('off', '16', '160'), unit='Hz', docstring= "Set the filter frequency of the internal low pass filter.") if sn == 'ANM150': mode_vals = ['gnd', 'cap', 'stp', 'off', 'stp+', 'stp-'] elif sn == 'ANM200': mode_vals = ['gnd', 'cap', 'stp', 'off', 'stp+', 'stp-', 'inp'] else: # ANM300 mode_vals = ['gnd', 'cap', 'stp', 'off', 'stp+', 'stp-', 'inp'] mode_docs = """ 'gnd': Setting to this mode diables all outputs and connects them to chassis mass. 'cap': Setting to cap mode starts a capacitance measurement. The axis returns to gnd mode afterwards. It is not needed to switch to gnd mode before. 'stp': This enables stepping mode. AC-IN and DC-IN functionalities are not modified, while an offset function would be turned off. 'off': This enables offset mode. AC-IN and DC-IN functionalities are not modified, while any stepping would be turned off. 'stp+': This enables additive offset + stepping mode. Stepping waveforms are added to an offset. AC-IN and DC-IN functionalities are not modified. 'stp-': This enables subtractive offset + stepping mode. Stepping waveforms are subtracted from an offset. AC-IN and DC-IN functionalities, are not modified. """ if 'inp' in mode_vals: mode_docs += """ 'inp': In this mode, AC-IN and DC-IN can be enabled using the specific attributes. Setting to inp mode disables stepping and offset modes. """ self.add_parameter('mode', label='Set/get mode', get_cmd='getm {}'.format(axis), set_cmd='setm {}'.format(axis) + ' {}', vals=vals.Enum(*mode_vals), docstring=""" Setting to a certain mode typically switches other functionalities off. Especially, there are the following modes: """ + mode_docs) if sn != 'ANM150': self.add_parameter('ac', label='Set/get status of AC-IN input', get_cmd='getaci {}'.format(axis), set_cmd='setaci {}'.format(axis) + ' {}', vals=vals.Enum('off', 'on'), docstring=""" When switching on the AC-IN feature, a voltage of up to 10 VAC can be added to the output (gain 1, no amplification) using the AC-IN BNC on the frontplate of the module. """) self.add_parameter('dc', label='Set/get status of DC-IN input', get_cmd='getdci {}'.format(axis), set_cmd='setdci {}'.format(axis) + ' {}', vals=vals.Enum('off', 'on'), docstring=""" When switching on the DC-IN feature, a voltage in the range -10 .. +10 V can be added to the output. The gain is 15. """) self.add_parameter('move', label='Move steps', get_cmd=False, set_cmd=self._domove, vals=vals.Ints(), docstring=""" Start the movement with the given steps. For moving out use positive numbers and to move in use negative numbers. """) self.add_parameter( 'start', label='Move continously', get_cmd=False, set_cmd=self._contmove, vals=vals.Enum('up', 'down'), docstring="Start a continous movement in the given direction.") self.add_parameter('triggerUp', label='Set/get input trigger up number on axis', get_cmd='gettu {}'.format(axis), set_cmd='settu {}'.format(axis) + ' {}', vals=vals.Enum('off', '1', '2', '3', '4', '5', '6', '7'), docstring="Set/get input trigger up number on axis") self.add_parameter( 'triggerDown', label='Set/get input trigger down numbers on axis', get_cmd='gettd {}'.format(axis), set_cmd='settd {}'.format(axis) + ' {}', vals=vals.Enum('off', '1', '2', '3', '4', '5', '6', '7'), docstring="Set/get input trigger down number on axis")
def __init__(self, name, address, reset=False, clock=1e9, numpoints=1000, **kw): ''' Initializes the AWG520. Args: name (str) : name of the instrument address (str) : GPIB address (Note: 520 cannot be controlled via ethernet) reset (bool) : resets to default values, default=false numpoints (int) : sets the number of datapoints Output: None ''' super().__init__(name, address, **kw) self._address = address self._values = {} self._values['files'] = {} self._clock = clock self._numpoints = numpoints self._fname = '' self.add_function('reset', call_cmd='*RST') self.add_parameter('state', get_cmd=self.get_state) # Add parameters self.add_parameter('trigger_mode', get_cmd='AWGC:RMOD?', set_cmd='AWGC:RMOD ' + '{}', vals=vals.Enum('CONT', 'TRIG', 'ENH', 'GAT')) self.add_parameter('trigger_impedance', unit='Ohm', label='Trigger impedance (Ohm)', get_cmd='TRIG:IMP?', set_cmd='TRIG:IMP ' + '{}', vals=vals.Enum(50, 1000), get_parser=float) self.add_parameter('trigger_level', unit='V', label='Trigger level (V)', get_cmd='TRIG:LEV?', set_cmd='TRIG:LEV ' + '{:.3f}', vals=vals.Numbers(-5, 5), get_parser=float) self.add_parameter('clock_freq', label='Clock frequency (Hz)', get_cmd='SOUR:FREQ?', set_cmd='SOUR:FREQ ' + '{}', vals=vals.Numbers(1e6, 1e9), get_parser=float) # Todo check if max freq is 1.2 GHz for the AWG 520 aswell self.add_parameter('numpoints', label='Number of datapoints per wave', get_cmd=self._do_get_numpoints, set_cmd=self._do_set_numpoints, vals=vals.Ints(100, int(1e9))) for ch in [1, 2]: amp_cmd = 'SOUR{}:VOLT:LEV:IMM:AMPL'.format(ch) offset_cmd = 'SOUR{}:VOLT:LEV:IMM:OFFS'.format(ch) self.add_parameter('ch{}_filename'.format(ch), set_cmd=self._gen_ch_set_func( self._do_set_filename, ch), vals=vals.Anything()) self.add_parameter('ch{}_amp'.format(ch), label='Amplitude channel {} (V)'.format(ch), unit='V', get_cmd=amp_cmd + '?', set_cmd=amp_cmd + ' {:.6f}', vals=vals.Numbers(0.02, 2.0), get_parser=float) self.add_parameter('ch{}_offset'.format(ch), label='Offset channel {} (V)'.format(ch), unit='V', get_cmd=offset_cmd + '?', set_cmd=offset_cmd + ' {:.3f}', vals=vals.Numbers(-1.0, 1.0), get_parser=float) self.add_parameter('ch{}_status'.format(ch), get_cmd='OUTP{}?'.format(ch), set_cmd='OUTP{}'.format(ch) + ' {}', vals=vals.Enum('ON', 'OFF'), get_parser=float) for j in [1, 2]: # TODO: check that 520 does not have marker delay feature # m_del_cmd = 'SOUR{}:MARK{}:DEL'.format(ch, j) m_high_cmd = 'SOUR{}:MARK{}:VOLT:LEV:IMM:HIGH'.format(ch, j) m_low_cmd = 'SOUR{}:MARK{}:VOLT:LEV:IMM:LOW'.format(ch, j) self.add_parameter( 'ch{}_m{}_high'.format(ch, j), label='Channel {} Marker {} high level (V)'.format(ch, j), get_cmd=m_high_cmd + '?', set_cmd=m_high_cmd + ' {:.3f}', vals=vals.Numbers(-2., 2.), get_parser=float) self.add_parameter( 'ch{}_m{}_low'.format(ch, j), label='Channel {} Marker {} low level (V)'.format(ch, j), get_cmd=m_low_cmd + '?', set_cmd=m_low_cmd + ' {:.3f}', vals=vals.Numbers(-2., 2.), get_parser=float) # Add functions if reset: self.reset() else: self.get_all() self.connect_message()
def __init__(self, name, **kwargs): super().__init__(name=name, **kwargs) self.add_parameter(name='power', label='Power', unit='dBm', parameter_class=ManualParameter, vals=vals.Numbers(-150, 25)) self.add_parameter(name='avg', label='Averages', unit='', parameter_class=ManualParameter, vals=vals.Numbers(1, 1000)) self.add_parameter(name='average_mode', parameter_class=ManualParameter, vals=vals.Enum('auto', 'flatten', 'reduce', 'moving')) self.add_parameter(name='average_state', parameter_class=ManualParameter, vals=vals.OnOff()) self.add_parameter(name='bandwidth', label='Bandwidth', unit='Hz', parameter_class=ManualParameter, vals=vals.Numbers(1, 1e6)) self.add_parameter(name='center_frequency', unit='Hz', parameter_class=ManualParameter, vals=vals.Numbers(100e3, 20e9)) self.add_parameter(name='span_frequency', unit='Hz', parameter_class=ManualParameter, vals=vals.Numbers(0, 20e9)) self.add_parameter(name='start_frequency', unit='Hz', parameter_class=ManualParameter, vals=vals.Numbers(100e3, 20e9)) self.add_parameter(name='stop_frequency', unit='Hz', parameter_class=ManualParameter, vals=vals.Numbers(100e3, 20e9)) self.add_parameter(name='number_sweeps_all', parameter_class=ManualParameter, vals=vals.Ints(1, 100000)) self.add_parameter(name='npts', parameter_class=ManualParameter, vals=vals.Ints(1, 100001)) self.add_parameter(name='min_sweep_time', parameter_class=ManualParameter, vals=vals.OnOff()) self.add_parameter(name='sweep_time', parameter_class=ManualParameter, vals=vals.Numbers(0, 1e5)) self.add_parameter(name='sweep_type', parameter_class=ManualParameter, vals=vals.Enum('lin', 'linear', 'log', 'logarithmic', 'pow', 'power', 'cw', 'poin', 'point', 'segm', 'segment'))
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) channels.lock() self.add_submodule('channels', channels) # Submodules meassubsys = MeasurementSubsystem(self, 'measure') self.add_submodule('measure', meassubsys)
def __init__(self, name, address, **kwargs): super().__init__(name, address, terminator='\n', **kwargs) self.add_parameter(name='frequency', label='Frequency', unit='Hz', get_cmd='SOUR:FREQ?', set_cmd='SOUR:FREQ {:.2f}', get_parser=float, vals=vals.Numbers(1e6, 20e9)) self.add_parameter(name='phase', label='Phase', unit='deg', get_cmd='SOUR:PHAS?', set_cmd='SOUR:PHAS {:.2f}', get_parser=float, vals=vals.Numbers(0, 360)) self.add_parameter(name='power', label='Power', unit='dBm', get_cmd='SOUR:POW?', set_cmd='SOUR:POW {:.2f}', get_parser=float, vals=vals.Numbers(-120, 25)) self.add_parameter('status', label='RF Output', get_cmd=':OUTP:STAT?', set_cmd=':OUTP:STAT {}', get_parser=self.get_parser_on_off, set_parser=self.set_parser_on_off) self.add_parameter('IQ_state', label='IQ Modulation', get_cmd=':IQ:STAT?', set_cmd=':IQ:STAT {}', get_parser=self.get_parser_on_off, set_parser=self.set_parser_on_off) self.add_parameter('pulsemod_state', label='Pulse Modulation', get_cmd=':SOUR:PULM:STAT?', set_cmd=':SOUR:PULM:STAT {}', get_parser=self.get_parser_on_off, set_parser=self.set_parser_on_off) self.add_parameter('pulsemod_source', label='Pulse Modulation Source', get_cmd='SOUR:PULM:SOUR?', set_cmd='SOUR:PULM:SOUR {}', vals=vals.Enum('INT', 'EXT', 'int', 'ext')) self.add_parameter('ref_osc_source', label='Reference Oscillator Source', get_cmd='SOUR:ROSC:SOUR?', set_cmd='SOUR:ROSC:SOUR {}', vals=vals.Enum('INT', 'EXT', 'int', 'ext')) # Define LO source INT/EXT (Only with K-90 option) self.add_parameter('LO_source', label='Local Oscillator Source', get_cmd='SOUR:LOSC:SOUR?', set_cmd='SOUR:LOSC:SOUR {}', vals=vals.Enum('INT', 'EXT', 'int', 'ext')) # Define output at REF/LO Output (Only with K-90 option) self.add_parameter('ref_LO_out', label='REF/LO Output', get_cmd='CONN:REFL:OUTP?', set_cmd='CONN:REFL:OUTP {}', vals=vals.Enum('REF', 'LO', 'OFF', 'ref', 'lo', 'off', 'Off')) # Frequency mw_source outputs when used as a reference self.add_parameter('ref_osc_output_freq', label='Reference Oscillator Output Frequency', get_cmd='SOUR:ROSC:OUTP:FREQ?', set_cmd='SOUR:ROSC:OUTP:FREQ {}', vals=vals.Enum('10MHz', '100MHz', '1000MHz')) # Frequency of the external reference mw_source uses self.add_parameter('ref_osc_external_freq', label='Reference Oscillator External Frequency', get_cmd='SOUR:ROSC:EXT:FREQ?', set_cmd='SOUR:ROSC:EXT:FREQ {}', vals=vals.Enum('10MHz', '100MHz', '1000MHz')) # IQ impairments self.add_parameter('IQ_impairments', label='IQ Impairments', get_cmd=':SOUR:IQ:IMP:STAT?', set_cmd=':SOUR:IQ:IMP:STAT {}', get_parser=self.get_parser_on_off, set_parser=self.set_parser_on_off) self.add_parameter('I_offset', label='I Offset', get_cmd='SOUR:IQ:IMP:LEAK:I?', set_cmd='SOUR:IQ:IMP:LEAK:I {:.2f}', get_parser=float, vals=vals.Numbers(-10, 10)) self.add_parameter('Q_offset', label='Q Offset', get_cmd='SOUR:IQ:IMP:LEAK:Q?', set_cmd='SOUR:IQ:IMP:LEAK:Q {:.2f}', get_parser=float, vals=vals.Numbers(-10, 10)) self.add_parameter('IQ_gain_imbalance', label='IQ Gain Imbalance', get_cmd='SOUR:IQ:IMP:IQR?', set_cmd='SOUR:IQ:IMP:IQR {:.2f}', get_parser=float, vals=vals.Numbers(-1, 1)) self.add_parameter('IQ_angle', label='IQ Angle Offset', get_cmd='SOUR:IQ:IMP:QUAD?', set_cmd='SOUR:IQ:IMP:QUAD {:.2f}', get_parser=float, vals=vals.Numbers(-8, 8)) self.add_function('reset', call_cmd='*RST') self.add_function('run_self_tests', call_cmd='*TST?') self.connect_message()
def __init__(self, name: str, address: str, step_attenuator: Optional[bool] = None, terminator: str = '\n', **kwargs: Any) -> None: super().__init__(name, address, terminator=terminator, **kwargs) if step_attenuator is not None: warnings.warn("step_attenuator argument to E8527D is deprecated " "and has no effect. It will be removed in the " "future.") # Query installed options self._options = self.ask_raw('DIAG:CPU:INFO:OPT:DET?') # Determine installed frequency option frequency_option = None for f_option in ['513', '520', '521', '532', '540', '550', '567']: if f_option in self._options: frequency_option = f_option if frequency_option is None: raise RuntimeError('Could not determine the frequency option') # convert installed frequency option to frequency ranges, based on: # https://www.keysight.com/us/en/assets/7018-01233/configuration-guides # /5989-1325.pdf # the frequency range here is the max range and not the specified # (calibrated) one f_options_dict = { "513": (100e3, 13e9), "520": (100e3, 20e9), "521": (10e6, 20e9), "532": (100e3, 31.8e9), "540": (100e3, 40e9), "550": (100e3, 50e9), "567": (100e3, 70e9) } # assign min and max frequencies self._min_freq: float self._max_freq: float self._min_freq, self._max_freq = f_options_dict[frequency_option] # Based on installed frequency option and presence/absence of step # attenuator (option '1E1') determine power range based on: # https://www.keysight.com/us/en/assets/7018-01211/data-sheets # /5989-0698.pdf # assign min and max powers self._min_power: float self._max_power: float if '1E1' in self._options: if frequency_option in ['513', '520', '521', '532', '540']: self._min_power = -135 self._max_power = 10 else: self._min_power = -110 self._max_power = 5 else: # default minimal power is -20 dBm if frequency_option in ['513', '520', '521', '532', '540']: self._min_power = -20 self._max_power = 10 else: self._min_power = -20 self._max_power = 5 self.add_parameter(name='frequency', label='Frequency', unit='Hz', get_cmd='FREQ:CW?', set_cmd='FREQ:CW' + ' {:.4f}', get_parser=float, set_parser=float, vals=vals.Numbers(self._min_freq, self._max_freq)) self.add_parameter(name='phase', label='Phase', unit='deg', get_cmd='PHASE?', set_cmd='PHASE' + ' {:.8f}', get_parser=self.rad_to_deg, set_parser=self.deg_to_rad, vals=vals.Numbers(-180, 180)) self.add_parameter(name='power', label='Power', unit='dBm', get_cmd='POW:AMPL?', set_cmd='POW:AMPL' + ' {:.4f}', get_parser=float, set_parser=float, vals=vals.Numbers(self._min_power, self._max_power)) self.add_parameter('status', get_cmd=':OUTP?', set_cmd='OUTP {}', val_mapping=create_on_off_val_mapping(on_val='1', off_val='0')) self.connect_message()
def set_R_Attn(self, R_bias, Attn): self._Attn = Attn self._R_bias = R_bias self.I_to_V = lambda i: i*self._R_bias*self._Attn self.I.vals = vals.Numbers(-4/self._R_bias/self._Attn, 4/self._R_bias/self._Attn)
def __init__(self, name, address=None, **kwargs): ''' Initializes the Keysight_P9374A, and communicates with the wrapper. Input: name (string) : name of the instrument address (string) : GPIB address reset (bool) : resets to default values, default=False ''' if address == None: raise Exception('TCP IP address needed') logging.info(__name__ + ' : Initializing instrument Keysight PNA') super().__init__(name, address, terminator='\n', **kwargs) # Add in parameters self.add_parameter('fstart', get_cmd=':SENS1:FREQ:STAR?', set_cmd=':SENS1:FREQ:STAR {}', vals=vals.Numbers(), get_parser=float, unit='Hz') self.add_parameter('fstop', get_cmd=':SENS1:FREQ:STOP?', set_cmd=':SENS1:FREQ:STOP {}', vals=vals.Numbers(), get_parser=float, unit='Hz') self.add_parameter('fcenter', get_cmd=':SENS1:FREQ:CENT?', set_cmd=':SENS1:FREQ:CENT {}', vals=vals.Numbers(), get_parser=float, unit='Hz') self.add_parameter('fspan', get_cmd=':SENS1:FREQ:SPAN?', set_cmd=':SENS1:FREQ:SPAN {}', vals=vals.Numbers(), get_parser=float, unit='Hz') self.add_parameter('rfout', get_cmd=':OUTP?', set_cmd=':OUTP {}', vals=vals.Ints(0, 1), get_parser=int) self.add_parameter('num_points', get_cmd=':SENS1:SWE:POIN?', set_cmd=':SENS1:SWE:POIN {}', vals=vals.Ints(1, 1601), get_parser=int) self.add_parameter('ifbw', get_cmd=':SENS1:BWID?', set_cmd=':SENS1:BWID {}', vals=vals.Numbers(10, 1.5e6), get_parser=float) self.add_parameter('power', get_cmd=":SOUR1:POW?", set_cmd=":SOUR1:POW {}", unit='dBm', get_parser=float, vals=vals.Numbers(-85, 10)) self.add_parameter('power_start', get_cmd=':SOUR1:POW:STAR?', set_cmd=':SOUR1:POW:STAR {}', unit='dBm', get_parser=float, vals=vals.Numbers(-85, 10)) self.add_parameter('power_stop', get_cmd=':SOUR:POW:STOP?', set_cmd=':SOUR1:POW:STOP {}', unit='dBm', get_parser=float, vals=vals.Numbers(-85, 20)), self.add_parameter('averaging', get_cmd=':SENS1:AVER?', set_cmd=':SENS1:AVER {}', get_parser=int, vals=vals.Ints(0, 1)) self.add_parameter('average_trigger', get_cmd=':TRIG:AVER?', set_cmd=':TRIG:AVER {}', get_parser=int, vals=vals.Ints(0, 1)) self.add_parameter('avgnum', get_cmd=':SENS1:AVER:COUN?', set_cmd=':SENS1:AVER:COUN {}', vals=vals.Ints(1), get_parser=int) self.add_parameter('phase_offset', get_cmd=':CALC1:CORR:OFFS:PHAS?', set_cmd=':CALC1:CORR:OFFS:PHAS {}', get_parser=float, vals=vals.Numbers()) self.add_parameter('electrical_delay', get_cmd='CALC1:CORR:EDEL:TIME?', set_cmd='CALC1:CORR:EDEL:TIME {}', unit='s', get_parser=float, vals=vals.Numbers()) #TODO: Set trg sources self.add_parameter('trigger_source', get_cmd='TRIG:SOUR?', set_cmd='TRIG:SOUR {}', vals=vals.Enum('INT', 'EXT', 'MAN', 'BUS')) self.add_parameter('trform', get_cmd=':CALC1:FORM?', set_cmd=':CALC1:FORM {}', vals=vals.Enum( 'MLOG', 'PHAS', 'GDEL', 'SCOM', 'SMIT', 'SADM', 'POL', 'MLIN', 'SWR', 'REAL', 'IMAG', 'UPH', 'PPH', 'SLIN', 'SLOG', )) self.add_parameter('math', get_cmd=':CALC1:MATH:FUNC?', set_cmd=':CALC1:MATH:FUNC {}', vals=vals.Enum('ADD', 'SUBT', 'DIV', 'MULT', 'NORM')) self.add_parameter('sweep_type', get_cmd=':SENS1:SWE:TYPE?', set_cmd=':SENS1:SWE:TYPE {}', vals=vals.Enum('LIN', 'LOG', 'SEGM', 'POW')) self.add_parameter('correction', get_cmd=':SENS1:CORR:STAT?', set_cmd=':SENS1:CORR:STAT {}', get_parser=int) self.add_parameter('smoothing', get_cmd=':CALC1:SMO:STAT?', set_cmd=':CALC1:SMO:STAT {}', get_parser=float) self.add_parameter( 'sweep_time', get_cmd=':SENS1:SWE:TIME?', set_cmd= None, #generally just adjust ifbw and number of pts to change it, get_parser=float, unit='s') self.write('CALC1:PAR:MNUM 1' ) #sets the active msmt to the first channel/trace self.connect_message()
def __init__(self, parent, name, channel, ch_range, ovp_range, ocp_range): super().__init__(parent, name) self.vmax = ch_range[0] self.imax = ch_range[1] self.ovp_range = ovp_range self.ocp_range = ocp_range select_cmd = ":INSTrument:NSELect {};".format(channel) strstrip = lambda s: str(s).strip() self.add_parameter("set_voltage", label='Target voltage output', set_cmd="{} :SOURce:VOLTage:LEVel:IMMediate:AMPLitude {}".format( select_cmd, '{}'), get_cmd="{} :SOURce:VOLTage:LEVel:IMMediate:AMPLitude?".format( select_cmd), get_parser=float, unit='V', vals=vals.Numbers(min(0, self.vmax), max(0, self.vmax)) ) self.add_parameter("set_current", label='Target current output', set_cmd="{} :SOURce:CURRent:LEVel:IMMediate:AMPLitude {}".format( select_cmd, '{}'), get_cmd="{} :SOURce:CURRent:LEVel:IMMediate:AMPLitude?".format( select_cmd), get_parser=float, unit='A', vals=vals.Numbers(0, self.imax) ) self.add_parameter('state', label='Output enabled', set_cmd='{} :OUTPut:STATe {}'.format(select_cmd, '{}'), get_cmd='{} :OUTPut:STATe?'.format(select_cmd), get_parser=strstrip, vals=vals.OnOff() ) self.add_parameter('mode', label='Get the output mode', get_cmd='{} :OUTPut:MODE?'.format(select_cmd), get_parser=strstrip, val_mapping={'ConstantVoltage': 'CV', 'ConstantCurrent': 'CC', 'Unregulated': 'UR'} ) self.add_parameter("voltage", label='Measured voltage', get_cmd="{} :MEASure:VOLTage:DC?".format( select_cmd), get_parser=float, unit='V', ) self.add_parameter("current", label='Measured current', get_cmd="{} :MEASure:CURRent:DC?".format( select_cmd), get_parser=float, unit='A', ) self.add_parameter("power", label='Measured power', get_cmd="{} :MEASure:POWer?".format( select_cmd), get_parser=float, unit='W', ) self.add_parameter("ovp_value", label='Over Voltage Protection value', set_cmd="{} :VOLTage:PROTection:LEVel {}".format( select_cmd, '{}'), get_cmd="{} :VOLTage:PROTection:LEVel?".format( select_cmd), get_parser=float, unit='V', vals=vals.Numbers(self.ovp_range[0], self.ovp_range[1]) ) self.add_parameter('ovp_state', label='Over Voltage Protection status', set_cmd='{} :VOLTage:PROTection:STATe {}'.format(select_cmd, '{}'), get_cmd='{} :VOLTage:PROTection:STATe?'.format(select_cmd), get_parser=strstrip, vals=vals.OnOff() ) self.add_parameter("ocp_value", label='Over Current Protection value', set_cmd="{} :CURRent:PROTection:LEVel {}".format( select_cmd, '{}'), get_cmd="{} :CURRent:PROTection:LEVel?".format( select_cmd), get_parser=float, unit='A', vals=vals.Numbers(self.ocp_range[0], self.ocp_range[1]) ) self.add_parameter('ocp_state', label='Over Current Protection status', set_cmd='{} :CURRent:PROTection:STATe {}'.format(select_cmd, '{}'), get_cmd='{} :CURRent:PROTection:STATe?'.format(select_cmd), get_parser=strstrip, vals=vals.OnOff() )
def __init__(self, name, address, step_attenuator=False, **kwargs): super().__init__(name, address, **kwargs) # Only listed most common spellings idealy want a # .upper val for Enum or string on_off_validator = vals.Enum('on', 'On', 'ON', 'off', 'Off', 'OFF') on_off_mapping = create_on_off_val_mapping(1, 0) self.add_parameter(name='frequency', label='Frequency', unit='Hz', get_cmd='FREQ:CW?', set_cmd='FREQ:CW' + ' {:.4f}', get_parser=float, set_parser=float, vals=vals.Numbers(1e5, 20e9), docstring='Adjust the RF output frequency') self.add_parameter(name='freq_offset', label='Frequency offset', unit='Hz', get_cmd='FREQ:OFFS?', set_cmd='FREQ:OFFS {}', get_parser=float, vals=Numbers(min_value=-200e9, max_value=200e9)) self.add_parameter(name='frequency_offset', source=self.freq_offset, parameter_class=DelegateParameter, docstring="'frequency_offset' delegate parameter " "for 'freq_offset' is deprecated to " "make the parameter name consistent with " "that of one present in Agilent (Keysight)" " E8267C driver in Qcodes") self.add_parameter('freq_mode', label='Frequency mode', set_cmd='FREQ:MODE {}', get_cmd='FREQ:MODE?', get_parser=lambda s: s.strip(), vals=vals.Enum('FIX', 'CW', 'SWE', 'LIST')) self.add_parameter(name='frequency_mode', source=self.freq_mode, parameter_class=DelegateParameter, docstring="'frequency_mode' delegate parameter for " "'freq_mode' is deprecated to make the " "parameter name consistent with that of " "one present in Agilent (Keysight) E8267C " "driver in Qcodes") self.add_parameter(name='phase', label='Phase', unit='deg', get_cmd='PHASE?', set_cmd='PHASE' + ' {:.8f}', get_parser=self.rad_to_deg, set_parser=self.deg_to_rad, vals=vals.Numbers(-180, 180)) self.add_parameter(name='power', label='Power', unit='dBm', get_cmd='POW:AMPL?', set_cmd='POW:AMPL' + ' {:.4f}', get_parser=float, set_parser=float, vals=vals.Numbers(-130, 25)) self.add_parameter('output_rf', get_cmd=':OUTP?', set_cmd='OUTP {}', get_parser=parse_on_off, vals=on_off_validator) self.add_parameter(name='status', source=self.output_rf, parameter_class=DelegateParameter, docstring="'status' delegate parameter for " "'output_rf' is deprecated to make the " "parameter name consistent with that of " "one present in Agilent (Keysight) E8267C " "driver in Qcodes") self.add_parameter(name='modulation_rf', get_cmd='OUTP:MOD?', set_cmd='OUTP:MOD {}', val_mapping=on_off_mapping) self.add_parameter(name='modulation_rf_enabled', source=self.modulation_rf, parameter_class=DelegateParameter, docstring="'modulation_rf_enabled' delegate " "parameter for 'modulation_rf' is " "deprecated to make the parameter name " "consistent with that of one present in " "Agilent (Keysight) E8267C driver in " "Qcodes") self.add_parameter( 'IQmodulator_enabled', get_cmd='DM:STATe?', set_cmd='DM:STATe {}', val_mapping=on_off_mapping, docstring= 'Enables or disables the internal I/Q modulator. Source can be external or internal.' ) for source in [1, 2]: self.add_parameter(f'IQsource{source}', get_cmd=f'DM:SOUR{source}?', set_cmd=f'DM:SOUR{source} {{}}', get_parser=lambda s: s.strip(), vals=vals.Enum('OFF', 'EXT', 'EXT600', 'INT'), docstring=IQsource_docstring) self.add_parameter(f'IQadjustments_enabled', get_cmd=f'DM:IQAD?', set_cmd=f'DM:IQAD {{}}', val_mapping=on_off_mapping, docstring='Enable or disable IQ adjustments') IQoffset_parameters = dict(get_parser=float, set_parser=float, vals=vals.Numbers(-100, 100)) self.add_parameter(f'I_offset', get_cmd=f'DM:IQAD:IOFF?', set_cmd=f'DM:IQAD:IOFF {{}}', **IQoffset_parameters, docstring='I channel offset in percentage') self.add_parameter(f'Q_offset', get_cmd=f'DM:IQAD:QOFF?', set_cmd=f'DM:IQAD:QOFF {{}}', **IQoffset_parameters, docstring='Q channel offset in percentage') self.add_parameter(f'IQ_quadrature', get_cmd=f'DM:IQAD:QSK?', set_cmd=f'DM:IQAD:QSK {{}}', get_parser=float, set_parser=float, docstring='IQ quadrature offset', unit='deg') self.add_parameter(f'pulse_modulation_enabled', get_cmd=f'PULM:STATe?', set_cmd=f'PULM:STATe {{}}', val_mapping=on_off_mapping, docstring='Enable or disable pulse modulation path') self.add_parameter(f'pulse_modulation_source', get_cmd=f'PULM:SOURce?', set_cmd=f'PULM:SOURce {{}}', get_parser=lambda s: s.strip(), vals=vals.Enum('EXT', 'INT', 'SCAL')) self.add_parameter( f'wideband_amplitude_modulation_enabled', get_cmd=f'AM:WID:STATe?', set_cmd=f'AM:WID:STATe {{}}', val_mapping=on_off_mapping, docstring= 'This command enables or disables wideband amplitude modulation') self.add_parameter('wideband_IQ_modulation_enabled', get_cmd=f'AM:WID:STATe?', set_cmd=f'AM:WID:STATe {{}}', val_mapping=on_off_mapping) self.add_parameter('ALC_status', get_cmd=f'ALC:STATe?', set_cmd=f'ALC:STATe {{}}', val_mapping=on_off_mapping) self.add_parameter('FM_status', get_cmd=f'FM:STATe?', set_cmd=f'FM:STATe {{}}', val_mapping=on_off_mapping) self.add_parameter('FM_source', get_cmd=f'FM:SOURce?', set_cmd=f'FM:SOURce {{}}', get_parser=lambda s: s.strip(), vals=vals.Enum('EXT1', 'EXT2', 'INT', 'INT1', 'INT2')) self.add_parameter('FM_deviation', get_cmd=f'FM:DEViation?', set_cmd=f'FM:DEViation {{}}', get_parser=lambda s: str(s) + 'MHz') self.connect_message()
def __init__(self, parent, name, channum): """ Args: parent (Instrument): The instrument to which the channel is attached. name (str): The name of the channel channum (int): The number of the channel in question (1-2) """ super().__init__(parent, name) def val_parser(parser, inputstring): """ Parses return values from instrument. Meant to be used when a query can return a meaningful finite number or a numeric representation of infinity Args: inputstring (str): The raw return value parser (type): Either int or float, what to return in finite cases """ inputstring = inputstring.strip() if float(inputstring) == 9.9e37: output = float('inf') else: output = float(inputstring) if parser == int: output = parser(output) return output self.add_parameter('function_type', label='Channel {} function type'.format(channum), set_cmd='SOURce{}:FUNCtion {{}}'.format(channum), get_cmd='SOURce{}:FUNCtion?'.format(channum), get_parser=str.rstrip, vals=vals.Enum('SIN', 'SQU', 'TRI', 'RAMP', 'PULS', 'PRBS', 'NOIS', 'ARB', 'DC')) self.add_parameter( 'frequency_mode', label='Channel {} frequency mode'.format(channum), set_cmd='SOURce{}:FREQuency:MODE {{}}'.format(channum), get_cmd='SOURce{}:FREQuency:MODE?'.format(channum), get_parser=str.rstrip, vals=vals.Enum('CW', 'LIST', 'SWEEP', 'FIXED')) self.add_parameter( 'frequency', label='Channel {} frequency'.format(channum), set_cmd='SOURce{}:FREQuency {{}}'.format(channum), get_cmd='SOURce{}:FREQuency?'.format(channum), get_parser=float, unit='Hz', # TODO: max. freq. actually really tricky vals=vals.Numbers(1e-6, 30e6)) self.add_parameter('phase', label='Channel {} phase'.format(channum), set_cmd='SOURce{}:PHASe {{}}'.format(channum), get_cmd='SOURce{}:PHASe?'.format(channum), get_parser=float, unit='deg', vals=vals.Numbers(0, 360)) self.add_parameter( 'amplitude_unit', label='Channel {} amplitude unit'.format(channum), set_cmd='SOURce{}:VOLTage:UNIT {{}}'.format(channum), get_cmd='SOURce{}:VOLTage:UNIT?'.format(channum), vals=vals.Enum('VPP', 'VRMS', 'DBM'), get_parser=str.rstrip) self.add_parameter( 'amplitude', label='Channel {} amplitude'.format(channum), set_cmd='SOURce{}:VOLTage {{}}'.format(channum), get_cmd='SOURce{}:VOLTage?'.format(channum), unit='', # see amplitude_unit get_parser=float) self.add_parameter( 'offset', label='Channel {} voltage offset'.format(channum), set_cmd='SOURce{}:VOLTage:OFFSet {{}}'.format(channum), get_cmd='SOURce{}:VOLTage:OFFSet?'.format(channum), unit='V', get_parser=float) self.add_parameter('output', label='Channel {} output state'.format(channum), set_cmd='OUTPut{} {{}}'.format(channum), get_cmd='OUTPut{}?'.format(channum), val_mapping={ 'ON': 1, 'OFF': 0 }) self.add_parameter( 'ramp_symmetry', label='Channel {} ramp symmetry'.format(channum), set_cmd='SOURce{}:FUNCtion:RAMP:SYMMetry {{}}'.format(channum), get_cmd='SOURce{}:FUNCtion:RAMP:SYMMetry?'.format(channum), get_parser=float, unit='%', vals=vals.Numbers(0, 100)) # TRIGGER MENU self.add_parameter( 'trigger_source', label='Channel {} trigger source'.format(channum), set_cmd='TRIGger{}:SOURce {{}}'.format(channum), get_cmd='TRIGger{}:SOURce?'.format(channum), vals=vals.Enum('IMM', 'EXT', 'TIM', 'BUS'), get_parser=str.rstrip, ) self.add_parameter('trigger_count', label='Channel {} trigger count'.format(channum), set_cmd='TRIGger{}:COUNt {{}}'.format(channum), get_cmd='TRIGger{}:COUNt?'.format(channum), vals=vals.Ints(1, 1000000), get_parser=partial(val_parser, int)) self.add_parameter('trigger_delay', label='Channel {} trigger delay'.format(channum), set_cmd='TRIGger{}:DELay {{}}'.format(channum), get_cmd='TRIGger{}:DELay?'.format(channum), vals=vals.Numbers(0, 1000), get_parser=float, unit='s') # TODO: trigger level doesn't work remotely. Why? self.add_parameter('trigger_slope', label='Channel {} trigger slope'.format(channum), set_cmd='TRIGger{}:SLOPe {{}}'.format(channum), get_cmd='TRIGger{}:SLOPe?'.format(channum), vals=vals.Enum('POS', 'NEG'), get_parser=str.rstrip) self.add_parameter('trigger_timer', label='Channel {} trigger timer'.format(channum), set_cmd='TRIGger{}:TIMer {{}}'.format(channum), get_cmd='TRIGger{}:TIMer?'.format(channum), vals=vals.Numbers(1e-6, 8000), get_parser=float) # output menu self.add_parameter('output_polarity', label='Channel {} output polarity'.format(channum), set_cmd='OUTPut{}:POLarity {{}}'.format(channum), get_cmd='OUTPut{}:POLarity?'.format(channum), get_parser=str.rstrip, vals=vals.Enum('NORM', 'INV')) # BURST MENU self.add_parameter('burst_state', label='Channel {} burst state'.format(channum), set_cmd='SOURce{}:BURSt:STATe {{}}'.format(channum), get_cmd='SOURce{}:BURSt:STATe?'.format(channum), val_mapping={ 'ON': 1, 'OFF': 0 }, vals=vals.Enum('ON', 'OFF')) self.add_parameter('burst_mode', label='Channel {} burst mode'.format(channum), set_cmd='SOURce{}:BURSt:MODE {{}}'.format(channum), get_cmd='SOURce{}:BURSt:MODE?'.format(channum), get_parser=str.rstrip, val_mapping={ 'N Cycle': 'TRIG', 'Gated': 'GAT' }, vals=vals.Enum('N Cycle', 'Gated')) self.add_parameter( 'burst_ncycles', label='Channel {} burst no. of cycles'.format(channum), set_cmd='SOURce{}:BURSt:NCYCles {{}}'.format(channum), get_cmd='SOURce{}:BURSt:NCYCLes?'.format(channum), get_parser=partial(val_parser, int), vals=vals.MultiType(vals.Ints(1), vals.Enum('MIN', 'MAX', 'INF'))) self.add_parameter( 'burst_phase', label='Channel {} burst start phase'.format(channum), set_cmd='SOURce{}:BURSt:PHASe {{}}'.format(channum), get_cmd='SOURce{}:BURSt:PHASe?'.format(channum), vals=vals.Numbers(-360, 360), unit='degrees', get_parser=float) self.add_parameter( 'burst_polarity', label='Channel {} burst gated polarity'.format(channum), set_cmd='SOURce{}:BURSt:GATE:POLarity {{}}'.format(channum), get_cmd='SOURce{}:BURSt:GATE:POLarity?'.format(channum), vals=vals.Enum('NORM', 'INV')) self.add_parameter( 'burst_int_period', label=('Channel {}'.format(channum) + ' burst internal period'), set_cmd='SOURce{}:BURSt:INTernal:PERiod {{}}'.format(channum), get_cmd='SOURce{}:BURSt:INTernal:PERiod'.format(channum), unit='s', vals=vals.Numbers(1e-6, 8e3), get_parser=float, docstring=('The burst period is the time ' 'between the starts of consecutive ' 'bursts when trigger is immediate.'))
def __init__(self, name, address, **kwargs): super().__init__(name, address, terminator='\n', timeout=60, **kwargs) self._data_processor = None #By default we are working with the channel number 1, so SENSe<cnum>: if all queries is just SENSe1: ... # if 'P9373' in self.ask('*IDN?'): self._is_big_endian = True # else: # self._is_big_endian = False # Acquisition parameters self.add_parameter('freq_start', label='Start frequency', unit='Hz', get_cmd='SENSe1:FREQuency:STARt?', get_parser=float, set_cmd='SENSe1:FREQuency:STARt {:f}', vals=vals.Numbers(1., 20e9)) self.add_parameter('freq_stop', label='Stop frequency', unit='Hz', get_cmd='SENSe1:FREQuency:STOP?', get_parser=float, set_cmd='SENSe1:FREQuency:STOP {:f}', vals=vals.Numbers(1., 20e9)) self.add_parameter('freq_center', label='Center frequency', unit='Hz', get_cmd='SENSe1:FREQuency:CENTer?', get_parser=float, set_cmd='SENSe1:FREQuency:CENTer {:f}', vals=vals.Numbers(1., 20e9)) self.add_parameter('freq_span', label='Frequency span', unit='Hz', get_cmd='SENSe1:FREQuency:SPAN?', get_parser=float, set_cmd='SENSe1:FREQuency:SPAN {:f}', vals=vals.Numbers(0., 10e9)) self.add_parameter( 'freq_CW', label='CW frequency', unit='Hz', docstring= '''Sets the frequency of the single-frequency continuous wave sweep. This is the frequency which will be used for CW or POWer sweeps.''', get_cmd='SENS:FREQ:CW?', get_parser=float, set_cmd='SENS:FREQ:CW {:f}', vals=vals.Numbers(0., 20e9)) self.add_parameter('power_start', label='Start power', unit='dB', docstring='Start power for the power sweep mode', get_cmd='SOUR:POW:STAR?', get_parser=float, set_cmd='SOUR:POW:STAR {:f}', vals=vals.Numbers(-30., 30)) self.add_parameter('power_stop', label='Stop power', unit='dB', docstring='Stop power for the power sweep mode', get_cmd='SOUR:POW:STOP?', get_parser=float, set_cmd='SOUR:POW:STOP {:f}', vals=vals.Numbers(-30., 30)) self.add_parameter('output', docstring='''Turns the output power ON or OFF''', get_cmd='OUTP?', set_cmd='OUTP {}', val_mapping={ 'ON': 1, 'OFF': 0, True: 1, False: 0, 1: 1, 0: 0 }) #val_mapping = OrderedDict((True, 1), (False, 0), (1, 1), (0, 0), ('ON', 1), ('OFF', 0))) self.add_parameter('power', label='power', unit='dB', docstring='''Sets the source power''', get_cmd='SOUR:POW?', get_parser=float, set_cmd='SOUR:POW {:f}', vals=vals.Numbers(-60., 20.)) self.add_parameter('averaging', docstring='''Averaging ON/OFF''', get_cmd='SENS:AVER?', set_cmd='SENS:AVER {}', val_mapping={ True: 1, False: 0 }) self.add_parameter('averaging_mode', docstring=''' Sets the type of averaging to perform: Point or Sweep. POINT - Averaging measurements are made on each data point before stepping to the next data point. SWEEP - Averaging measurements are made on subsequent sweeps until the required number of averaging sweeps are performed. Default setting is sweep. ''', get_cmd='SENS:AVER:MODE?', set_cmd='SENS:AVER:MODE {}', val_mapping={ 'point': 'POIN', 'sweep': 'SWE' }) self.add_parameter( 'averages', label='averages', docstring= '''Sets the number of averages. Averaging should be True as well.''', get_cmd='SENS:AVER:COUN?', get_parser=int, set_cmd='SENS:AVER:COUN {:d}', vals=vals.Ints(1, 1 << 16)) self.add_parameter('sweep_points', label='Points in sweep', get_cmd='SENS:SWE:POIN?', get_parser=int, set_cmd='SENS:SWE:POIN {:d}', vals=vals.Ints(1, 32001)) self.add_parameter( 'sweep_time', unit='s', docstring='''The time in seconds required to complete a single sweep. Setting to zero will result in minimum possible time required to run the sweep. The setting is valid for any sweep type.''', get_cmd='SENS:SWE:TIME?', get_parser=float, set_cmd='SENS:SWE:TIME {:f}', vals=vals.Numbers(0, 86400)) self.add_parameter( 'bandwidth', label='bandwidth', docstring= '''Sets the measurement bandwidth in Hz, working range is a list of values from 1Hz to 15MHz. Automatically rounds the input value to the closest value from the list.''', get_cmd='SENS:BAND?', get_parser=float, set_cmd='SENS:BAND {:f}', vals=vals.Numbers(1, 15e6)) self.add_parameter('sweep_type', docstring='''Type of the sweep.''', get_cmd='SENS:SWE:TYPE?', set_cmd='SENS:SWE:TYPE {}', vals=vals.Enum('LIN', 'LOG', 'POW', 'CW', 'SEGM', 'PHAS')) self.add_parameter( 'trigger', docstring= '''Mode of the internal trigger of the instrument: hold, continuous, groups or single.''', get_cmd='SENS:SWE:MODE?', set_cmd='SENS:SWE:MODE {}', vals=vals.Enum('hold', 'cont', 'gro', 'sing')) self.add_parameter( 'trigger_source', docstring= '''Source of the internal trigger of the instrument: EXTernal, IMMediate, or MANual.''', get_cmd='TRIG:SOUR?', set_cmd='TRIG:SOUR {}', vals=vals.Enum('EXT', 'IMM', 'MAN')) self._num_repetitions = 1 self._segment_freqs = [] # *IDN? self.connect_message()
def __init__(self, parent:Instrument, name:str, duration_get_cmd:callable=None) -> None: super().__init__(parent, name) self.add_parameter( 'channel', ManualParameter, docstring='Output channel of the pulse generator' ) if name == 'awg': # the primary awg must always be triggered at time zero self.add_parameter( 'reference', docstring='Time relative to which the in/output starts.', get_cmd=lambda:'awg output start' ) self.add_parameter( 'offset', unit='s', docstring='In/output time offset from reference point.', get_cmd=lambda: 0. ) else: self.add_parameter( 'reference', ManualParameter, docstring='Time relative to which the in/output starts.', vals=vals.Enum('zero', 'awg output start', 'fixed point'), initial_value='fixed point' ) self.add_parameter( 'offset', ManualParameter, unit='s', docstring='In/output time offset from reference point.', vals=vals.Numbers(), initial_value=0. ) if duration_get_cmd is not None: # if duration_get_cmd is given, use it to compute duration # and make duration only gettable self.add_parameter( 'duration', unit='s', get_cmd=duration_get_cmd, docstring='Duration of the in/output.', ) else: self.add_parameter( 'duration', ManualParameter, unit='s', docstring='Duration of the in/output.', vals=vals.Numbers(min_value=0.), initial_value=None ) self.add_parameter( 'trigger_delay', ManualParameter, unit='s', docstring='Time delay between sending a trigger pulse and start of ' 'in/output on the instrument. Usually found in the data sheet.', vals=vals.Numbers(min_value=0.), initial_value=0. ) self.add_parameter( 'trigger_duration', ManualParameter, unit='s', docstring='Duration of the trigger pulse sent to the instrument.', vals=vals.Numbers(min_value=0.), initial_value=100e-9 ) self.add_parameter( 'trigger_holdoff', ManualParameter, unit='s', docstring='Minimum time required before a trigger can be processed ' 'after in/output finishes.', vals=vals.Numbers(min_value=0.), initial_value=0. )
def __init__(self, name, address, timeout=20, **kwargs): """ Initialises the oscilloscope. Args: name (str): Name of the instrument used by QCoDeS address (string): Instrument address as used by VISA timeout (float): visa timeout, in secs. """ super().__init__(name, address, timeout=timeout, terminator='\n', **kwargs) self.connect_message() self.write('*RST') # resets oscilloscope - initialize to known state self.write('*CLS') # clears status registers and output queue # Turns off system headers to allow faster throughput # and immediate access to the data values requested by queries. self.write(':SYSTem:HEADer OFF') # Scope trace boolean self.trace_ready = False # NOTE: The list of implemented parameters is not complete. Refer to # the manual (Infiniium prog guide). # Timebase self.add_parameter( 'timebase_reference', label='Reference of the time axis', get_cmd=':TIMebase:REFerence?', set_cmd=':TIMebase:REFerence {}', vals=Enum('CENT', 'CENTer') # NOTE: needs more values ) self.add_parameter( 'timebase_range', label='Range of the time axis', unit='s', get_cmd=':TIMebase:RANGe?', set_cmd=':TIMebase:RANGe {}', vals=vals.Numbers(2e-9, 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=vals.Numbers(), get_parser=float, ) # Trigger # TODO: add enum for case insesitivity 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(*(['CHANnel{}'.format(i) for i in range(1, 4 + 1)] + ['CHAN{}'.format(i) for i in range(1, 4 + 1)] + ['DIGital{}'.format(i) for i in range(16 + 1)] + ['DIG{}'.format(i) for i in range(16 + 1)] + ['AUX', 'LINE']))) 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(), ) # Acquisition # If sample points, rate and timebase_scale are set in an # incommensurate way, the scope only displays part of the waveform self.add_parameter('acquire_mode', label='acquisition mode', get_cmd='ACQuire:MODE?', set_cmd='ACQuire:MODE {}', vals=Enum('RTIMe', 'ETIMe', 'PDETect', 'HRESolution', 'SEGMented')) self.add_parameter( 'acquire_average', label='average on/off', get_cmd='ACQuire:AVERage?', set_cmd='ACQuire:AVERage {}', val_mapping={ True: 1, False: 0 }, ) self.add_parameter( 'acquire_points', label='sample points', get_cmd='ACQuire:POINts?', get_parser=int, set_cmd=self._cmd_and_invalidate('ACQuire:POINts {}'), 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) self.add_parameter( 'data_source', label='Waveform Data source', get_cmd=':WAVeform:SOURce?', set_cmd=':WAVeform:SOURce {}', vals=Enum(*(['CHANnel{}'.format(i) for i in range(1, 4 + 1)] + ['CHAN{}'.format(i) for i in range(1, 4 + 1)] + ['FUNCtion{}'.format(i) for i in range(1, 16 + 1)] + ['FUNC{}'.format(i) for i in range(1, 16 + 1)] + ['WMEMory{}'.format(i) for i in range(1, 4 + 1)] + ['WMEM{}'.format(i) for i in range(1, 4 + 1)] + ['HISTogram', 'HIST', 'POD1', 'POD2', 'PODALL']))) ## 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_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) # Channels channels = ChannelList(self, "Channels", InfiniiumChannel, snapshotable=False) for i in range(1, 5): channel = InfiniiumChannel(self, 'chan{}'.format(i), i) channels.append(channel) self.add_submodule('ch{}'.format(i), channel) channels.lock() self.add_submodule('channels', channels)
def add_calibration_parameters(self): # First add a function so a user can poll if calibration data has # been set correctly in the VSM in order to correctly use the # orthogonalized parameters self.add_parameter( 'getCalibrationDataAvailable', docstring='Use this to check if the calibration data has been '\ 'set correctly in the VSM. Outputs an integer 0 (False), 1 (True)', get_cmd='CALIBRATIONDATAPATH' + '?', get_parser=int, vals=validators.Ints(0,1) ) # Raw attenuationa and phase # Two input pulses for pulse in ('gaussian', 'derivative'): # Two DACs for dac in ('att', 'phase'): # All channels and modules at once (no getter) var_name = '_{p}_{d}_raw'.format(p=pulse, d=dac) var_scpi = ':{p}:{d}:RAW'.format(p=pulse.upper(), d=dac.upper()) # Individual outputs: per (module, channel) pair for channel in self.channels: for mod in self.modules: doc_dac = 'Raw {d} DAC value (0--65535) for the {p} ' \ 'input of channel {c} ' \ 'of module {m}.'.format(p=pulse, d=dac, c=channel, m=mod) ch_name = '_mod{m}_ch{c}'.format(m=mod, c=channel) ch_scpi = ':MODULE{m}:CHANNEL{c}'.format(m=mod, c=channel) scpi_name = 'CALIBRATION' + ch_scpi + var_scpi self.add_parameter( ch_name + var_name, label=ch_name + var_name, docstring=doc_dac, get_cmd=scpi_name + '?', set_cmd=scpi_name + ' {}', get_parser=int, set_parser=int, vals=validators.Numbers(min_value=0, max_value=2**16-1) ) # orthogonalized attenuation and phase # Two input pulses for pulse in ('gaussian', 'derivative'): for channel in self.channels: for mod in self.modules: ch_name = 'mod{m}_ch{c}'.format(m=mod, c=channel) ch_scpi = ':MODULE{m}:CHANNEL{c}'.format(m=mod, c=channel) doc_var = 'Attenuation value (in dB) for the {p} ' \ 'input of channel {c} ' \ 'of module {m}.\nN.B. Safe range: '\ '0.1<=v<=1.0'.format(p=pulse, c=channel, m=mod) var_name = '_'+ch_name + '_{p}_att_db'.format(p=pulse) var_scpi = ch_scpi + ':{p}:ATTENUATION:DB'.format(p=pulse.upper()) scpi_name = 'CALIBRATION' + var_scpi self.add_parameter(var_name, docstring=doc_var, get_cmd=scpi_name + '?', set_cmd=scpi_name + ' {}', unit='dB', get_parser=float, vals=validators.Numbers()) doc_var = 'Amplitude value (linear) for the {p} ' \ 'input of channel {c} ' \ 'of module {m}.'.format(p=pulse, c=channel, m=mod) var_name = ch_name + '_{p}_amp'.format(p=pulse) var_scpi = ch_scpi + ':{p}:ATTENUATION:LIN'.format(p=pulse.upper()) scpi_name = 'CALIBRATION' + var_scpi self.add_parameter(var_name, docstring=doc_var, get_cmd=scpi_name + '?', set_cmd=scpi_name + ' {}', get_parser=float, vals=validators.Numbers(min_value=0.1, max_value=1.0)) doc_var = 'Phase value (in rad) for the {p} ' \ 'input of channel {c} ' \ 'of module {m}.'.format(p=pulse, c=channel, m=mod) var_name = '_' + ch_name + '_{p}_phs_rad'.format(p=pulse) var_scpi = ch_scpi + ':{p}:PHASE:RAD'.format(p=pulse.upper()) scpi_name = 'CALIBRATION' + var_scpi self.add_parameter(var_name, docstring=doc_var, get_cmd=scpi_name + '?', set_cmd=scpi_name + ' {}', unit='rad', get_parser=float, vals=validators.Numbers()) doc_var = 'Phase value (in deg) for the {p} ' \ 'input of channel {c} ' \ 'of module {m}.'.format(p=pulse, c=channel, m=mod) var_name = ch_name + '_{p}_phase'.format(p=pulse) var_scpi = ch_scpi + ':{p}:PHASE:DEG'.format(p=pulse.upper()) scpi_name = 'CALIBRATION' + var_scpi self.add_parameter(var_name, docstring=doc_var, get_cmd=scpi_name + '?', set_cmd=scpi_name + ' {}', unit='deg', get_parser=float, vals=validators.Numbers(-125,45))
def __init__( self, name: str, device_type: str, readout_methods: Optional[Dict[str, qc.Parameter]] = None, gate_parameters: Optional[Dict[int, Any]] = None, ohmic_parameters: Optional[Dict[int, Any]] = None, sensor_parameters: Optional[Dict[int, Any]] = None, measurement_options: Optional[Dict[str, Dict[str, Any]]] = None, sensor_side: str = "left", initial_valid_ranges: Optional[vltg_rngs_tp] = None, normalization_constants: Optional[nrm_cnst_tp] = None, ) -> None: super().__init__(name) super().add_parameter( name="device_type", label="device type", docstring="", set_cmd=None, get_cmd=None, initial_value=device_type, vals=vals.Strings(), ) all_meths = nt.config['core']['readout_methods'] if readout_methods is not None: assert list(set(all_meths).intersection(readout_methods.keys())) else: readout_methods = {} self._readout_methods = readout_methods super().add_parameter( name="readout_methods", label=f"{name} readout methods", docstring="readout methods to use for measurements", set_cmd=self.set_readout_methods, get_cmd=self.get_readout_methods, initial_value=readout_methods, vals=vals.Dict(), ) self._measurement_options = measurement_options super().add_parameter( name="measurement_options", label=f"{name} measurement options", docstring="readout methods to use for measurements", set_cmd=self.set_measurement_options, get_cmd=self.get_measurement_options, initial_value=measurement_options, vals=vals.Dict(), ) super().add_parameter( name="sensor_side", label="sensor side", docstring="side where the sensor is located", set_cmd=None, get_cmd=None, initial_value=sensor_side, vals=vals.Enum("left", "right"), ) self.layout = nt.config["device"][self.device_type()] self.gates: List[Gate] = [] self.sensor_gates: List[Gate] = [] self.ohmics: List[Ohmic] = [] required_parameter_fields = ['channel_id', 'dac_instrument'] if gate_parameters is not None: for layout_id, gate_param in gate_parameters.items(): for required_param in required_parameter_fields: assert gate_param.get(required_param) is not None alias = self.layout[layout_id] gate_param['layout_id'] = layout_id gate_param['use_ramp'] = True gate = Gate( parent=self, name=alias, **gate_param, ) super().add_submodule(alias, gate) self.gates.append(gate) # if self.sensor_side() == "right": # self.outer_barriers.reverse() # self.plungers.reverse() if sensor_parameters is not None: for layout_id, sens_param in sensor_parameters.items(): for required_param in required_parameter_fields: assert sens_param.get(required_param) is not None alias = self.layout[layout_id] sens_param['layout_id'] = layout_id sens_param['use_ramp'] = True gate = Gate( parent=self, name=alias, **sens_param, ) super().add_submodule(alias, gate) self.sensor_gates.append(gate) if ohmic_parameters is not None: for ohmic_id, ohm_param in ohmic_parameters.items(): for required_param in required_parameter_fields: assert ohm_param.get(required_param) is not None alias = f"ohmic_{ohmic_id}" ohm_param['ohmic_id'] = ohmic_id ohmic = Ohmic( parent=self, name=alias, **ohm_param, ) super().add_submodule(alias, ohmic) self.ohmics.append(ohmic) if initial_valid_ranges is None: initial_valid_ranges = {} for gate in self.gates: initial_valid_ranges[gate.layout_id()] = gate.safety_range() self._initial_valid_ranges: vltg_rngs_tp = {} super().add_parameter( name="initial_valid_ranges", label="initial valid ranges", docstring="", set_cmd=self.set_initial_valid_ranges, get_cmd=self.get_initial_valid_ranges, initial_value=initial_valid_ranges, vals=vals.Dict(), ) super().add_parameter( name="quality", label="device quality", docstring="", set_cmd=None, get_cmd=None, initial_value=0, vals=vals.Numbers(), ) if normalization_constants is not None: self._normalization_constants = normalization_constants else: self._normalization_constants = { key: (0, 1) for key in ["dc_current", "rf", "dc_sensor"] } super().add_parameter( name="normalization_constants", label="open circuit signal", docstring=("Signal measured with all gates at zero. Used as " "normalization during data post processing"), set_cmd=self.set_normalization_constants, get_cmd=self.get_normalization_constants, initial_value=self._normalization_constants, vals=vals.Dict(), )
def __init__(self, name, address, step_attenuator=False, **kwargs): super().__init__(name, address, **kwargs) # Only listed most common spellings idealy want a # .upper val for Enum or string on_off_validator = vals.Enum('on', 'On', 'ON', 'off', 'Off', 'OFF') on_off_mapping = create_on_off_val_mapping(1, 0) self.add_parameter(name='frequency', label='Frequency', unit='Hz', get_cmd='FREQ:CW?', set_cmd='FREQ:CW' + ' {:.4f}', get_parser=float, set_parser=float, vals=vals.Numbers(1e5, 20e9), docstring='Adjust the RF output frequency') self.add_parameter(name='frequency_offset', label='Frequency offset', unit='Hz', get_cmd='FREQ:OFFS?', set_cmd='FREQ:OFFS {}', get_parser=float, vals=Numbers(min_value=-200e9, max_value=200e9)) self.add_parameter('frequency_mode', label='Frequency mode', set_cmd='FREQ:MODE {}', get_cmd='FREQ:MODE?', get_parser=lambda s: s.strip(), vals=vals.Enum('FIX', 'CW', 'SWE', 'LIST')) self.add_parameter(name='phase', label='Phase', unit='deg', get_cmd='PHASE?', set_cmd='PHASE' + ' {:.8f}', get_parser=self.rad_to_deg, set_parser=self.deg_to_rad, vals=vals.Numbers(-180, 180)) self.add_parameter(name='power', label='Power', unit='dBm', get_cmd='POW:AMPL?', set_cmd='POW:AMPL' + ' {:.4f}', get_parser=float, set_parser=float, vals=vals.Numbers(-130, 25)) # self.add_parameter('status', self.add_parameter( 'rf_output', ### MLu edit 2020-04-07 Instrument driver looks for key 'rf_output' get_cmd=':OUTP?', set_cmd='OUTP {}', get_parser=parse_on_off, vals=on_off_validator) self.add_parameter(name='modulation_rf_enabled', get_cmd='OUTP:MOD?', set_cmd='OUTP:MOD {}', val_mapping={ 'on': 1, 'off': 0 }) # val_mapping=on_off_mapping) self.add_parameter( 'IQmodulator_enabled', get_cmd='DM:STATe?', set_cmd='DM:STATe {}', val_mapping=on_off_mapping, docstring= 'Enables or disables the internal I/Q modulator. Source can be external or internal.' ) for source in [1, 2]: self.add_parameter(f'IQsource{source}', get_cmd=f'DM:SOUR{source}?', set_cmd=f'DM:SOUR{source} {{}}', get_parser=lambda s: s.strip(), vals=vals.Enum('OFF', 'EXT', 'EXT600', 'INT'), docstring=IQsource_docstring) self.add_parameter(f'IQadjustments_enabled', get_cmd=f'DM:IQAD?', set_cmd=f'DM:IQAD {{}}', val_mapping=on_off_mapping, docstring='Enable or disable IQ adjustments') IQoffset_parameters = dict(get_parser=float, set_parser=float, vals=vals.Numbers(-100, 100)) self.add_parameter(f'I_offset', get_cmd=f'DM:IQAD:IOFF?', set_cmd=f'DM:IQAD:IOFF {{}}', **IQoffset_parameters, docstring='I channel offset in percentage') self.add_parameter(f'Q_offset', get_cmd=f'DM:IQAD:QOFF?', set_cmd=f'DM:IQAD:QOFF {{}}', **IQoffset_parameters, docstring='Q channel offset in percentage') self.add_parameter(f'IQ_quadrature', get_cmd=f'DM:IQAD:QSK?', set_cmd=f'DM:IQAD:QSK {{}}', get_parser=float, set_parser=float, docstring='IQ quadrature offset', unit='deg') self.add_parameter(f'pulse_modulation_enabled', get_cmd=f'PULM:STATe?', set_cmd=f'PULM:STATe {{}}', val_mapping=on_off_mapping, docstring='Enable or disable pulse modulation path') self.add_parameter(f'pulse_modulation_source', get_cmd=f'PULM:SOURce?', set_cmd=f'PULM:SOURce {{}}', get_parser=lambda s: s.strip(), vals=vals.Enum('EXT', 'INT', 'SCAL')) self.add_parameter( f'wideband_amplitude_modulation_enabled', get_cmd=f'AM:WID:STATe?', set_cmd=f'AM:WID:STATe {{}}', val_mapping=on_off_mapping, docstring= 'This command enables or disables wideband amplitude modulation') self.connect_message()
def __init__(self, name, setup_folder, address, reset=False, clock=1e9, numpoints=1000, timeout=180, **kwargs): ''' Initializes the AWG5014. Input: name (string) : name of the instrument setup_folder (string) : folder where externally generate seqs are stored address (string) : GPIB or ethernet address reset (bool) : resets to default values, default=false numpoints (int) : sets the number of datapoints timeout (float) : visa timeout, in secs. long default (180) to accommodate large waveforms Output: None ''' super().__init__(name, address, timeout=timeout, **kwargs) self._address = address self._values = {} self._values['files'] = {} self._clock = clock self._numpoints = numpoints self.add_function('reset', call_cmd='*RST') self.add_parameter('state', get_cmd=self.get_state) self.add_parameter('run_mode', get_cmd='AWGC:RMOD?', set_cmd='AWGC:RMOD ' + '{}', vals=vals.Enum('CONT', 'TRIG', 'SEQ', 'GAT')) # Trigger parameters # # ! Warning this is the same as run mode, do not use! exists # Solely for legacy purposes self.add_parameter('trigger_mode', get_cmd='AWGC:RMOD?', set_cmd='AWGC:RMOD ' + '{}', vals=vals.Enum('CONT', 'TRIG', 'SEQ', 'GAT')) self.add_parameter('trigger_impedance', label='Trigger impedance (Ohm)', units='Ohm', get_cmd='TRIG:IMP?', set_cmd='TRIG:IMP ' + '{}', vals=vals.Enum(50, 1000), get_parser=float) self.add_parameter('trigger_level', units='V', label='Trigger level (V)', get_cmd='TRIG:LEV?', set_cmd='TRIG:LEV ' + '{:.3f}', vals=vals.Numbers(-5, 5), get_parser=float) self.add_parameter('trigger_slope', get_cmd='TRIG:SLOP?', set_cmd='TRIG:SLOP ' + '{}', vals=vals.Enum('POS', 'NEG')) # , # get_parser=self.parse_int_pos_neg) self.add_parameter('trigger_source', get_cmd='TRIG:source?', set_cmd='TRIG:source ' + '{}', vals=vals.Enum('INT', 'EXT')) # Event parameters # self.add_parameter('event_polarity', get_cmd='EVEN:POL?', set_cmd='EVEN:POL ' + '{}', vals=vals.Enum('POS', 'NEG')) self.add_parameter('event_impedance', label='Event impedance (Ohm)', get_cmd='EVEN:IMP?', set_cmd='EVEN:IMP ' + '{}', vals=vals.Enum(50, 1000), get_parser=float) self.add_parameter('event_level', label='Event level (V)', get_cmd='EVEN:LEV?', set_cmd='EVEN:LEV ' + '{:.3f}', vals=vals.Numbers(-5, 5), get_parser=float) self.add_parameter('event_jump_timing', get_cmd='EVEN:JTIM?', set_cmd='EVEN:JTIM {}', vals=vals.Enum('SYNC', 'ASYNC')) self.add_parameter('clock_freq', label='Clock frequency (Hz)', get_cmd='SOUR:FREQ?', set_cmd='SOUR:FREQ ' + '{}', vals=vals.Numbers(1e6, 1.2e9), get_parser=float) self.add_parameter('numpoints', label='Number of datapoints per wave', get_cmd=self._do_get_numpoints, set_cmd=self._do_set_numpoints, vals=vals.Ints(100, int(1e9))) self.add_parameter('setup_filename', get_cmd='AWGC:SNAM?') # set_cmd=self.do_set_setup_filename, # vals=vals.Strings()) # set function has optional args and therefore # does not work with QCodes # Channel parameters # for i in range(1, 5): amp_cmd = 'SOUR{}:VOLT:LEV:IMM:AMPL'.format(i) offset_cmd = 'SOUR{}:VOLT:LEV:IMM:OFFS'.format(i) state_cmd = 'OUTPUT{}:STATE'.format(i) waveform_cmd = 'SOUR{}:WAV'.format(i) # Set channel first to ensure sensible sorting of pars self.add_parameter('ch{}_state'.format(i), label='Status channel {}'.format(i), get_cmd=state_cmd + '?', set_cmd=state_cmd + ' {}', vals=vals.Ints(0, 1)) self.add_parameter('ch{}_amp'.format(i), label='Amplitude channel {} (Vpp)'.format(i), units='Vpp', get_cmd=amp_cmd + '?', set_cmd=amp_cmd + ' {:.6f}', vals=vals.Numbers(0.02, 4.5), get_parser=float) self.add_parameter('ch{}_offset'.format(i), label='Offset channel {} (V)'.format(i), units='V', get_cmd=offset_cmd + '?', set_cmd=offset_cmd + ' {:.3f}', vals=vals.Numbers(-.1, .1), get_parser=float) self.add_parameter('ch{}_waveform'.format(i), label='Waveform channel {}'.format(i), get_cmd=waveform_cmd + '?', set_cmd=waveform_cmd + ' "{}"', vals=vals.Strings(), get_parser=parsestr) # Marker channels for j in range(1, 3): m_del_cmd = 'SOUR{}:MARK{}:DEL'.format(i, j) m_high_cmd = 'SOUR{}:MARK{}:VOLT:LEV:IMM:HIGH'.format(i, j) m_low_cmd = 'SOUR{}:MARK{}:VOLT:LEV:IMM:LOW'.format(i, j) self.add_parameter( 'ch{}_m{}_del'.format(i, j), label='Channel {} Marker {} delay (ns)'.format(i, j), get_cmd=m_del_cmd + '?', set_cmd=m_del_cmd + ' {:.3f}e-9', vals=vals.Numbers(0, 1), get_parser=float) self.add_parameter( 'ch{}_m{}_high'.format(i, j), label='Channel {} Marker {} high level (V)'.format(i, j), get_cmd=m_high_cmd + '?', set_cmd=m_high_cmd + ' {:.3f}', vals=vals.Numbers(-2.7, 2.7), get_parser=float) self.add_parameter( 'ch{}_m{}_low'.format(i, j), label='Channel {} Marker {} low level (V)'.format(i, j), get_cmd=m_low_cmd + '?', set_cmd=m_low_cmd + ' {:.3f}', vals=vals.Numbers(-2.7, 2.7), get_parser=float) # # Add functions # self.add_function('get_state') # self.add_function('set_event_jump_timing') # self.add_function('get_event_jump_timing') # self.add_function('generate_awg_file') # self.add_function('send_awg_file') # self.add_function('load_awg_file') # self.add_function('get_error') # self.add_function('pack_waveform') # self.add_function('clear_visa') # self.add_function('initialize_dc_waveforms') # # Setup filepaths self.waveform_folder = "Waveforms" self._rem_file_path = "Z:\\Waveforms\\" # NOTE! this directory has to exist on the AWG!! self._setup_folder = setup_folder self.goto_root() self.change_folder(self.waveform_folder) self.set('trigger_impedance', 50) if self.get('clock_freq') != 1e9: logging.warning('AWG clock freq not set to 1GHz') self.connect_message()
def __init__(self, name, address, number=2, **kwargs): """Initializes the Oxford Instruments IPS 120 Magnet Power Supply. Args: name (string) : name of the instrument address (string) : instrument address number (int) : ISOBUS instrument number """ log.debug('Initializing instrument') super().__init__(name, address, **kwargs) self._address = address self._number = number self._values = {} self.visa_handle.set_visa_attribute( visa.constants.VI_ATTR_ASRL_STOP_BITS, visa.constants.VI_ASRL_STOP_TWO) # Add parameters self.add_parameter('mode', get_cmd=self._get_mode, set_cmd=self._set_mode, vals=vals.Ints()) self.add_parameter('mode2', get_cmd=self._get_mode2) self.add_parameter('activity', get_cmd=self._get_activity, set_cmd=self._set_activity, vals=vals.Ints()) self.add_parameter('switch_heater', get_cmd=self._get_switch_heater, set_cmd=self._set_switch_heater, vals=vals.Ints()) self.add_parameter('field_setpoint', unit='T', get_cmd=self._get_field_setpoint, set_cmd=self._set_field_setpoint, vals=vals.Numbers(-8, 8)) self.add_parameter('sweeprate_field', unit='T/min', get_cmd=self._get_sweeprate_field, set_cmd=self._set_sweeprate_field, vals=vals.Numbers(0, 0.524)) self.add_parameter('system_status', get_cmd=self._get_system_status) self.add_parameter('system_status2', get_cmd=self._get_system_status2) self.add_parameter('polarity', get_cmd=self._get_polarity) self.add_parameter('voltage', unit='V', get_cmd=self._get_voltage) self.add_parameter('voltage_limit', unit='V', get_cmd=self._get_voltage_limit) # Find the F field limits MaxField = self.field_setpoint.vals._max_value MinField = self.field_setpoint.vals._min_value MaxFieldSweep = self.sweeprate_field.vals._max_value MinFieldSweep = self.sweeprate_field.vals._min_value # A to B conversion ABconversion = 115.733 / 14 # Ampere per Tesla self.add_parameter('current_setpoint', unit='A', get_cmd=self._get_current_setpoint, set_cmd=self._set_current_setpoint, vals=vals.Numbers(ABconversion * MinField, ABconversion * MaxField)) self.add_parameter('sweeprate_current', unit='A/min', get_cmd=self._get_sweeprate_current, set_cmd=self._set_sweeprate_current, vals=vals.Numbers(ABconversion * MinFieldSweep, ABconversion * MaxFieldSweep)) self.add_parameter('remote_status', get_cmd=self._get_remote_status, set_cmd=self._set_remote_status, vals=vals.Ints()) self.add_parameter('current', unit='A', get_cmd=self._get_current) self.add_parameter('magnet_current', unit='A', get_cmd=self._get_magnet_current) self.add_parameter('field', unit='T', get_cmd=self._get_field) self.add_parameter('persistent_current', unit='A', get_cmd=self._get_persistent_current) self.add_parameter('persistent_field', unit='T', get_cmd=self._get_persistent_field) self.add_parameter('magnet_inductance', unit='H', get_cmd=self._get_magnet_inductance) self.add_parameter('lead_resistance', unit='mOhm', get_cmd=self._get_lead_resistance) self.add_parameter('current_limit_lower', unit='A', get_cmd=self._get_current_limit_lower) self.add_parameter('current_limit_upper', unit='A', get_cmd=self._get_current_limit_upper) self.add_parameter('heater_current', unit='mA', get_cmd=self._get_heater_current) self.add_parameter('trip_field', unit='T', get_cmd=self._get_trip_field) self.add_parameter('trip_current', unit='A', get_cmd=self._get_trip_current) # to handle VisaIOError which occurs at first read try: self.visa_handle.write('@%s%s' % (self._number, 'V')) sleep(100e-3) self._read() except visa.VisaIOError: pass
def __init__(self, name, **kwargs): t0 = time() super().__init__(name, **kwargs) self.add_parameter('frequency', label='Frequency ', unit='Hz', initial_value=5e9, parameter_class=ManualParameter, vals=vals.Numbers()) self.add_parameter('span', label='Span ', unit='Hz', initial_value=.25e6, parameter_class=ManualParameter, vals=vals.Numbers()) self.add_parameter('power', label='Power ', unit='dBm', initial_value=0, parameter_class=ManualParameter, vals=vals.Numbers(max_value=20)) self.add_parameter('ref_lvl', label='Reference power ', unit='dBm', initial_value=0, parameter_class=ManualParameter, vals=vals.Numbers(max_value=20)) self.add_parameter('external_reference', parameter_class=ManualParameter, initial_value=False, vals=vals.Bool()) self.add_parameter('device_type', parameter_class=ManualParameter) self.add_parameter('device_mode', initial_value='sweeping', parameter_class=ManualParameter, vals=vals.Anything()) self.add_parameter('acquisition_mode', parameter_class=ManualParameter, initial_value='average', vals=vals.Enum('average', 'min-max')) self.add_parameter('scale', parameter_class=ManualParameter, initial_value='log-scale', vals=vals.Enum('log-scale', 'lin-scale', 'log-full-scale', 'lin-full-scale')) self.add_parameter('running', parameter_class=ManualParameter, initial_value=False, vals=vals.Bool()) self.add_parameter('decimation', parameter_class=ManualParameter, initial_value=1, vals=vals.Ints(1, 8)) self.add_parameter('bandwidth', label='Bandwidth', unit='Hz', initial_value=0, parameter_class=ManualParameter, vals=vals.Numbers()) # rbw Resolution bandwidth in Hz. RBW can be arbitrary. self.add_parameter('rbw', label='Resolution Bandwidth', unit='Hz', initial_value=1e3, parameter_class=ManualParameter, vals=vals.Numbers()) # vbw Video bandwidth in Hz. VBW must be less than or equal to RBW. # VBW can be arbitrary. For best performance use RBW as the VBW. self.add_parameter('vbw', label='Video Bandwidth', unit='Hz', initial_value=1e3, parameter_class=ManualParameter, vals=vals.Numbers()) self.add_parameter('avg', label='Number of averages', initial_value=2, parameter_class=ManualParameter, vals=vals.Numbers()) t1 = time() print('Initialized SignalHound in %.2fs' % (t1 - t0))
def __init__(self, parent: "Infiniium", name: str, channel: int, **kwargs: Any): """ Initialize an infiniium channel. """ self._channel = channel super().__init__(parent, name, **kwargs) # display self.display = Parameter( name="display", instrument=self, label=f"Channel {channel} display on/off", set_cmd=f"CHAN{channel}:DISP {{}}", get_cmd=f"CHAN{channel}:DISP?", val_mapping=create_on_off_val_mapping(on_val=1, off_val=0), ) # scaling self.offset = Parameter( name="offset", instrument=self, label=f"Channel {channel} offset", set_cmd=f"CHAN{channel}:OFFS {{}}", unit="V", get_cmd=f"CHAN{channel}:OFFS?", get_parser=float, ) self.range = Parameter( name="range", instrument=self, label=f"Channel {channel} range", unit="V", set_cmd=f"CHAN{channel}:RANG {{}}", get_cmd=f"CHAN{channel}:RANG?", get_parser=float, vals=vals.Numbers(), ) # Trigger level self.trigger_level = Parameter( name="trigger_level", instrument=self, label=f"Channel {channel} trigger level", unit="V", set_cmd=f":TRIG:LEV CHAN{channel},{{}}", get_cmd=f":TRIG:LEV? CHAN{channel}", get_parser=float, vals=vals.Numbers(), ) # Trace data self.time_axis = DSOTimeAxisParam( name="time_axis", instrument=self, label="Time", unit="s", xorigin=0.0, xincrement=0.0, points=1, vals=vals.Arrays(shape=(self.parent.acquire_points, )), snapshot_value=False, ) self.trace = DSOTraceParam( name="trace", instrument=self, label=f"Channel {channel} trace", unit="V", channel=self.channel_name, vals=vals.Arrays(shape=(self.parent.acquire_points, )), snapshot_value=False, ) # Measurement subsystem self.add_submodule("measure", BoundMeasurement(self, "measure"))
def __init__(self, parent: 'DG1062', name: str, channel: int): """ Args: parent: The instrument this channel belongs to name (str) channel (int) """ super().__init__(parent, name) self.channel = channel for param, unit in [ ("freq", "Hz"), ("ampl", "V"), ("offset", "V"), ("phase", "deg"), ("sample_rate", "1/s") ]: self.add_parameter( param, unit=unit, get_cmd=partial(self._get_waveform_param, param), set_cmd=partial(self._set_waveform_param, param), ) self.add_parameter( "waveform", get_cmd=partial(self._get_waveform_param, "waveform") ) self.add_parameter( "impedance", get_cmd=f":OUTPUT{channel}:IMP?", set_cmd=f":OUTPUT{channel}:IMP {{}}", unit="Ohm", vals=vals.MultiType( vals.Ints( min_value=DG1062Channel.min_impedance, max_value=DG1062Channel.max_impedance ), vals.Enum("INF", "MIN", "MAX", "HighZ") ), get_parser=(lambda value: "HighZ" if float(value) > DG1062Channel.max_impedance else float(value)), set_parser=lambda value: "INF" if value == "HighZ" else value ) self.add_parameter( "sync", get_cmd=f":OUTPUT{channel}:SYNC?", set_cmd=f"OUTPUT{channel}:SYNC {{}}", vals=vals.Enum(0, 1, "ON", "OFF"), ) self.add_parameter( "polarity", get_cmd=f":OUTPUT{channel}:GAT:POL?", set_cmd=f":OUTPUT{channel}:GAT:POL {{}}", vals=vals.OnOff(), val_mapping={1: 'POSITIVE', 0: 'NEGATIVE'}, ) self.add_parameter( "state", get_cmd=f"OUTPUT{channel}:STATE?", set_cmd=f"OUTPUT{channel}:STATE {{}}", ) self.add_parameter( "duty_cycle", get_cmd=self._get_duty_cycle, set_cmd=self._set_duty_cycle, unit="%", vals=vals.Numbers(min_value=1, max_value=99), docstring=('This functions reads/sets the duty ' 'cycle for a square and pulse wave ' 'since these inherit a duty cycle.\n' 'For other waveforms it will give ' 'the user an error') ) burst = DG1062Burst(cast(DG1062, self.parent), "burst", self.channel) self.add_submodule("burst", burst) # We want to be able to do the following: # >>> help(gd.channels[0].sin) # >>> gd.channels[0].sin(freq=2E3, ampl=1.0, offset=0, phase=0) # We do not use add_function as it is more cumbersome to use. for waveform in self.waveforms: f = partial_with_docstring( self.apply, docstring="Args: " + ", ".join(self.waveform_params[waveform]), waveform=waveform ) setattr(self, waveform.lower(), f) # Retrieve current waveform from device self.waveform()
def __init__(self, name: str, address: str, num_channels: int, timeout: float = 10, **kwargs) -> None: """ Args: name: The name used internally by QCoDeS in the DataSet address: The VISA resource name of the instrument timeout: The VISA timeout time (in seconds) num_channels: Number of channels on the AWG """ self.num_channels = num_channels super().__init__(name, address, timeout=timeout, terminator='\n', **kwargs) # The 'model' value begins with 'AWG' self.model = self.IDN()['model'][3:] if self.model not in ['70001A', '70002A']: raise ValueError('Unknown model type: {}. Are you using ' 'the right driver for your instrument?' ''.format(self.model)) self.add_parameter('current_directory', label='Current file system directory', set_cmd='MMEMory:CDIRectory "{}"', get_cmd='MMEMory:CDIRectory?', vals=vals.Strings()) self.add_parameter('mode', label='Instrument operation mode', set_cmd='INSTrument:MODE {}', get_cmd='INSTrument:MODE?', vals=vals.Enum('AWG', 'FGEN')) ################################################## # Clock parameters self.add_parameter('sample_rate', label='Clock sample rate', set_cmd='CLOCk:SRATe {}', get_cmd='CLOCk:SRATe?', unit='Sa/s', get_parser=float, vals=SRValidator(self)) self.add_parameter('clock_source', label='Clock source', set_cmd='CLOCk:SOURce {}', get_cmd='CLOCk:SOURce?', val_mapping={ 'Internal': 'INT', 'Internal, 10 MHZ ref.': 'EFIX', 'Internal, variable ref.': 'EVAR', 'External': 'EXT' }) self.add_parameter('clock_external_frequency', label='External clock frequency', set_cmd='CLOCk:ECLock:FREQuency {}', get_cmd='CLOCk:ECLock:FREQuency?', get_parser=float, unit='Hz', vals=vals.Numbers(6.25e9, 12.5e9)) for ch_num in range(1, num_channels + 1): ch_name = 'ch{}'.format(ch_num) channel = AWGChannel(self, ch_name, ch_num) self.add_submodule(ch_name, channel) # Folder on the AWG where to files are uplaoded by default self.wfmxFileFolder = "\\Users\\OEM\\Documents" self.seqxFileFolder = "\\Users\\OEM\Documents" self.current_directory(self.wfmxFileFolder) self.connect_message()
def __init__(self, parent: 'DG1062', name: str, channel: int): super().__init__(parent, name) self.channel = channel self.add_parameter( "on", get_cmd=f":SOUR{channel}:BURS?", set_cmd=f":SOUR{channel}:BURS {{}}", vals=vals.Enum(0, 1, "ON", "OFF") ) self.add_parameter( "polarity", get_cmd=f":SOUR{channel}:BURS:GATE:POL?", set_cmd=f":SOUR{channel}:BURS:GATE:POL {{}}", vals=vals.Enum("NORM", "INV") ) self.add_parameter( "period", get_cmd=f":SOUR{channel}:BURS:INT:PER?", set_cmd=f":SOUR{channel}:BURS:INT:PER {{}}", vals=vals.MultiType( vals.Numbers(min_value=3E-6, max_value=500), vals.Enum("MIN", "MAX") ) ) self.add_parameter( "mode", get_cmd=f":SOUR{channel}:BURS:MODE?", set_cmd=f":SOUR{channel}:BURS:MODE {{}}", vals=vals.Enum("TRIG", "INF", "GAT") ) self.add_parameter( "ncycles", get_cmd=f":SOUR{channel}:BURS:NCYC?", set_cmd=f":SOUR{channel}:BURS:NCYC {{}}", vals=vals.Numbers(min_value=1, max_value=500000) ) self.add_parameter( "phase", get_cmd=f":SOUR{channel}:BURS:PHAS?", set_cmd=f":SOUR{channel}:BURS:PHAS {{}}", vals=vals.Numbers(min_value=0, max_value=360) ) self.add_parameter( "time_delay", get_cmd=f":SOUR{channel}:BURS:TDEL?", set_cmd=f":SOUR{channel}:BURS:TDEL {{}}", vals=vals.Numbers(min_value=0) ) self.add_parameter( "trigger_slope", get_cmd=f":SOUR{channel}:BURS:TRIG:SLOP?", set_cmd=f":SOUR{channel}:BURS:TRIG:SLOP {{}}", vals=vals.Enum("POS", "NEG") ) self.add_parameter( "source", get_cmd=f":SOUR{channel}:BURS:TRIG:SOUR?", set_cmd=f":SOUR{channel}:BURS:TRIG:SOUR {{}}", vals=vals.Enum("INT", "EXT", "MAN") ) self.add_parameter( "idle", get_cmd=f":SOUR{channel}:BURST:IDLE?", set_cmd=f":SOUR{channel}:BURST:IDLE {{}}", vals=vals.MultiType( vals.Enum("FPT", "TOP", "BOTTOM", "CENTER"), vals.Numbers() # DIY ) )
def __init__(self, name, address, reset=False, numdacs=16, dac_step=10, dac_delay=.1, safe_version=True, polarity=['BIP', 'BIP', 'BIP', 'BIP'], use_locks=False, **kwargs): ''' Initialzes the IVVI, and communicates with the wrapper Args: name (string) : name of the instrument address (string) : ASRL address reset (bool) : resets to default values, default=false numdacs (int) : number of dacs, multiple of 4, default=16 polarity (string[4]) : list of polarities of each set of 4 dacs choose from 'BIP', 'POS', 'NEG', default=['BIP', 'BIP', 'BIP', 'BIP'] dac_step (float) : max step size for dac parameter dac_delay (float) : delay (in seconds) for dac safe_version (bool) : if True then do not send version commands to the IVVI controller use_locks (bool) : if True then locks are used in the `ask` function of the driver. The IVVI driver is not thread safe, this locking mechanism makes it thread safe at the cost of making the call to ask blocking. ''' t0 = time.time() super().__init__(name, address, **kwargs) if use_locks: self.lock = threading.Lock() else: self.lock = None self.safe_version = safe_version if numdacs % 4 == 0 and numdacs > 0: self._numdacs = int(numdacs) else: raise ValueError('numdacs must be a positive multiple of 4, ' 'not {}'.format(numdacs)) # values based on descriptor self.visa_handle.baud_rate = 115200 self.visa_handle.parity = visa.constants.Parity(1) # odd parity self.visa_handle.write_termination = '' self.visa_handle.read_termination = '' self.add_parameter('version', get_cmd=self._get_version) self.add_parameter('check_setpoints', get_cmd=None, set_cmd=None, initial_value=False, label='Check setpoints', vals=Bool(), docstring=('Whether to check if the setpoint is the' ' same as the current DAC value to ' 'prevent an unnecessary set command.')) # Time to wait before sending a set DAC command to the IVVI self.add_parameter('dac_set_sleep', get_cmd=None, set_cmd=None, initial_value=0.05, label='DAC set sleep', unit='s', vals=Numbers(0), docstring=('When check_setpoints is set to True, ' 'this is the waiting time between the' 'command that checks the current DAC ' 'values and the final set DAC command')) # Minimum time to wait before the read buffer contains data self.add_parameter('dac_read_buffer_sleep', get_cmd=None, set_cmd=None, initial_value=0.025, label='DAC read buffer sleep', unit='s', vals=Numbers(0), docstring=('While receiving bytes from the IVVI, ' 'sleeping is done in multiples of this ' 'value. Change to a lower value for ' 'a shorter minimum time to wait.')) self.add_parameter('dac voltages', label='Dac voltages', get_cmd=self._get_dacs) self.add_function('trigger', call_cmd=self._send_trigger) # initialize pol_num, the voltage offset due to the polarity self.pol_num = np.zeros(self._numdacs) for i in range(int(self._numdacs / 4)): self.set_pol_dacrack(polarity[i], np.arange(1 + i * 4, 1 + (i + 1) * 4), get_all=False) for i in range(1, numdacs + 1): self.add_parameter('dac{}'.format(i), label='Dac {}'.format(i), unit='mV', get_cmd=self._gen_ch_get_func(self._get_dac, i), set_cmd=self._gen_ch_set_func(self._set_dac, i), vals=vals.Numbers( self.pol_num[i - 1], self.pol_num[i - 1] + self.Fullrange), step=dac_step, inter_delay=dac_delay, max_val_age=10) self._update_time = 5 # seconds self._time_last_update = 0 # ensures first call will always update t1 = time.time() # make sure we ignore termination characters # See http://www.ni.com/tutorial/4256/en/#toc2 on Termination Character # Enabled v = self.visa_handle v.set_visa_attribute(visa.constants.VI_ATTR_TERMCHAR_EN, 0) v.set_visa_attribute(visa.constants.VI_ATTR_ASRL_END_IN, 0) v.set_visa_attribute(visa.constants.VI_ATTR_ASRL_END_OUT, 0) v.set_visa_attribute(visa.constants.VI_ATTR_SEND_END_EN, 0) # basic test to confirm we are properly connected try: self.get_all() except Exception as ex: print('IVVI: get_all() failed, maybe connected to wrong port?') print(traceback.format_exc()) print('Initialized IVVI-rack in %.2fs' % (t1 - t0))
def __init__(self, name, address='COM5', spi_module=1, spi_baud=1000000, spi_timeout=1, reset=False, dac_step=10, dac_delay=.1, dac_max_delay=0.2, divider=1000, safe_version=True, use_locks=True, **kwargs): """ Initialzes the D5a, and communicates with the wrapper Args: name (string) : name of the instrument address (string) : ASRL address reset (bool) : resets to default values, default=false dac_step (float) : max step size for dac parameter dac_delay (float) : delay (in seconds) for dac dac_max_delay (float) : maximum delay before emitting a warning """ self.verbose = 1 self.spi_rack = SPI_rack(address, spi_baud, spi_timeout) self.spi_rack.unlock() self.D5a = D5a_module(self.spi_rack, spi_module, reset_voltages=reset) t0 = time.time() super().__init__(name, **kwargs) if use_locks: self.lock = threading.Lock() else: self.lock = None self._numdacs = 16 self.divider = divider self._dacoffset = 1 if divider == 1000: unit = 'mV' elif divider == 1: unit = 'V' else: unit = 'a.u.' for i in range(self._dacoffset, self._numdacs + self._dacoffset): self.add_parameter('dac{}'.format(i), label='dac{} '.format(i), unit=unit, get_cmd=partial(self._get_voltage, i - self._dacoffset), set_cmd=partial(self._set_voltage, i - self._dacoffset), vals=vals.Numbers(-2000, 2000), step=dac_step, delay=dac_delay, max_delay=dac_max_delay, max_val_age=10) t1 = time.time() if self.verbose: print('Initialized %s in %.2fs' % (self.name, t1 - t0))