def __init__(self, parent: 'DG1062', name: str, channel: int) -> None: 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, 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, 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 __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, instrument_name, **kwargs): super().__init__(instrument_name, **kwargs) self._input_channels = { "I": Channel(instrument_name=self.instrument_name(), name="I", input=True), "Q": Channel(instrument_name=self.instrument_name(), name="Q", input=True), "pulse_mod": Channel( instrument_name=self.instrument_name(), name="pulse_mod", input=True ), } self._output_channels = { "RF_out": Channel( instrument_name=self.instrument_name(), name="RF_out", output=True ) } self._channels = { **self._input_channels, **self._output_channels, "sync": Channel( instrument_name=self.instrument_name(), name="sync", output=True ), } self.pulse_implementations = [ SinePulseImplementation( pulse_requirements=[ ("frequency", {"min": 1e6, "max": 40e9}), ("power", {"min": -120, "max": 25}), ("duration", {"min": 100e-9}), ] ), FrequencyRampPulseImplementation( pulse_requirements=[ ("frequency_start", {"min": 1e6, "max": 40e9}), ("frequency_stop", {"min": 1e6, "max": 40e9}), ("power", {"min": -120, "max": 25}), ("duration", {"min": 100e-9}), ] ), ] self.envelope_padding = Parameter( "envelope_padding", unit="s", set_cmd=None, initial_value=0, vals=vals.Numbers(min_value=0, max_value=10e-3), docstring="Padding for any pulses that use IQ modulation. " "This is to ensure that any IQ pulses such as sine waves " "are applied a bit before the pulse starts. The marker pulse " "used for pulse modulation does not use any envelope padding.", ) self.marker_amplitude = Parameter( unit="V", set_cmd=None, initial_value=1.5, docstring="Amplitude of marker pulse used for gating", ) self.fix_frequency = Parameter( set_cmd=None, initial_value=False, vals=vals.Bool(), docstring="Whether to fix frequency to current value, or to " "dynamically choose frequency during setup", ) self.frequency_carrier_choice = Parameter( set_cmd=None, initial_value="center", vals=vals.MultiType(vals.Enum("min", "center", "max"), vals.Numbers()), docstring="The choice for the microwave frequency, This is used if " "pulses with multiple frequencies are used, or if frequency " "modulation is needed. Ignored if fix_frequency = True. " 'Can be either "max", "min", or "center", or a ' "number which is the offset from the center", ) self.frequency = Parameter( unit="Hz", set_cmd=None, initial_value=self.instrument.frequency() ) self.power = Parameter( unit="dBm", set_cmd=None, initial_value=self.instrument.power(), docstring="Power that the microwave source will be set to. " "Set to equal the maximum power of the pulses", ) self.IQ_modulation = Parameter( initial_value=None, vals=vals.Bool(), docstring="Whether to use IQ modulation. Cannot be directly set, but " "is set internally if there are pulses with multiple " "frequencies, self.fix_frequency() is True, or " "self.force_IQ_modulation() is True.", ) self.IQ_channels = Parameter( initial_value='IQ', vals=vals.Enum('IQ', 'I', 'Q'), set_cmd=None, docstring="Which channels to use for IQ modulation." "Double-sideband modulation is used if only 'I' or 'Q' " "is chosen, while single-sideband modulation is used when" "'IQ' is chosen." ) self.force_IQ_modulation = Parameter( initial_value=False, vals=vals.Bool(), set_cmd=None, docstring="Whether to force IQ modulation.", ) self.marker_per_pulse = Parameter( initial_value=True, vals=vals.Bool(), set_cmd=None, docstring='Use a separate marker per pulse. If False, a single ' 'marker pulse is requested for the first pulse to the last ' 'pulse. In this case, envelope padding will be added to ' 'either side of the single marker pulse.' ) # Add parameters that are not set via setup self.additional_settings = ParameterNode() for parameter_name in [ "phase", "maximum_power", "IQ_impairment", "I_leakage", "Q_leakage", "Q_offset", "IQ_ratio", "IQ_wideband", "IQ_crestfactor", "reference_oscillator_source", "reference_oscillator_output_frequency", "reference_oscillator_external_frequency", ]: parameter = getattr(self.instrument, parameter_name) setattr(self.additional_settings, parameter_name, parameter)
def __init__(self, parent: Instrument, name: str, channum: int) -> None: """ Args: parent: The instrument to which the channel is attached. name: The name of the channel channum: The number of the channel in question (1-2) """ super().__init__(parent, name) self._channum = channum def val_parser(parser: type, inputstring: str) -> Union[float, int]: """ 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: parser: Either int or float, what to return in finite cases inputstring: The raw return value """ inputstring = inputstring.strip() if float(inputstring) == 9.9e37: output = float('inf') else: output = float(inputstring) if parser == int: output = parser(output) return output self.model = self._parent.model 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')) max_freq = self._parent._max_freqs[self.model] if self._parent.model in ['33511B', '33512B', '33522B', '33622A']: # FUNC ARB self.add_parameter( 'arb_waveform_fname', label='Channel {} arb waveform filename'.format(channum), set_cmd='SOURce{}:FUNC:ARB {{}}'.format(channum), get_cmd='SOURce{}:FUNC:ARB?'.format(channum), get_parser=str.rstrip, vals=vals.Strings()) self.add_parameter( 'arb_waveform_adv', label='Channel {} arb waveform advance mode'.format(channum), set_cmd='SOURce{}:FUNCtion:ARBitrary:ADVance {{}}'.format( channum), get_cmd='SOURce{}:FUNCtion:ARBitrary:ADVance?'.format(channum), get_parser=str.rstrip, vals=vals.Enum('TRIG', 'SRAT')) self.add_parameter( 'arb_waveform_filter', label='Channel {} arb waveform filter'.format(channum), set_cmd='SOURce{}:FUNCtion:ARBitrary:FILTer {{}}'.format( channum), get_cmd='SOURce{}:FUNCtion:ARBitrary:FILTer?'.format(channum), get_parser=str.rstrip, vals=vals.Enum('NORM', 'STEP', 'OFF')) self.add_parameter( 'arb_waveform_frequency', label='Channel {} arb waveform frequency'.format(channum), set_cmd='SOURce{}:FUNCtion:ARBitrary:FREQuency {{}}'.format( channum), get_cmd='SOURce{}:FUNCtion:ARBitrary:FREQuency?'.format( channum), get_parser=float, unit='Hz', # TODO: max. freq. actually really tricky vals=vals.Numbers(1e-6, max_freq)) self.add_parameter( 'arb_waveform_period', label='Channel {} arb waveform period'.format(channum), set_cmd='SOURce{}:FUNCtion:ARBitrary:PERiod {{}}'.format( channum), get_cmd='SOURce{}:FUNCtion:ARBitrary:PERiod?'.format(channum), get_parser=float, unit='s', vals=vals.Numbers(0)) self.add_parameter( 'arb_waveform_points', label='Channel {} arb waveform number of points'.format( channum), get_cmd='SOURce{}:FUNCtion:ARBitrary:POINts?'.format(channum), get_parser=int) max_rate = self._parent._max_rates[self.model] self.add_parameter( 'arb_waveform_srate', label='Channel {} arb waveform sampling rate'.format(channum), set_cmd='SOURce{}:FUNCtion:ARBitrary:SRATe {{}}'.format( channum), get_cmd='SOURce{}:FUNCtion:ARBitrary:SRATe?'.format(channum), get_parser=float, unit='Sa/s', # TODO: max. rate. actually really tricky vals=vals.Numbers(1e-6, max_rate)) 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, max_freq)) 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)) self.add_parameter( 'pulse_width', label="Channel {} pulse width".format(channum), set_cmd='SOURce{}:FUNCtion:PULSE:WIDTh {{}}'.format(channum), get_cmd='SOURce{}:FUNCtion:PULSE:WIDTh?'.format(channum), get_parser=float, unit='S') # 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_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) # Older models do not have all the fancy trigger options if self._parent.model[2] in ['5', '6']: 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') 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) # TODO: trigger level doesn't work remotely. Why? # 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.'))