def add_standard_parameters(self): """ Dummy version, all are manual parameters """ self.parameter_list = self._read_parameters() for parameter in self.parameter_list: name = parameter["name"] del parameter["name"] # Remove these as this is for a Dummy instrument if "get_cmd" in parameter: del parameter["get_cmd"] if "set_cmd" in parameter: del parameter["set_cmd"] if ("vals" in parameter): validator = parameter["vals"] try: val_type = validator["type"] if (val_type == "Bool"): # Bool can naturally only have 2 values, 0 or 1... parameter["vals"] = vals.Ints(0, 1) elif (val_type == "Non_Neg_Number"): # Non negative integers try: if ("range" in validator): # if range key is specified in the parameter, # then, the validator is limited to the # specified min,max values val_min = validator["range"][0] val_max = validator["range"][1] parameter["vals"] = vals.Ints(val_min, val_max) except Exception as e: parameter["vals"] = vals.Ints(0, INT32_MAX) log.warning("Range of validator not set correctly") else: log.warning("Failed to set the validator for the" + " parameter " + name + ", because of a" + " unknown validator type: '" + val_type + "'") except Exception as e: log.warning( "Failed to set the validator for the parameter " + name + ".(%s)", str(e)) try: self.add_parameter(name, parameter_class=ManualParameter, **parameter) except Exception as e: log.warning("Failed to create the parameter " + name + ", because of a unknown keyword in this" + " parameter.(%s)", str(e))
def __init__( self, parent: InstrumentBase, dac_instrument: DACInterface, channel_id: int, ohmic_id: int, name: str = "ohmic", label: str = "ohmic", **kwargs, ) -> None: super().__init__(parent, name) self._dac_instrument = dac_instrument self._dac_channel = self._dac_instrument.nt_channels[channel_id] super().add_parameter( name="channel_id", label=" instrument channel id", set_cmd=None, get_cmd=None, initial_value=channel_id, vals=vals.Ints(0), ) super().add_parameter( name="label", label="ohmic label", set_cmd=self._dac_channel.set_label, get_cmd=self._dac_channel.get_label, initial_value=label, vals=vals.Strings(), ) super().add_parameter( name="ohmic_id", label=self.label() + " ohmic number", set_cmd=None, get_cmd=None, initial_value=ohmic_id, vals=vals.Ints(0), ) super().add_parameter( name="relay_state", label=f"{label} DAC channel relay state", set_cmd=self._dac_channel.set_relay_state, get_cmd=self._dac_channel.get_relay_state, initial_value=self._dac_channel.get_relay_state(), vals=vals.Strings(), )
def import_awg(visa_address, name='awg', timeout=40, station=None): from qcodes.instrument_drivers.tektronix.AWG5014 import Tektronix_AWG5014 awg = Tektronix_AWG5014(name, visa_address, timeout=timeout) awg.add_parameter(name='current_seq', parameter_class=ManualParameter, initial_value=None, label='Uploaded sequence index', vals=vals.Ints()) awg.ch1_m1_high(1) awg.ch1_m2_high(1) awg.ch2_m1_high(1) awg.ch2_m2_high(1) awg.ch3_m1_high(1) awg.ch3_m2_high(1) awg.ch4_m1_high(1) awg.ch4_m2_high(1) awg.ch1_filter(100000000.0) awg.ch2_filter(100000000.0) awg.ch3_filter(100000000.0) awg.ch4_filter(100000000.0) awg.ref_source('EXT') awg.clear_message_queue() if station is not None: station.add_component(awg) logging.info('imported tektronix awg5014c: \'{}\''.format(name)) print('imported tektronix awg5014c: \'{}\''.format(name)) print('-------------------------') return awg
def __init__(self, parent: Instrument, name: str, **kwargs): super().__init__(parent, name, **kwargs) self.add_parameter( 'decimation', ManualParameter, vals=vals.Ints(1), initial_value=1, docstring='The sample rate is reduced by the decimation factor ' 'after filtering.') self.add_parameter('coefficients', ManualParameter, vals=vals.Arrays(), docstring='FIR filter coefficients') self.add_parameter('description', ManualParameter, vals=vals.Strings(), docstring='FIR filter description') self.add_parameter( 'mode', ManualParameter, vals=vals.Enum('full', 'valid'), initial_value='full', docstring='Convolution mode. If `valid`, only points where the ' 'filter and signal overlap completely are returned.') self.coefficients.set(np.array([1.]))
def __init__(self, name, address, timeout=180, num_channels=8, **kwargs): """ Initializes the AWG5014. Args: name (string): name of the instrument address (string): GPIB or ethernet address as used by VISA timeout (float): visa timeout, in secs. long default (180) to accommodate large waveforms num_channels (int): number of channels on the device Returns: None """ super().__init__(name, address, timeout=timeout, num_channels=num_channels, **kwargs) for i in range(1, self.num_channels + 1): resolution_cmd = 'SOURCE{}:DAC:RESOLUTION'.format(i) self.add_parameter('ch{}_resolution'.format(i), label='Resultion for channel {}'.format(i), get_cmd=resolution_cmd + '?', set_cmd=resolution_cmd + ' {}', vals=vals.Ints(0, 17), get_parser=int) # this driver only supports 14-bit resolution (e.g. 2 marker # channels) self.set('ch{}_resolution'.format(i), 14)
def add_standard_parameters(self): """ Function to automatically generate the CC-Light specific functions from the qcodes parameters. The function uses the add_parameter function internally. """ self.parameter_list = self._read_parameters() for parameter in self.parameter_list: name = parameter["name"] del parameter["name"] if ("vals" in parameter): validator = parameter["vals"] try: val_type = validator["type"] if (val_type == "Bool"): parameter["vals"] = vals.Ints(0, 1) parameter['get_parser'] = int elif (val_type == "Non_Neg_Number"): if ("range" in validator): val_min = validator["range"][0] val_max = validator["range"][1] else: val_min = 0 val_max = INT32_MAX parameter["vals"] = vals.PermissiveInts( val_min, val_max) parameter['get_parser'] = int parameter['set_parser'] = int else: log.warning("Failed to set the validator for the" + " parameter " + name + ", because of a" + " unknown validator type: '" + val_type + "'") except Exception as e: log.warning( "Failed to set the validator for the parameter " + name + ".(%s)", str(e)) try: log.info("Adding parameter:") for key, value in parameter.items(): log.info("\t", key, value) log.info("\n") self.add_parameter(name, **parameter) except Exception as e: log.warning( "Failed to create the parameter " + name + ", because of a unknown keyword in this" + " parameter.(%s)", str(e))
def __init__(self, parent: Instrument, name: str, **kwargs): super().__init__(parent, name, **kwargs) self.add_parameter( 'markers', ManualParameter, vals=vals.Ints(0, 2), default_value=0, docstring='Number of bits of digital data per sample.') self.add_parameter( 'out_dtype', ManualParameter, default_value=np.float32, vals=vals.Enum(np.float16, np.float32, np.float64), docstring='Output floating point type for analog data.') self.markers.set(0) self.out_dtype.set(np.float32)
def __init__(self, name: str, label: str = "Couter", **kwargs): hardcoded_kwargs = ["unit", "get_cmd", "set_cmd"] for hck in hardcoded_kwargs: if hck in kwargs: raise ValueError(f'Can not set "{hck}" for an ' "CountParameter.") super().__init__( name, label=label, unit="#", vals=vals.Ints(min_value=0), set_cmd=False, **kwargs, ) self._count = 0
def __init__(self, parent: Instrument, name: str, **kwargs): super().__init__(parent, name, **kwargs) self.add_parameter( 'method', ManualParameter, vals=vals.Enum('one', 'two', 'all'), default_value='one', docstring='Number of synchronization markers to analyze. ' '`one` uses the first marker found as the start marker, ' '`two` allows automatic segment count detection, ' '`all` allows missing trigger detection.') self.add_parameter( 'mask', ManualParameter, vals=vals.Ints(), default_value=0xffff, docstring='Bit mask to extract the desired digital input channel.') self.method.set('one') self.mask.set(0xffff)
def _add_dio_parameters(self): self.add_parameter('dio_mode', unit='', label='DIO input operation mode', get_cmd=self.get_dio_mode, set_cmd=self.set_dio_mode, vals=vals.Enum('MASTER', 'SLAVE'), val_mapping={ 'MASTER': 'MASter', 'SLAVE': 'SLAve' }, docstring=_dio_mode_doc + '\nEffective immediately when sent' ) # FIXME: no way, not a HandshakeParameter # FIXME: handle through SCPI status (once implemented on QWG) self.add_parameter('dio_is_calibrated', unit='', label='DIO calibration status', get_cmd='DIO:CALibrate?', val_mapping={ True: '1', False: '0' }, docstring='Get DIO calibration status\n' 'Result:\n' '\tTrue: DIO is calibrated\n' '\tFalse: DIO is not calibrated') self.add_parameter( 'dio_active_index', unit='', label='DIO calibration index', get_cmd=self.get_dio_active_index, set_cmd=self.set_dio_active_index, get_parser=np.uint32, vals=vals.Ints(0, 20), docstring='Get and set DIO calibration index\n' 'See dio_calibrate() parameter\n' 'Effective immediately when sent' # FIXME: no way, not a HandshakeParameter )
def __init__( self, parent: InstrumentBase, name: str = "node", label: str = "", node_type: Optional[str] = None, n_init: int = 0, v_init: float = 0, ): docstring = """ """ super().__init__(parent, name) self.add_parameter( "node_type", label="node type " + label, unit=None, get_cmd=None, set_cmd=None, initial_value=node_type, vals=vals.Strings(), ) self.add_parameter( "n", label="number of charges " + label, unit=None, set_cmd=self._set_n, get_cmd=self._get_n, initial_value=n_init, vals=vals.Ints(-100000, 100000), ) self.add_parameter( "v", label="voltage node " + label, unit="V", set_cmd=self._set_v, get_cmd=self._get_v, initial_value=v_init, vals=vals.Numbers(-100000, 100000), )
def __init__(self, name, address, timeout=180, num_channels=8, **kwargs): """ Initializes the AWG5014. Args: name (str): name of the instrument address (str): GPIB or ethernet address as used by VISA timeout (float): visa timeout, in secs. long default (180) to accommodate large waveforms num_channels (int): number of channels on the device Returns: None """ warnings.warn('This driver, Tektronix_AWG5200, is deprecated and will ' 'be removed in the future. Please use the AWG5208 driver' ' instead.') super().__init__(name, address, timeout=timeout, num_channels=num_channels, **kwargs) for i in range(1, self.num_channels + 1): resolution_cmd = f'SOURCE{i}:DAC:RESOLUTION' self.add_parameter(f'ch{i}_resolution', label=f'Resultion for channel {i}', get_cmd=resolution_cmd + '?', set_cmd=resolution_cmd + ' {}', vals=vals.Ints(0, 17), get_parser=int) # this driver only supports 14-bit resolution (e.g. 2 marker # channels) self.set(f'ch{i}_resolution', 14)
def __init__( self, parent: InstrumentBase, dac_instrument: DACInterface, channel_id: int, layout_id: int, name: str = "nanotune_gate", label: str = "nanotune gate", line_type: str = "dc_current", safety_range: Tuple[float, float] = (-3, 0), use_ramp: bool = True, ramp_rate: float = 0.1, max_jump: float = 0.05, delay: float = 0.001, fast_readout_source: Optional[InstrumentChannel] = None, **kwargs, ) -> None: """ Args: dac_instrument (Optional[Parameter]): line_type (Optional[str]): min_v (Optional[float]): max_v (Optional[float]): use_ramp (Optional[bool]): ramp_rate (Optional[float]): max_jump (Optional[float]): delay (Optional[float]): Delay in between setting and measuring another parameter """ assert issubclass(dac_instrument.__class__, DACInterface) super().__init__(parent, name) self._dac_instrument = dac_instrument self._dac_channel = self._dac_instrument.nt_channels[channel_id] super().add_parameter( name="channel_id", label="instrument channel id", set_cmd=None, get_cmd=None, initial_value=channel_id, vals=vals.Ints(0), ) super().add_parameter( name="dc_voltage", label=f"{label} dc voltage", set_cmd=self.set_dc_voltage, get_cmd=self._dac_channel.get_dc_voltage, vals=vals.Numbers(*safety_range), ) self.has_ramp = self._dac_channel.supports_hardware_ramp super().add_parameter( name="label", label="gate label", set_cmd=self._dac_channel.set_label, get_cmd=self._dac_channel.get_label, initial_value=label, vals=vals.Strings(), ) qc_safety_range = (safety_range[0] - 0.01, safety_range[1] + 0.01) super().add_parameter( name="safety_range", label=f"{label} DC voltage safety range", set_cmd=self.set_safety_range, get_cmd=self.get_safety_range, initial_value=list(safety_range), vals=vals.Lists(), ) super().add_parameter( name="inter_delay", label=f"{label} inter delay", set_cmd=self._dac_channel.set_inter_delay, get_cmd=self._dac_channel.get_inter_delay, initial_value=delay, vals=vals.Numbers(), ) super().add_parameter( name="post_delay", label=label + " post delay", set_cmd=self._dac_channel.set_post_delay, get_cmd=self._dac_channel.get_post_delay, initial_value=delay, vals=vals.Numbers(), ) super().add_parameter( name="max_jump", label=f"{label} maximum voltage jump", set_cmd=self.set_max_jump, get_cmd=self.get_max_jump, initial_value=max_jump, vals=vals.Numbers(), ) super().add_parameter( name="step", label=f"{label} voltage step", set_cmd=self._dac_channel.set_step, get_cmd=self._dac_channel.get_step, initial_value=max_jump, vals=vals.Numbers(), ) super().add_parameter( name="ramp_rate", label=f"{label} ramp rate", set_cmd=self._dac_channel.set_ramp_rate, get_cmd=self._dac_channel.get_ramp_rate, initial_value=ramp_rate, vals=vals.Numbers(), ) super().add_parameter( name="use_ramp", label=f"{label} ramp setting", set_cmd=self.set_ramp, get_cmd=self.get_ramp, initial_value=use_ramp, vals=vals.Bool(), ) super().add_parameter( name="relay_state", label=f"{label} DAC channel relay state", set_cmd=self._dac_channel.set_relay_state, get_cmd=self._dac_channel.get_relay_state, initial_value=self._dac_channel.get_relay_state(), vals=vals.Strings(), ) super().add_parameter( name="layout_id", label=f"{label} device layout id", set_cmd=None, get_cmd=None, initial_value=layout_id, vals=vals.Ints(0), ) super().add_parameter( name="current_valid_range", label=f"{label} current valid range", set_cmd=self.set_current_valid_range, get_cmd=self.get_current_valid_range, initial_value=[], vals=vals.Lists(), ) super().add_parameter( name="transition_voltage", label=f"{label} transition voltage", set_cmd=self.set_transition_voltage, get_cmd=self.compute_transition_voltage, initial_value=0, vals=vals.Numbers(), ) super().add_parameter( name="amplitude", label=f"{label} sawtooth amplitude", set_cmd=self._dac_channel.set_amplitude, get_cmd=self._dac_channel.get_amplitude, initial_value=0, vals=vals.Numbers(-0.5, 0.5), ) super().add_parameter( name="offset", label=f"{label} sawtooth offset", set_cmd=self._set_offset, get_cmd=self._dac_channel.get_offset, initial_value=0, vals=vals.Numbers(*qc_safety_range), ) super().add_parameter( name="frequency", label=f"{label} sawtooth frequency", set_cmd=self._dac_channel.set_frequency, get_cmd=self._dac_channel.get_frequency, initial_value=0, vals=vals.Numbers(), )
def __init__(self, name, address, **kwargs): super().__init__(name, address, terminator='\n', **kwargs) # Acknowledge type comes back when a command has been sent # It tells us if the machine has understood our command # 0 = command ok - Command accepted and executed # 1 = command error - Command type not excepted # 2 = parameter error - Wrong parameters applied # 3 = receive error - Received failed, send command again. # 4 = not accepted - Illegal data send, ignored. self.add_parameter('latest_ack', GroupParameter, label='Acknowledge type from latest command', vals=vals.Ints(0, 4)) # Status parameter - Gets the system status # 1 = start # 2 = 3He # 3 = 4He # 4 = Normal # 5 = Recovery self.add_parameter('status', GroupParameter, label='System status', vals=vals.Ints(1, 5)) self.status_group = Group([self.latest_ack, self.status], get_parser=self.status_parser, get_cmd='STATUS?') # Led status - Tells us what leds are on or off # 1 = off # 2 = on led_group = [self.latest_ack] for i in range(1, 65): # Create a parameter for each led led_label = f'led_x{i + 100}' self.add_parameter(led_label, GroupParameter, label=f'Led for key x{i+100}', vals=vals.Ints(1, 2)) led_group.append(self[led_label]) # Setup a group to describe the leds (and ack) self.led_group = Group(led_group, get_parser=self.led_status_parser, get_cmd='LEDS?') # Pressure status (raw ADC value) # P1-P7 are normal sensors # P8 is a flow sensor pressure_group = [self.latest_ack] for i in range(1, 9): # Create a parameter for each sensor pressure_label = f'pressure_p{i}' self.add_parameter(pressure_label, GroupParameter, label=f'Pressure sensor p{i}', vals=vals.Ints(0, 999999)) pressure_group.append(self[pressure_label]) # Add all the pressure sensors to a group self.pressure_group = Group(pressure_group, get_parser=self.pressure_status_parser, get_cmd='ADC?') # Pressure settings # P6 low - P6 value at which it stops condensing 4He # P6 high - P6 value at which it stops recovering 4He # P7 low - P7 value at which it stops condensing 3He # P7 high - P7 value at which it stops recovering 3He self.add_parameter('set_p6_low', GroupParameter, label='Low pressure limit on P6', vals=vals.Ints(0, 999999)) self.add_parameter('set_p6_high', GroupParameter, label='High pressure limit on P6', vals=vals.Ints(0, 999999)) self.add_parameter('set_p7_low', GroupParameter, label='Low pressure limit on P7', vals=vals.Ints(0, 999999)) self.add_parameter('set_p7_high', GroupParameter, label='High pressure limit on P7', vals=vals.Ints(0, 999999)) # Add all the pressure limits to a group self.pressure_settings_group = Group( [ self.latest_ack, self.set_p6_low, self.set_p6_high, self.set_p7_low, self.set_p7_high ], get_parser=self.pressure_settings_parser, get_cmd="SETTINGS?", set_cmd= "SETTINGS {set_p6_low},{set_p6_high},{set_p7_low},{set_p7_high}") # Keys on the front panel # 1 = off # 2 = on keys_group = [self.latest_ack] for i in range(1, 65): # Create a parameter for each key key_label = f'key_x{i+100}' self.add_parameter(key_label, GroupParameter, label=f'Status for key x{i+100}', vals=vals.Ints(1, 2)) keys_group.append(self[key_label]) # Add all the keys to a group self.keys_group = Group(keys_group, get_parser=self.keys_status_parser, get_cmd='KEYS?') # Connect to the instrument and get an IDN print('Connect string:', self.ask('ID?'))
def __init__(self, name, address, reset=False): ''' Initializes the AWG5014C, and communicates with the wrapper. Input: name (string) : name of the instrument address (string) : GPIB address reset (bool) : resets to default values, default=False ''' logging.info(__name__ + ' : Initializing instrument AWG5014C') super().__init__(name, address, terminator = '\n') # Add some global constants self._address = address #self.add_parameter('runningstate',flags=Instrument.FLAG_GETSET, type=types.BooleanType) self.add_parameter('DC1output', get_cmd = 'AWGControl:DC1:STATe?', set_cmd = 'AWGControl:DC1:STATe {}', vals = vals.Ints(), get_parser = int) #self.add_parameter('sequence',flags=Instrument.FLAG_GETSET, type=types.StringType) self.add_parameter('AWGmode', set_cmd = 'AWGCONTROL:RMODE {}', get_cmd = 'AWGCONTROL:RMODE?', get_parser = str) self.add_parameter('sequence_length', set_cmd = 'SEQUENCE:LENGTH {}', vals = vals.Ints(), get_parser = int, get_cmd = 'SEQUENCE:LENGTH?' ) self.add_parameter('internal_trigger_rate', get_cmd = 'TRIGGER:SEQUENCE:TIMER?', set_cmd = 'TRIGGER:SEQUENCE:TIMER {}', vals = vals.Numbers(), get_parser = float ) self.add_parameter('ch1offset', get_cmd = 'SOURCE1:VOLTAGE:LEVEL:IMMEDIATE:OFFSET?', set_cmd = 'SOURCE1:VOLTAGE:LEVEL:IMMEDIATE:OFFSET {}', vals = vals.Numbers(), get_parser = float ) self.add_parameter('ch2offset', get_cmd = 'SOURCE2:VOLTAGE:LEVEL:IMMEDIATE:OFFSET?', set_cmd = 'SOURCE2:VOLTAGE:LEVEL:IMMEDIATE:OFFSET {}', get_parser = float, vals = vals.Numbers() ) self.add_parameter('ch3offset', get_cmd = 'SOURCE3:VOLTAGE:LEVEL:IMMEDIATE:OFFSET?', set_cmd = 'SOURCE3:VOLTAGE:LEVEL:IMMEDIATE:OFFSET {}', get_parser = float, vals = vals.Numbers() ) self.add_parameter('ch4offset', get_cmd = 'SOURCE4:VOLTAGE:LEVEL:IMMEDIATE:OFFSET?', set_cmd = 'SOURCE4:VOLTAGE:LEVEL:IMMEDIATE:OFFSET {}', get_parser = float, vals = vals.Numbers() ) self.add_parameter('ch1skew', get_cmd = 'SOURCE1:SKEW?', set_cmd = 'SOURCE1:SKEW {} NS', get_parser = float, vals = vals.Numbers() ) self.add_parameter('ch2skew', get_cmd = 'SOURCE2:SKEW?', set_cmd = 'SOURCE2:SKEW {} NS', get_parser = float, vals = vals.Numbers() ) self.add_parameter('ch3skew', get_cmd = 'SOURCE3:SKEW?', set_cmd = 'SOURCE3:SKEW {} NS', get_parser = float, vals = vals.Numbers() ) self.add_parameter('ch4skew', get_cmd = 'SOURCE4:SKEW?', set_cmd = 'SOURCE4:SKEW {} NS', get_parser = float, vals = vals.Numbers() ) self.add_parameter('ch1amp', get_cmd = 'SOURCE1:VOLTAGE:AMPLITUDE?', set_cmd = 'SOURCE1:VOLTAGE:AMPLITUDE {}', vals = vals.Numbers(), get_parser = float ) self.add_parameter('ch2amp', get_cmd = 'SOURCE2:VOLTAGE:AMPLITUDE?', set_cmd = 'SOURCE2:VOLTAGE:AMPLITUDE {}', vals = vals.Numbers(), get_parser = float ) self.add_parameter('ch3amp', get_cmd = 'SOURCE3:VOLTAGE:AMPLITUDE?', set_cmd = 'SOURCE3:VOLTAGE:AMPLITUDE {}', vals = vals.Numbers(), get_parser = float ) self.add_parameter('ch4amp', get_cmd = 'SOURCE4:VOLTAGE:AMPLITUDE?', set_cmd = 'SOURCE4:VOLTAGE:AMPLITUDE {}', vals = vals.Numbers(), get_parser = float ) self.connect_message() if (reset): self.reset() else: self.get_all()
def __init__(self, name, address, silent=False, **kwargs): """ Args: name (string): The name of the instrument used internally by QCoDeS. Must be unique. address (string): The VISA resource name. silent (Optional[bool]): If True, no connect message is printed. """ super().__init__(name, address, **kwargs) # convenient little helper functions def setcmd(channel, setting): return 'SOURce{}:'.format(channel) + setting + ' {}' def getcmd(channel, setting): return 'SOURce{}:'.format(channel) + setting + '?' def errorparser(rawmssg): """ Parses the error message. Args: rawmssg (str): The raw return value of 'SYSTem:ERRor?' Returns: tuple (int, str): The error code and the error message. """ code = int(rawmssg.split(',')[0]) mssg = rawmssg.split(',')[1].strip().replace('"', '') return code, mssg 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 for chan in [1, 2]: self.add_parameter('ch{}_function_type'.format(chan), label='Channel {} function type'.format(chan), set_cmd=setcmd(chan, 'FUNCtion'), get_cmd=getcmd(chan, 'FUNCtion'), vals=vals.Enum('SIN', 'SQU', 'TRI', 'RAMP', 'PULS', 'PRBS', 'NOIS', 'ARB', 'DC')) self.add_parameter('ch{}_frequency_mode'.format(chan), label='Channel {} frequency mode'.format(chan), set_cmd=setcmd(chan, 'FREQuency:MODE'), get_cmd=getcmd(chan, 'FREQuency:MODE'), vals=vals.Enum('CW', 'LIST', 'SWEEP', 'FIXED')) self.add_parameter( 'ch{}_frequency'.format(chan), label='Channel {} frequency'.format(chan), set_cmd=setcmd(chan, 'FREQuency'), get_cmd=getcmd(chan, 'FREQUency'), get_parser=float, unit='Hz', # TODO: max. freq. actually really tricky vals=vals.Numbers(1e-6, 30e6)) self.add_parameter('ch{}_phase'.format(chan), label='Channel {} phase'.format(chan), set_cmd=setcmd(chan, 'PHASe'), get_cmd=getcmd(chan, 'PHASe'), get_parser=float, unit='deg', vals=vals.Numbers(0, 360)) self.add_parameter('ch{}_amplitude_unit'.format(chan), label='Channel {} amplitude unit'.format(chan), set_cmd=setcmd(chan, 'VOLTage:UNIT'), get_cmd=getcmd(chan, 'VOLTage:UNIT'), vals=vals.Enum('VPP', 'VRMS', 'DBM')) self.add_parameter( 'ch{}_amplitude'.format(chan), label='Channel {} amplitude'.format(chan), set_cmd=setcmd(chan, 'VOLTage'), get_cmd=getcmd(chan, 'VOLTage'), unit='', # see amplitude_unit get_parser=float) self.add_parameter('ch{}_offset'.format(chan), label='Channel {} voltage offset'.format(chan), set_cmd=setcmd(chan, 'VOLTage:OFFSet'), get_cmd=getcmd(chan, 'VOLTage:OFFSet'), unit='V', get_parser=float) self.add_parameter('ch{}_output'.format(chan), label='Channel {} output state'.format(chan), set_cmd='OUTPut{}'.format(chan) + ' {}', get_cmd='OUTPut{}?'.format(chan), val_mapping={ 'ON': 1, 'OFF': 0 }) self.add_parameter('ch{}_ramp_symmetry'.format(chan), label='Channel {} ramp symmetry'.format(chan), set_cmd=setcmd(chan, 'FUNCtion:RAMP:SYMMetry'), get_cmd=getcmd(chan, 'FUNCtion:RAMP:SYMMetry'), get_parser=float, vals=vals.Numbers(0, 100)) # TRIGGER MENU self.add_parameter('ch{}_trigger_source'.format(chan), label='Channel {} trigger source'.format(chan), set_cmd='TRIGger{}:SOURce {}'.format( chan, '{}'), get_cmd='TRIGger{}:SOURce?'.format(chan), vals=vals.Enum('IMM', 'EXT', 'TIM', 'BUS')) self.add_parameter('ch{}_trigger_count'.format(chan), label='Channel {} trigger count'.format(chan), set_cmd='TRIGger{}:COUNt {}'.format(chan, '{}'), get_cmd='TRIGger{}:COUNt?'.format(chan), vals=vals.Ints(1, 1000000), get_parser=partial(val_parser, int)) self.add_parameter('ch{}_trigger_delay'.format(chan), label='Channel {} trigger delay'.format(chan), set_cmd='TRIGger{}:DELay {}'.format(chan, '{}'), get_cmd='TRIGger{}:DELay?'.format(chan), vals=vals.Numbers(0, 1000), get_parser=float, unit='s') # TODO: trigger level doesn't work remotely. Why? self.add_parameter('ch{}_trigger_slope'.format(chan), label='Channel {} trigger slope'.format(chan), set_cmd='TRIGger{}:SLOPe {}'.format(chan, '{}'), get_cmd='TRIGger{}:SLOPe?'.format(chan), vals=vals.Enum('POS', 'NEG')) self.add_parameter('ch{}_trigger_timer'.format(chan), label='Channel {} trigger timer'.format(chan), set_cmd='TRIGger{}:TIMer {}'.format(chan, '{}'), get_cmd='TRIGger{}:TIMer?'.format(chan), vals=vals.Numbers(1e-6, 8000), get_parser=float) # BURST MENU self.add_parameter('ch{}_burst_state'.format(chan), label='Channel {} burst state'.format(chan), set_cmd=setcmd(chan, 'BURSt:STATe'), get_cmd=getcmd(chan, 'BURSt:STATe'), val_mapping={ 'ON': 1, 'OFF': 0 }, vals=vals.Enum('ON', 'OFF')) self.add_parameter('ch{}_burst_mode'.format(chan), label='Channel {} burst mode'.format(chan), set_cmd=setcmd(chan, 'BURSt:MODE'), get_cmd=getcmd(chan, 'BURSt:MODE'), val_mapping={ 'N Cycle': 'TRIG', 'Gated': 'GAT' }, vals=vals.Enum('N Cycle', 'Gated')) self.add_parameter( 'ch{}_burst_ncycles'.format(chan), label='Channel {} burst no. of cycles'.format(chan), set_cmd=setcmd(chan, 'BURSt:NCYCles'), get_cmd=getcmd(chan, 'BURSt:NCYCLes'), get_parser=partial(val_parser, int), vals=vals.MultiType(vals.Ints(1), vals.Enum('MIN', 'MAX', 'INF'))) self.add_parameter( 'ch{}_burst_phase'.format(chan), label='Channel {} burst start phase'.format(chan), set_cmd=setcmd(chan, 'BURSt:PHASe'), get_cmd=getcmd(chan, 'BURSt:PHASe'), vals=vals.Numbers(-360, 360), unit='degrees', get_parser=float) self.add_parameter( 'ch{}_burst_polarity'.format(chan), label='Channel {} burst gated polarity'.format(chan), set_cmd=setcmd(chan, 'BURSt:GATE:POLarity'), get_cmd=getcmd(chan, 'BURSt:GATE:POLarity'), vals=vals.Enum('NORM', 'INV')) self.add_parameter('ch{}_burst_int_period'.format(chan), label=('Channel {}'.format(chan) + ' burst internal period'), set_cmd=setcmd(chan, 'BURSt:INTernal:PERiod'), get_cmd=getcmd(chan, 'BURSt:INTernal:PERiod'), 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.')) self.add_parameter('sync_source', label='Source of sync function', set_cmd='OUTPut:SYNC:SOURce {}', get_cmd='OUTPut:SYNC:SOURce?', val_mapping={ 1: 'CH1', 2: 'CH2' }, vals=vals.Enum(1, 2)) self.add_parameter('sync_output', label='Sync output state', set_cmd='OUTPut:SYNC {}', get_cmd='OUTPut:SYNC?', val_mapping={ 'ON': 1, 'OFF': 0 }, vals=vals.Enum('ON', 'OFF')) self.add_parameter('error', label='Error message', get_cmd='SYSTem:ERRor?', get_parser=errorparser) self.add_function('force_trigger', call_cmd='*TRG') if not silent: self.connect_message()
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, parent: 'DG1062', name: str, channel: int) -> None: """ 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 inheret 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) # Retreive current waveform from device self.waveform()
def __init__(self, name, address=None, **kwargs): ''' Initializes the Keysight_MXA_N9020A, 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_MXA_N9020A') super().__init__(name, address, terminator='\n', **kwargs) self.add_parameter("fstart", get_cmd='FREQ:STAR?', set_cmd='FREQ:STAR {}', vals=vals.Numbers(10), get_parser=float, unit='Hz') self.add_parameter("fstop", get_cmd='FREQ:STOP?', set_cmd='FREQ:STOP {}', vals=vals.Numbers(10), get_parser=float, unit='Hz') self.add_parameter("fcenter", get_cmd='FREQ:CENT?', set_cmd='FREQ:CENT {}', vals=vals.Numbers(10), get_parser=float, unit='Hz') self.add_parameter("fspan", get_cmd='FREQ:SPAN?', set_cmd='FREQ:SPAN {}', vals=vals.Numbers(0), get_parser=float, unit='Hz') self.add_parameter("RBW", get_cmd='BAND?', set_cmd='BAND {}', vals=vals.Numbers(10), get_parser=float, unit='Hz') self.add_parameter("RBW_auto", get_cmd='BAND:AUTO?', set_cmd='BAND:AUTO {}', vals=vals.Ints(0, 1), get_parser=int) self.add_parameter("VBW", get_cmd='BAND:VID?', set_cmd='BAND:VID {}', vals=vals.Numbers(1, 8e6), get_parser=float, unit='Hz') self.add_parameter("VBW_auto", get_cmd='BAND:VID:AUTO?', set_cmd='BAND:VID:AUTO {}', vals=vals.Ints(0, 1), get_parser=int) self.add_parameter("trigger_source", get_cmd='TRIG:SOUR?', set_cmd='TRIG:SOUR {}', vals=vals.Enum('ext1', 'ext2', 'imm'), get_parser=str) self.add_parameter("sweep_time", get_cmd='SWE:TIME?', set_cmd='SWE:TIME {}', vals=vals.Numbers(1e-6, 6000), get_parser=float, unit='s') self.add_parameter("sweep_time_auto", get_cmd='SWE:TIME:AUTO?', set_cmd='SWE:TIME:AUTO {}', vals=vals.Ints(0, 1), get_parser=int) self.add_parameter("sweep_time_auto_rules", get_cmd='SWE:TIME:AUTO:RUL?', set_cmd='SWE:TIME:AUTO:RUL {}', vals=vals.Enum('norm', 'normal', 'accuracy', 'acc', 'sres', 'sresponse'), get_parser=str) self.add_parameter("continuous_measurement", get_cmd='INIT:CONT?', set_cmd='INIT:CONT {}', vals=vals.Ints(0, 1), get_parser=float) self.add_parameter('mode', get_cmd=':INSTRUMENT?', set_cmd=':INSTRUMENT {}') self.add_parameter('avgnum', get_cmd='AVER:COUN?', set_cmd='AVER:COUN {}', get_parser=int, vals=vals.Ints(0, 10000)) #adding trace parameters, only gettable with custom commands below self.add_parameter("trace_1", set_cmd=None, get_cmd=self.do_get_trace_1) self.add_parameter("trace_2", set_cmd=None, get_cmd=self.do_get_trace_2) self.add_parameter("trace_3", set_cmd=None, get_cmd=self.do_get_trace_3) self.add_parameter("trace_4", set_cmd=None, get_cmd=self.do_get_trace_4) self.add_parameter("trace_5", set_cmd=None, get_cmd=self.do_get_trace_5) self.add_parameter("trace_6", set_cmd=None, get_cmd=self.do_get_trace_6) self.connect_message()
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='FGEN:CHANnel{}:FREQuency {{}}'.format(channel), unit='Hz', vals=vals.Numbers(1, 50000000), 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 = None, **kwargs): ''' Initializes the Agilent_E5071C, 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 Agilent_E5071C') 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, 10)), 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() ) 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('PLOG', 'MLOG', 'PHAS', 'GDEL', 'SLIN', 'SLOG', 'SCOM', 'SMIT', 'SADM', 'PLIN', 'POL', 'MLIN', 'SWR', 'REAL', 'IMAG', 'UPH', 'PPH') ) 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('trace', set_cmd = None, get_cmd = self.gettrace) self.add_parameter('SweepData', set_cmd = None, get_cmd = self.getSweepData) self.add_parameter('pdata', set_cmd = None, get_cmd = self.getpdata) 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.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, **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, 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 add_standard_parameters(self): """ Function to automatically generate the QCC specific functions from the qcodes parameters. The function uses the add_parameter function internally. """ self.parameter_list = self._read_parameters() for parameter in self.parameter_list: name = parameter["name"] del parameter["name"] if ("vals" in parameter): validator = parameter["vals"] try: val_type = validator["type"] if (val_type == "Bool"): parameter["vals"] = vals.Ints(0, 1) parameter['get_parser'] = int elif (val_type == "IntArray"): parameter["vals"] = vals.Arrays() parameter['get_parser'] = lambda v: np.array( v.split(','), dtype=int) elif (val_type == "QECDataType"): # The QECDataType assumes a long array of ints in which groups of 6 datapoints are returned. # In this datatype every row corresponds to a timeslot # every column corresponds to a qubit index. parameter["vals"] = vals.Anything() elif (val_type == "Non_Neg_Number"): if ("range" in validator): val_min = validator["range"][0] val_max = validator["range"][1] else: val_min = 0 val_max = INT32_MAX parameter["vals"] = vals.PermissiveInts( val_min, val_max) parameter['get_parser'] = int parameter['set_parser'] = int else: log.warning("Failed to set the validator for the" + " parameter " + name + ", because of a" + " unknown validator type: '" + val_type + "'") except Exception as e: log.warning( "Failed to set the validator for the parameter " + name + ".(%s)", str(e)) try: log.info("Adding parameter:") for key, value in parameter.items(): log.info("\t", key, value) log.info("\n") self.add_parameter(name, **parameter) except Exception as e: log.warning( "Failed to create the parameter " + name + ", because of a unknown keyword in this" + " parameter.(%s)", str(e))
def __init__(self, name, address, number=5, **kwargs): """ Initializes the Oxford Instruments Kelvinox IGH Dilution Refrigerator. Input: 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) self._valve_map = { 1: '9', 2: '8', 3: '7', 4: '11A', 5: '13A', 6: '13B', 7: '11B', 8: '12B', 10: '1', 11: '5', 12: '4', 13: '3', 14: '14', 15: '10', 16: '2', 17: '2A', 18: '1A', 19: '5A', 20: '4A' } # Add parameters self.add_parameter('one_K_pot_temp', unit='K', get_cmd=self._get_one_K_pot_temp) self.add_parameter('mix_chamber_temp', unit='K', get_cmd=self._get_mix_chamber_temp, set_cmd=self._set_mix_chamber_temp) self.add_parameter('G1', unit='mbar', get_cmd=self._get_G1) self.add_parameter('G2', unit='mbar', get_cmd=self._get_G2) self.add_parameter('G3', unit='mbar', get_cmd=self._get_G3) self.add_parameter('P1', unit='mbar', get_cmd=self._get_P1) self.add_parameter('P2', unit='mbar', get_cmd=self._get_P2) self.add_parameter('V6_valve', unit='%', get_cmd=self._get_V6_valve, set_cmd=self._set_V6_valve) self.add_parameter('V12A_valve', unit='%', get_cmd=self._get_V12A_valve, set_cmd=self._set_V12A_valve) self.add_parameter('still_status', get_cmd=self._get_still_status) self.add_parameter('sorb_status', get_cmd=self._get_sorb_status) self.add_parameter('still_power', unit='mW', get_cmd=self._get_still_power, set_cmd=self._set_still_power) self.add_parameter('sorb_temp', unit='K', get_cmd=self._get_sorb_temp, set_cmd=self._set_sorb_temp) self.add_parameter('remote_status', get_cmd=self._get_remote_status, set_cmd=self._set_remote_status, vals=vals.Ints()) for valve in self._valve_map: self.add_parameter('V%s_valve' % self._valve_map[valve], get_cmd=partial( self._get_valve_status, valve=valve), set_cmd=partial(self._set_valve_status, valve=valve))
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 add_parameters(self): ####################################################################### # QWG specific ####################################################################### for i in range(self.device_descriptor.numChannels // 2): ch_pair = i * 2 + 1 sfreq_cmd = 'qutech:output{}:frequency'.format(ch_pair) sph_cmd = 'qutech:output{}:phase'.format(ch_pair) # NB: sideband frequency has a resolution of ~0.23 Hz: self.add_parameter('ch_pair{}_sideband_frequency'.format(ch_pair), parameter_class=HandshakeParameter, unit='Hz', label=('Sideband frequency channel ' + 'pair {} (Hz)'.format(i)), get_cmd=sfreq_cmd + '?', set_cmd=sfreq_cmd + ' {}', vals=vals.Numbers(-300e6, 300e6), get_parser=float) self.add_parameter('ch_pair{}_sideband_phase'.format(ch_pair), parameter_class=HandshakeParameter, unit='deg', label=('Sideband phase channel' + ' pair {} (deg)'.format(i)), get_cmd=sph_cmd + '?', set_cmd=sph_cmd + ' {}', vals=vals.Numbers(-180, 360), get_parser=float) self.add_parameter( 'ch_pair{}_transform_matrix'.format(ch_pair), parameter_class=HandshakeParameter, label=('Transformation matrix channel' + 'pair {}'.format(i)), get_cmd=self._gen_ch_get_func(self._getMatrix, ch_pair), set_cmd=self._gen_ch_set_func(self._setMatrix, ch_pair), # NB range is not a hardware limit vals=vals.Arrays(-2, 2, shape=(2, 2))) for i in range(1, self.device_descriptor.numTriggers + 1): triglev_cmd = 'qutech:trigger{}:level'.format(i) # individual trigger level per trigger input: self.add_parameter('tr{}_trigger_level'.format(i), unit='V', label='Trigger level channel {} (V)'.format(i), get_cmd=triglev_cmd + '?', set_cmd=triglev_cmd + ' {}', vals=self.device_descriptor.mvals_trigger_level, get_parser=float) self.add_parameter('run_mode', get_cmd='AWGC:RMO?', set_cmd='AWGC:RMO ' + '{}', vals=vals.Enum('NONE', 'CONt', 'SEQ', 'CODeword')) # NB: setting mode "CON" (valid SCPI abbreviation) reads back as "CONt" # Channel parameters # for ch in range(1, self.device_descriptor.numChannels + 1): amp_cmd = 'SOUR{}:VOLT:LEV:IMM:AMPL'.format(ch) offset_cmd = 'SOUR{}:VOLT:LEV:IMM:OFFS'.format(ch) state_cmd = 'OUTPUT{}:STATE'.format(ch) waveform_cmd = 'SOUR{}:WAV'.format(ch) output_voltage_cmd = 'QUTEch:OUTPut{}:Voltage'.format(ch) dac_temperature_cmd = 'STATus:DAC{}:TEMperature'.format(ch) gain_adjust_cmd = 'DAC{}:GAIn:DRIFt:ADJust'.format(ch) dac_digital_value_cmd = 'DAC{}:DIGitalvalue'.format(ch) # Set channel first to ensure sensible sorting of pars # Compatibility: 5014, QWG self.add_parameter('ch{}_state'.format(ch), label='Status channel {}'.format(ch), get_cmd=state_cmd + '?', set_cmd=state_cmd + ' {}', val_mapping={ True: '1', False: '0' }, vals=vals.Bool()) self.add_parameter( 'ch{}_amp'.format(ch), parameter_class=HandshakeParameter, label='Channel {} Amplitude '.format(ch), unit='Vpp', docstring='Amplitude channel {} (Vpp into 50 Ohm)'.format(ch), get_cmd=amp_cmd + '?', set_cmd=amp_cmd + ' {:.6f}', vals=vals.Numbers(-1.6, 1.6), get_parser=float) self.add_parameter( 'ch{}_offset'.format(ch), # parameter_class=HandshakeParameter, label='Offset channel {}'.format(ch), unit='V', get_cmd=offset_cmd + '?', set_cmd=offset_cmd + ' {:.3f}', vals=vals.Numbers(-.25, .25), get_parser=float) self.add_parameter('ch{}_default_waveform'.format(ch), get_cmd=waveform_cmd + '?', set_cmd=waveform_cmd + ' "{}"', vals=vals.Strings()) self.add_parameter('status_dac{}_temperature'.format(ch), unit='C', label=('DAC {} temperature'.format(ch)), get_cmd=dac_temperature_cmd + '?', get_parser=float, docstring='Reads the temperature of a DAC.\n' \ +'Temperature measurement interval is 10 seconds\n' \ +'Return:\n float with temperature in Celsius') self.add_parameter('output{}_voltage'.format(ch), unit='V', label=('Channel {} voltage output').format(ch), get_cmd=output_voltage_cmd + '?', get_parser=float, docstring='Reads the output voltage of a channel.\n' \ +'Notes:\n Measurement interval is 10 seconds.\n' \ +' The output voltage will only be read if the channel is disabled:\n' \ +' E.g.: qwg.chX_state(False)\n' \ +' If the channel is enabled it will return an low value: >0.1\n' \ +'Return:\n float in voltage') self.add_parameter('dac{}_gain_drift_adjust'.format(ch), unit='', label=('DAC {}, gain drift adjust').format(ch), get_cmd=gain_adjust_cmd + '?', set_cmd=gain_adjust_cmd + ' {}', vals=vals.Ints(0, 4095), get_parser=int, docstring='Gain drift adjust setting of the DAC of a channel.\n' \ +'Used for calibration of the DAC. Do not use to set the gain of a channel!\n' \ +'Notes:\n The gain setting is from 0 to 4095 \n' \ +' Where 0 is 0 V and 4095 is 3.3V \n' \ +'Get Return:\n Setting of the gain in interger (0 - 4095)\n'\ +'Set parameter:\n Integer: Gain of the DAC in , min: 0, max: 4095') self.add_parameter('_dac{}_digital_value'.format(ch), unit='', label=('DAC {}, set digital value').format(ch), set_cmd=dac_digital_value_cmd + ' {}', vals=vals.Ints(0, 4095), docstring='FOR DEVELOPMENT ONLY: Set a digital value directly into the DAC\n' \ +'Used for testing the DACs.\n' \ +'Notes:\n\tThis command will also set the ' \ +'\tinternal correction matrix (Phase and amplitude) of the channel pair to [0,0,0,0], ' \ +'disabling any influence from the wave memory.' \ +'This will also stop the wave the other channel of the pair!\n\n' \ +'Set parameter:\n\tInteger: Value to write to the DAC, min: 0, max: 4095\n' \ +'\tWhere 0 is minimal DAC scale and 4095 is maximal DAC scale \n') self.add_parameter('status_frontIO_temperature', unit='C', label=('FrontIO temperature'), get_cmd='STATus:FrontIO:TEMperature?', get_parser=float, docstring='Reads the temperature of the frontIO.\n' \ +'Temperature measurement interval is 10 seconds\n' \ +'Return:\n float with temperature in Celsius') self.add_parameter('status_fpga_temperature', unit='C', label=('FPGA temperature'), get_cmd='STATus:FPGA:TEMperature?', get_parser=int, docstring='Reads the temperature of the FPGA.\n' \ +'Temperature measurement interval is 10 seconds\n' \ +'Return:\n float with temperature in Celsius') for cw in range(self.device_descriptor.numCodewords): for j in range(self.device_descriptor.numChannels): ch = j + 1 # Codeword 0 corresponds to bitcode 0 cw_cmd = 'sequence:element{:d}:waveform{:d}'.format(cw, ch) self.add_parameter('codeword_{}_ch{}_waveform'.format(cw, ch), get_cmd=cw_cmd + '?', set_cmd=cw_cmd + ' "{:s}"', vals=vals.Strings()) # Waveform parameters self.add_parameter('WlistSize', label='Waveform list size', unit='#', get_cmd='wlist:size?', get_parser=int) self.add_parameter('Wlist', label='Waveform list', get_cmd=self._getWlist) self.add_parameter('get_system_status', unit='JSON', label=('System status'), get_cmd='SYSTem:STAtus?', vals=vals.Strings(), get_parser=self.JSON_parser, docstring='Reads the current system status. E.q. channel ' \ +'status: on or off, overflow, underdrive.\n' \ +'Return:\n JSON object with system status') # Trigger parameters doc_trgs_log_inp = 'Reads the current input values on the all the trigger ' \ +'inputs.\nReturn:\n uint32 where trigger 1 (T1) ' \ +'is on the Least significant bit (LSB), T2 on the second ' \ +'bit after LSB, etc.\n\n For example, if only T3 is ' \ +'connected to a high signal, the return value is: ' \ +'4 (0b0000100)\n\n Note: To convert the return value ' \ +'to a readable ' \ +'binary output use: `print(\"{0:#010b}\".format(qwg.' \ +'triggers_logic_input()))`' self.add_parameter( 'triggers_logic_input', label='Read triggers input value', get_cmd='QUTEch:TRIGgers:LOGIcinput?', get_parser=np.uint32, # Did not convert to readable # string because a uint32 is more # usefull when other logic is needed docstring=doc_trgs_log_inp) self._add_codeword_parameters() self.add_function('deleteWaveformAll', call_cmd='wlist:waveform:delete all') doc_sSG = "Synchronize both sideband frequency" \ + " generators, i.e. restart them with their defined phases." self.add_function('syncSidebandGenerators', call_cmd='QUTEch:OUTPut:SYNCsideband', docstring=doc_sSG)
def __init__( self, name: str, address: str, timeout: float = 20, channels: int = 4, silence_pyvisapy_warning: bool = False, **kwargs: Any, ): """ Initialises the oscilloscope. Args: name: Name of the instrument used by QCoDeS address: Instrument address as used by VISA timeout: Visa timeout, in secs. channels: The number of channels on the scope. silence_pyvisapy_warning: Don't warn about pyvisa-py at startup """ super().__init__(name, address, timeout=timeout, terminator="\n", **kwargs) self.connect_message() # Check if we are using pyvisa-py as our visa lib and warn users that # this may cause long digitize operations to fail if (self.visa_handle.visalib.library_path == "py" and not silence_pyvisapy_warning): self.log.warning( "Timeout not handled correctly in pyvisa_py. This may cause" " long acquisitions to fail. Either use ni/keysight visalib" " or set timeout to longer than longest expected acquisition" " time.") # switch the response header off else none of our parameters will work self.write(":SYSTem:HEADer OFF") # Then set up the data format used to retrieve waveforms self.write(":WAVEFORM:FORMAT WORD") self.write(":WAVEFORM:BYTEORDER LSBFirst") self.write(":WAVEFORM:STREAMING ON") # Query the oscilloscope parameters # Set sample rate, bandwidth and memory depth limits self._query_capabilities() # Number of channels can't be queried on most older scopes. Use a parameter # for now. self.no_channels = channels # Run state self.run_mode = Parameter( name="run_mode", instrument=self, label="run mode", get_cmd=":RST?", vals=vals.Enum("RUN", "STOP", "SING"), ) # Timing Parameters self.timebase_range = Parameter( name="timebase_range", instrument=self, label="Range of the time axis", unit="s", get_cmd=":TIM:RANG?", set_cmd=":TIM:RANG {}", vals=vals.Numbers(5e-12, 20), get_parser=float, ) self.timebase_position = Parameter( name="timebase_position", instrument=self, label="Offset of the time axis", unit="s", get_cmd=":TIM:POS?", set_cmd=":TIM:POS {}", vals=vals.Numbers(), get_parser=float, ) self.timebase_roll_enabled = Parameter( name="timebase_roll_enabled", instrument=self, label="Is rolling mode enabled", get_cmd=":TIM:ROLL:ENABLE?", set_cmd=":TIM:ROLL:ENABLE {}", val_mapping={ True: 1, False: 0 }, ) # Trigger self.trigger_mode = Parameter( name="trigger_mode", instrument=self, label="Trigger mode", get_cmd=":TRIG:MODE?", ) self.trigger_sweep = Parameter( name="trigger_sweep", instrument=self, label="Trigger sweep mode", get_cmd=":TRIG:SWE?", set_cmd=":TRIG:SWE {}", vals=vals.Enum("AUTO", "TRIG"), ) self.trigger_state = Parameter( name="trigger_state", instrument=self, label="Trigger state", get_cmd=":AST?", vals=vals.Enum("ARM", "TRIG", "ATRIG", "ADONE"), snapshot_value=False, ) # Edge trigger parameters # Note that for now we only support parameterized edge triggers - this may # be something worth expanding. # To set trigger level, use the "trigger_level" parameter in each channel self.trigger_edge_source = Parameter( name="trigger_edge_source", instrument=self, label="Source channel for the edge trigger", get_cmd=":TRIGger:EDGE:SOURce?", set_cmd=":TRIGger:EDGE:SOURce {}", vals=vals.Enum(*([f"CHAN{i}" for i in range(1, 4 + 1)] + [f"DIG{i}" for i in range(16 + 1)] + ["AUX", "LINE"])), ) self.trigger_edge_slope = Parameter( name="trigger_edge_slope", instrument=self, label="slope of the edge trigger", get_cmd=":TRIGger:EDGE:SLOPe?", set_cmd=":TRIGger:EDGE:SLOPe {}", vals=vals.Enum("POS", "POSITIVE", "NEG", "NEGATIVE", "EITH"), ) self.trigger_level_aux = Parameter( name="trigger_level_aux", instrument=self, label="Tirgger level AUX", unit="V", get_cmd=":TRIGger:LEVel? AUX", set_cmd=":TRIGger:LEVel AUX,{}", get_parser=float, vals=vals.Numbers(), ) # Aquisition # If sample points, rate and timebase_scale are set in an # incomensurate way, the scope only displays part of the waveform self.acquire_points = Parameter( name="acquire_points", instrument=self, label="sample points", get_cmd=":ACQ:POIN?", set_cmd=":ACQ:POIN {}", get_parser=int, vals=vals.Numbers(min_value=self.min_pts, max_value=self.max_pts), ) self.sample_rate = Parameter( name="sample_rate", instrument=self, label="sample rate", get_cmd=":ACQ:SRAT?", set_cmd=":ACQ:SRAT {}", unit="Hz", get_parser=float, vals=vals.Numbers(min_value=self.min_srat, max_value=self.max_srat), ) # Note: newer scopes allow a per-channel bandwidth. This is not implemented yet. self.bandwidth = Parameter( name="bandwidth", instrument=self, label="bandwidth", get_cmd=":ACQ:BAND?", set_cmd=":ACQ:BAND {}", unit="Hz", get_parser=float, vals=vals.Numbers(min_value=self.min_bw, max_value=self.max_bw), ) self.acquire_interpolate = Parameter( name="acquire_interpolate", instrument=self, get_cmd=":ACQ:INTerpolate?", set_cmd=":ACQuire:INTerpolate {}", vals=vals.Enum(0, 1, "INT1", "INT2", "INT4", "INT8", "INT16", "INT32"), ) self.acquire_mode = Parameter( name="acquire_mode", instrument=self, label="Acquisition mode", get_cmd="ACQuire:MODE?", set_cmd="ACQuire:MODE {}", vals=vals.Enum( "ETIMe", "RTIMe", "PDETect", "HRESolution", "SEGMented", "SEGPdetect", "SEGHres", ), ) self.average = Parameter( name="average", instrument=self, label="Averages", get_cmd=self._get_avg, set_cmd=self._set_avg, vals=vals.Ints(min_value=1, max_value=10486575), ) # Automatically digitize before acquiring a trace self.auto_digitize: Parameter = Parameter( name="auto_digitize", instrument=self, label="Auto digitize", set_cmd=None, get_cmd=None, val_mapping=create_on_off_val_mapping(), docstring=( "Digitize before each waveform download. " "If you need to acquire from multiple channels simultaneously " "or you wish to acquire with the scope running freely, " "set this value to False."), initial_value=True, ) self.cache_setpoints: Parameter = Parameter( name="cache_setpoints", instrument=self, label="Cache setpoints", set_cmd=None, get_cmd=None, val_mapping=create_on_off_val_mapping(), docstring= ("Cache setpoints. If false, the preamble is queried before each" " acquisition, which may add latency to measurements. If you" " are taking repeated measurements, set this to True and update" " setpoints manually by calling `instr.chX.update_setpoints()`."), initial_value=False, ) # Channels _channels = ChannelList(self, "channels", InfiniiumChannel, snapshotable=False) for i in range(1, self.no_channels + 1): channel = InfiniiumChannel(self, f"chan{i}", i) _channels.append(channel) self.add_submodule(f"ch{i}", channel) self.add_submodule("channels", _channels.to_channel_tuple()) # Functions _functions = ChannelList(self, "functions", InfiniiumFunction, snapshotable=False) for i in range(1, 16 + 1): function = InfiniiumFunction(self, f"func{i}", i) _functions.append(function) self.add_submodule(f"func{i}", function) # Have to call channel list "funcs" here as functions is a # reserved name in Instrument. self.add_submodule("funcs", _functions.to_channel_tuple()) # Submodules meassubsys = UnboundMeasurement(self, "measure") self.add_submodule("measure", meassubsys)
def __init__(self, name, 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()