class GSG_55(GSG): models = ["GPS", r"GSG-55"] def __init__(self, name, adapter, enableSCPI=True, **kwargs): super(GSG, self).__init__(name, adapter, enableSCPI, **kwargs) self.amplitude_units = 'Vpp' noise_bw = Instrument.control(":SOUR:NOISE:BW?;", "SOUR:NOISE:BW %g", "[GSG-55 ONLY] Noise bandwith, [0.001, 20.46]", strict_range, [0.001, 20.46] ) noise_offset = Instrument.control(":SOUR:NOISE:OFFSET?;", "SOUR:NOISE:OFFSET %g", "[GSG-55 ONLY] Noise frequency offset, [-10.23, 10.23]", strict_range, [-10.23, 10.23] )
class DMM(Meter): models = ["DMM", r"884\dA", r"34410A"] _FUNC = ["CAP", "CONT", "CURR:AC", "CURR:DC", "DIOD", "FRES", "FREQ", "PER", "RES", "TEMP:FRTD", "TEMP:RTD", "VOLT:AC", "VOLT:DC", "VOLT:DC:RAT"] VALID_TYPE_ARGS = ['AC','DC','DC:RAT'] def __init__(self, makemodel, adapter, **kwargs): super(DMM, self).__init__(makemodel, adapter, **kwargs) self._range = 'DEF' self._resolution = 'DEF' def close(self): del self._range del self._resolution mode = Instrument.control('FUNC?"','FUNC "%s"', "FUNCTION", strict_discrete_set, _FUNC) cap = Instrument.measurement("MEAS:CAP? DEF,DEF", "Capacitance, in Farads") def capacitance(self, trig=True): if trig: return float(self.query("MEAS:CAP? %s, %s"%(self._range,self._resolution))) else: return Instrument.configure("CAP") cont = Instrument.measurement("MEAS:CONT?", "Continuity, in Ohms") def continuity(self, trig=True): if trig: return float(self.query("MEAS:CONT?")) else: return Instrument.configure("CONT") diod = Instrument.measurement("MEAS:DIOD?", "Diode voltage, in Volts") def diode(self, trig=True): if trig: return float(self.query("MEAS:DIOD?")) else: return Instrument.configure("DIOD") freq = Instrument.measurement("MEAS:FREQ? DEF,DEF", "Frequency, in Hertz") per = Instrument.measurement("MEAS:PER? DEF,DEF", "Period, in Seconds") def frequency(self, trig=True): if trig: return float(self.query("MEAS:FREQ? %s, %s"%(self._range,self._resolution))) else: return Instrument.configure("FREQ") def period(self, trig=True): if trig: return float(self.query("MEAS:PER? %s, %s"%(self._range,self._resolution))) else: return Instrument.configure("PER") curr_ac = Instrument.measurement("MEAS:CURR:AC? DEF,DEF", "AC current, in Amps") curr_dc = Instrument.measurement("MEAS:CURR:DC? DEF,DEF", "DC current, in Amps") def current(self, trig=True,type='DC'): if type in self.VALID_TYPE_ARGS: if trig: return float(self.query("MEAS:CURR:%s? %s, %s"%(type.upper(),self._range,self._resolution))) else: return Instrument.configure("CURR:%s"%(type.upper())) volt_ac = Instrument.measurement("MEAS:VOLT:AC? DEF,DEF", "AC voltage, in Volts") volt_dc = Instrument.measurement("MEAS:VOLT:DC? DEF,DEF", "DC voltage, in Volts") voltage_ratio = Instrument.measurement("MEAS:VOLT:DC:RAT? DEF,DEF", "DC voltage, in Volts") def voltage(self, trig=True,type='DC'): if type in self.VALID_TYPE_ARGS: if trig: return float(self.query("MEAS:VOLT:%s? %s, %s"%(type.upper(),self._range,self._resolution))) else: return Instrument.configure("VOLT:%s"%(type.upper())) res = Instrument.measurement("MEAS:RES? DEF,DEF", "Resistance, in Ohms") res_4w = Instrument.measurement("MEAS:FRES? DEF,DEF", "Four-wires (remote sensing) resistance, in Ohms") def resistance(self, trig=True,fourwire=False): if trig: if fourwire: return float(self.query("MEAS:TEMP:FRTD? %s, %s"%(self._range,self._resolution))) else: return float(self.query("MEAS:TEMP:RTD? %s, %s"%(self._range,self._resolution))) else: if fourwire: return Instrument.configure("TEMP:FRES") else: return Instrument.configure("TEMP:RES") temp = Instrument.measurement("MEAS:TEMP:RTD?", "Temperature, in ") temp_4w = Instrument.measurement("MEAS:TEMP:FRTD?", "Four-wire Temperature, in ") def temperature(self, trig=True,fourwire=False): if trig: if fourwire: return float(self.query("MEAS:TEMP:FRTD? %s, %s"%(self._range,self._resolution))) else: return float(self.query("MEAS:TEMP:RTD? %s, %s"%(self._range,self._resolution))) else: if fourwire: return Instrument.configure("TEMP:FRTD") else: return Instrument.configure("TEMP:RTD") def getTerminal(self): return Instrument.measurement("ROUT:TERM?", "Determine Front/Rear Terminals") def resolution(self,res='DEF'): if res.upper() in self._LEVELS: self._resolution = res else: try: self._resolution = float(res) except: raise Exception('resolution argument is type (%s) must be float type or valid keyword (%s)'%(type(range),self._LEVELS)) def range(self,range='DEF'): if range.upper() in self._LEVELS: self._range = range else: try: self._range = float(range) except: raise Exception('range argument is type (%s) must be float type or valid keyword (%s)'%(type(range),self._LEVELS))
class PowerMeter(RFInstrument, ChannelizedInstrument): models = ["PM", r"E441[89]B"] SCmodels = ["E4418B"] MCmodels = ["E4419B"] _MATH = ["A", "B", "A-B", "B-A", "A/B", "B/A"] def __init__(self, name, adapter, **kwargs): super(PowerMeter, self).__init__(name, adapter, **kwargs) self.ch1 = PMChannel(1, adapter, self) try: if (self._mdl in self.MCmodels): print("Dual Channel Power Meter Detected!") self._num_channels = 2 self.ch2 = PMChannel(2, adapter, self) self.readDIF = Instrument.measurement( "READ:DIF?", "Power difference, in dB or W") self.readRAT = Instrument.measurement("READ:DIF?", "Power ratio, in dB") except: print("PowerMeter Exception: 2nd channel initialization") def close(self): #ChannelizedInstrument.close(self) del self.ch1 if (self._num_channels == 2): self.ch2.close() self.ch2 = None readDIF = None readRAT = None super(PowerMeter, self).close() def calibrate(self, ch=1, frq=300000000): self.active = ch self.ch1.freq(frq) print("You need to calibrate the Power Meter Sensor!") input() self.ch1.calibrate(1) print("You need to set the Power Meter attenuator offset!") input() self.ch1.autoattenuate() self._atten = self.ch1.offset() print("Offset: ", self._atten) print("Power Meter Channel Calibrated!") input() def freq(self, f=None): if (f == None): return self.value("SENS{}:FREQ?".format(self.active)) elif (isinstance(f, int) or isinstance(f, float) or isinstance(f, str)): self.write("SENS{}:FREQ {}".format(self.active, f)) else: print("INVALID PM FREQ: ", f) def offset(self, offset=None): # MIN DEF MAX UNITS # -100 << ( 0 ) << +100 W / % / dBm / dB if (offset == None): return self.value("CALC{}:GAIN?".format(self.active)) elif (isinstance(offset, int) or isinstance(offset, float)): self.write("CALC{}:GAIN {}".format(self.active, offset)) else: print("INVALID OFFSET: ", offset) def offsetenable(self, offset=None): if (offset == None): return int(self.query("CALC{}:GAIN:STATE?".format(self.active))) elif (offset in self._ONOFF): self.write("CALC{}:GAIN:STATE {}".format(self.active, offset)) else: print("INVALID ENABLE for OFFSET: ", offset) def power(self): return self.value("FETC{}?".format(self.active)) def powerStable(self, timeout=10, delay=0.1, maxtol=0.05): stable = 0 lastpwr = self.value("FETC{}?".format(self.active)) start_time = time.time() while (time.time() - start_time) < timeout: time.sleep(delay) pwr = self.value("FETC{}?".format(self.active)) if (abs(pwr - lastpwr) < maxtol): stable += 1 else: stable = 0 if (stable == 5): return pwr lastpwr = pwr return None def units(self, unit=None): if (unit == None): return self.query("UNIT{}:POW?".format(self.active)) elif (unit in self._UNITS): self.write("UNIT{}:POW {}".format(self.active, unit)) else: print("INVALID UNITS: ", unit) powref = Instrument.control("OUTP:ROSC?", "OUTP:ROSC {}", "Power reference, ON or OFF", strict_discrete_set, [0, 1, "ON", "OFF"])
class ArbGen(SigGen): """ Represents the Hewlett Packard 33120A Arbitrary Waveform Generator and provides a high-level interface for interacting with the instrument.""" models = ["AWG", r"HP\dA", r"335\d\dA"] SHAPES = {'sinusoid':'SIN', 'square':'SQU', 'triangle':'TRI', 'ramp':'RAMP', 'noise':'NOIS', 'dc':'DC', 'user':'******' } def __init__(self, name, adapter, **kwargs): super(SigGen, self).__init__(name, adapter, **kwargs) shape = Instrument.control("SOUR:FUNC:SHAP?", "SOUR:FUNC:SHAP %s", """ A string property that controls the shape of the wave, which can take the values: sinusoid, square, triangle, ramp, noise, dc, and user. """, validator=strict_discrete_set, values = SHAPES, map_values=True ) arb_srate = Instrument.control( "FUNC:ARB:SRAT?", "FUNC:ARB:SRAT %f", """ An floating point property that sets the sample rate of the currently selected arbitrary signal. Valid values are 1 µSa/s to 250 MSa/s. This can be set. """, validator=strict_range, values=[1e-6, 250e6], ) frequency = Instrument.control("SOUR:FREQ?", "SOUR:FREQ %g", """ A floating point property that controls the frequency of the output in Hz. The allowed range depends on the waveform shape and can be queried with :attr:`~.max_frequency` and :attr:`~.min_frequency`. """ ) max_frequency = Instrument.measurement("SOUR:FREQ? MAX", """ Reads the maximum :attr:`~.HP33120A.frequency` in Hz for the given shape """ ) min_frequency = Instrument.measurement("SOUR:FREQ? MIN", """ Reads the minimum :attr:`~.HP33120A.frequency` in Hz for the given shape """ ) amplitude = Instrument.control("SOUR:VOLT?", "SOUR:VOLT %g", """ A floating point property that controls the voltage amplitude of the output signal. The default units are in peak-to-peak Volts, but can be controlled by :attr:`~.amplitude_units`. The allowed range depends on the waveform shape and can be queried with :attr:`~.max_amplitude` and :attr:`~.min_amplitude`. """ ) max_amplitude = Instrument.measurement("SOUR:VOLT? MAX", """ Reads the maximum :attr:`~.amplitude` in Volts for the given shape """ ) min_amplitude = Instrument.measurement("SOUR:VOLT? MIN", """ Reads the minimum :attr:`~.amplitude` in Volts for the given shape """ ) offset = Instrument.control("SOUR:VOLT:OFFS?", "SOUR:VOLT:OFFS %g", """ A floating point property that controls the amplitude voltage offset in Volts. The allowed range depends on the waveform shape and can be queried with :attr:`~.max_offset` and :attr:`~.min_offset`. """ ) max_offset = Instrument.measurement("SOUR:VOLT:OFFS? MAX", """ Reads the maximum :attr:`~.offset` in Volts for the given shape """ ) min_offset = Instrument.measurement( "SOUR:VOLT:OFFS? MIN", """ Reads the minimum :attr:`~.offset` in Volts for the given shape """ ) AMPLITUDE_UNITS = {'Vpp':'VPP', 'Vrms':'VRMS', 'dBm':'DBM', 'default':'DEF'} amplitude_units = Instrument.control("SOUR:VOLT:UNIT?", "SOUR:VOLT:UNIT %s", """ A string property that controls the units of the amplitude, which can take the values Vpp, Vrms, dBm, and default. """, validator=strict_discrete_set, values=AMPLITUDE_UNITS, map_values=True )
class SigGen(RFInstrument): models = ["SG", r"8257D", r"E443\d[CD]"] def __init__(self, name, adapter, **kwargs): super(SigGen, self).__init__(name, adapter, **kwargs) def frequency(self, freq=None, units ="Hz"): if freq == None: return self.ask('FREQ?') elif(isinstance(freq, int) or isinstance(freq, float)): self.write('FREQ ' + str(freq) + units) elif(isinstance(freq, str)): self.write('FREQ ' + freq) else: print("Frequency (" + freq + ") is not int, float or str ") def level(self, ampl=None, units ="dBm"): if ampl == None: return self.ask('POW?') elif(isinstance(ampl, int) or isinstance(ampl, float)): self.write('POW:AMPL ' + str(ampl) + units) elif(isinstance(ampl, str)): self.write('POW:AMPL ' + ampl) else: print("Amplitude (" + ampl + ") is not int, float or str ") def output_state(self, output=None): if output == None: return self.ask('OUTP:STAT?') elif output in self._ONOFF: self.write('OUTP:STAT ' + str(output)) else: print("Output state (" + output + ") not in " + str(self._ONOFF)) def set_frequency_start_stop(self, start, stop): self.write(':SENS1:FREQ:STAR ' + str(start)) self.write(':SENS1:FREQ:STOP ' + str(stop)) def set_frequency_center_span(self, center, span=None): self.write('SENS1:FREQ:CENT ' + str(center)) if not span == None: self.write('SENS1:FREQ:SPAN ' + str(span)) def set_sweep_parameters(self, number_of_points, power): self.write(':SENS1:SWE:POIN ' + str(number_of_points)) self.write(':SOUR1:POW ' + str(power)) rf_en = Instrument.control(":OUTP:STAT?;", "OUTP:STAT %s;", "RF OUTPUT, ON or OFF", strict_discrete_set, ["ON", "OFF"] ) mod_en = Instrument.control(":OUTP:MOD:STAT?;", "OUTP:MOD:STAT %s;", "MOD OUTPUT, ON or OFF", strict_discrete_set, ["ON", "OFF"] ) power = Instrument.control(":POW?;", ":POW %g dBm;", """ A floating point property that represents the amplitude (dBm).""" ) power_offset = Instrument.control(":POW:LEV:IMM:OFFset?;", ":POW:LEV:IMM:OFFset %g DB;", """ A floating point property that represents the amplitude offset (dB). """ ) frequency = Instrument.control(":FREQ?;", ":FREQ %e Hz;", """ A floating point property that represents the output frequency (Hz).""" ) start_frequency = Instrument.control(":SOUR:FREQ:STAR?", ":SOUR:FREQ:STAR %e Hz", """ A floating point property that represents the start frequency (Hz).""" ) center_frequency = Instrument.control(":SOUR:FREQ:CENT?", ":SOUR:FREQ:CENT %e Hz;", """ A floating point property that represents the center frequency (Hz).""" ) stop_frequency = Instrument.control(":SOUR:FREQ:STOP?", ":SOUR:FREQ:STOP %e Hz", """ A floating point property that represents the stop frequency (Hz).""" ) start_power = Instrument.control(":SOUR:POW:STAR?", ":SOUR:POW:STAR %e dBm", """ A floating point property that represents the start power (dBm).""" ) stop_power = Instrument.control(":SOUR:POW:STOP?", ":SOUR:POW:STOP %e dBm", """ A floating point property that represents the stop power (dBm).""" ) dwell_time = Instrument.control(":SOUR:SWE:DWEL1?", ":SOUR:SWE:DWEL1 %.3f", """ A floating point property that represents the settling time (s) at the current frequency or power setting.""" ) step_points = Instrument.control(":SOUR:SWE:POIN?", ":SOUR:SWE:POIN %d", """ An integer number of points in a step sweep.""" ) ######################## # Amplitude modulation # ######################## AMPLITUDE_SOURCES = { 'internal':'INT', 'internal 2':'INT2', 'external':'EXT', 'external 2':'EXT2' } has_amplitude_modulation = Instrument.measurement(":SOUR:AM:STAT?", """ Reads a boolean value that is True if the amplitude modulation is enabled. """, cast=bool ) amplitude_depth = Instrument.control(":SOUR:AM:DEPT?", ":SOUR:AM:DEPT %g", """ A floating point property that controls the amplitude modulation in percent, which can take values from 0 to 100 %. """, validator=truncated_range, values=[0, 100] ) amplitude_source = Instrument.control(":SOUR:AM:SOUR?", ":SOUR:AM:SOUR %s", """ A string property that controls the source of the amplitude modulation signal, which can take the values: 'internal', 'internal 2', 'external', and 'external 2'. """, validator=strict_discrete_set, values=AMPLITUDE_SOURCES, map_values=True ) #################### # Pulse modulation # #################### PULSE_SOURCES = {'internal':'INT', 'external':'EXT', 'scalar':'SCAL'} PULSE_INPUTS = { 'square':'SQU', 'free-run':'FRUN', 'triggered':'TRIG', 'doublet':'DOUB', 'gated':'GATE' } has_pulse_modulation = Instrument.measurement(":SOUR:PULM:STAT?", """ Reads a boolean value that is True if the pulse modulation is enabled. """, cast=bool ) pulse_source = Instrument.control( ":SOUR:PULM:SOUR?", ":SOUR:PULM:SOUR %s", """ A string property that controls the source of the pulse modulation signal, which can take the values: 'internal', 'external', and 'scalar'. """, validator=strict_discrete_set, values=PULSE_SOURCES, map_values=True ) pulse_input = Instrument.control( ":SOUR:PULM:SOUR:INT?", ":SOUR:PULM:SOUR:INT %s", """ A string property that controls the internally generated modulation input for the pulse modulation, which can take the values: 'square', 'free-run', 'triggered', 'doublet', and 'gated'. """, validator=strict_discrete_set, values=PULSE_INPUTS, map_values=True ) pulse_frequency = Instrument.control( ":SOUR:PULM:INT:FREQ?", ":SOUR:PULM:INT:FREQ %g", """ A floating point property that controls the pulse rate frequency in Hertz, which can take values from 0.1 Hz to 10 MHz. """, validator=truncated_range, values=[0.1, 10e6] ) ######################## # Low-Frequency Output # ######################## LOW_FREQUENCY_SOURCES = { 'internal':'INT', 'internal 2':'INT2', 'function':'FUNC', 'function 2':'FUNC2' } lfo_amplitude = Instrument.control( ":SOUR:LFO:AMPL? ", ":SOUR:LFO:AMPL %g VP", """A floating point property that controls the peak voltage (amplitude) of the low frequency output in volts, which can take values from 0-3.5V""", validator=truncated_range, values=[0,3.5] ) lfo_source = Instrument.control( ":SOUR:LFO:SOUR?", ":SOUR:LFO:SOUR %s", """A string property which controls the source of the low frequency output, which can take the values 'internal [2]' for the inernal source, or 'function [2]' for an internal function generator which can be configured.""", validator=strict_discrete_set, values=LOW_FREQUENCY_SOURCES, map_values=True ) def enable_LFO(self, output): """Enables low frequency output""" if output == None: return self.ask('SOUR:LFO:STAT?') elif output in self._ONOFF: self.write('SOUR:LFO:STAT ' + str(output)) else: print("Output state (" + output + ") not in " + str(self._ONOFF)) def config_low_freq_out(self, source='internal', amplitude=3): """ Configures the low-frequency output signal. :param source: The source for the low-frequency output signal. :param amplitude: Amplitude of the low-frequency output """ self.enable_low_freq_out() self.low_freq_out_source = source self.low_freq_out_amplitude = amplitude ####################### # Internal Oscillator # ####################### INTERNAL_SHAPES = { 'sine':'SINE', 'triangle':'TRI', 'square':'SQU', 'ramp':'RAMP', 'noise':'NOIS', 'dual-sine':'DUAL', 'swept-sine':'SWEP' } internal_frequency = Instrument.control( ":SOUR:AM:INT:FREQ?", ":SOUR:AM:INT:FREQ %g", """ A floating point property that controls the frequency of the internal oscillator in Hertz, which can take values from 0.5 Hz to 1 MHz. """, validator=truncated_range, values=[0.5, 1e6] ) internal_shape = Instrument.control( ":SOUR:AM:INT:FUNC:SHAP?", ":SOUR:AM:INT:FUNC:SHAP %s", """ A string property that controls the shape of the internal oscillations, which can take the values: 'sine', 'triangle', 'square', 'ramp', 'noise', 'dual-sine', and 'swept-sine'. """, validator=strict_discrete_set, values=INTERNAL_SHAPES, map_values=True ) def enable(self, output): """ Enables the output of the signal. """ if output == None: return self.ask('OUTPUT?') elif output in self._ONOFF: self.write('OUTPUT ' + str(output)) else: print("Output state (" + output + ") not in " + str(self._ONOFF)) self.write(":OUTPUT ON;") def enable_modulation(self, output): if output == None: return self.ask('OUTPUT:MOD?') elif output in self._ONOFF: self.write('OUTPUT:MOD ' + str(output)) else: print("Output state (" + output + ") not in " + str(self._ONOFF)) def disable_modulation(self): """ Disables the signal modulation. """ self.write(":OUTPUT:MOD OFF;") self.write(":lfo:stat off;") def enable_multitone(self, output): if output == None: return self.ask('RAD:MTON:ARB?') elif output in self._ONOFF: self.write('RAD:MTON:ARB ' + str(output)) else: print("Output state (" + output + ") not in " + str(self._ONOFF)) def set_n_tones(self, n, spacing, units='Hz'): """ TODO: COMMENTS, mutliple returns... combine? """ self.command_value('RAD:MTON:ARB:SET:TABL:FSP', spacing, units) self.command_value('RAD:MTON:ARB:SET:TABL:NTON', n) def config_amplitude_modulation(self, frequency=1e3, depth=100.0, shape='sine'): """ Configures the amplitude modulation of the output signal. :param frequency: A modulation frequency for the internal oscillator :param depth: A linear depth precentage :param shape: A string that describes the shape for the internal oscillator """ self.enable_amplitude_modulation() self.amplitude_source = 'internal' self.internal_frequency = frequency self.internal_shape = shape self.amplitude_depth = depth def enable_AM(self, output): """ Enables amplitude modulation of the output signal. """ if output == None: return self.ask('SOUR:AM:STAT?') elif output in self._ONOFF: self.write('SOUR:AM:STAT ' + str(output)) else: print("Output state (" + output + ") not in " + str(self._ONOFF)) def config_pulse_modulation(self, frequency=1e3, input='square'): """ Configures the pulse modulation of the output signal. :param frequency: A pulse rate frequency in Hertz :param input: A string that describes the internal pulse input """ self.enable_pulse_modulation() self.pulse_source = 'internal' self.pulse_input = input self.pulse_frequency = frequency def enable_PM(self, output): """ Enables pulse modulation of the output signal. """ if output == None: return self.ask('SOUR:PULM:STAT?') elif output in self._ONOFF: self.write('SOUR:PULM:STAT ' + str(output)) else: print("Output state (" + output + ") not in " + str(self._ONOFF)) def enable_retrace(self): self.write(":SOUR:LIST:RETR 1") def disable_retrace(self): self.write(":SOUR:LIST:RETR 0") def config_step_sweep(self): """ Configures a step sweep through frequency """ self.write(":SOUR:FREQ:MODE SWE;" ":SOUR:SWE:GEN STEP;" ":SOUR:SWE:MODE AUTO;") def enable_sweep(self, output=True): if output == None: return self.ask('FREQ:MODE?') elif(output): self.write('FREQ:MODE LIST') elif(not output): self.write('FREQ:MODE CW') else: print("Output state (" + output + ") not in " + str(self._ONOFF)) def single_sweep(self): self.write(":SOUR:TSW") def single_sweep_sdr(self, bool=True): self.command_state('INIT:CONT', not bool) if bool : self.write('INIT:IMM') def set_frequency_sweep(self, start, stop, n, units='Hz', dwell=0.002, direction='UP'): self.command_value('LIST:DIR', direction) self.command_value('SWE:DWEL', dwell) self.command_value('SWE:POIN', n) self.command_value('FREQ:STAR', start, units) self.command_value('FREQ:STOP', stop, units) self.command_value('FREQ:MODE', 'LIST') def start_step_sweep(self): """ Starts a step sweep. """ self.write(":SOUR:SWE:CONT:STAT ON") def stop_step_sweep(self): """ Stops a step sweep. """ self.write(":SOUR:SWE:CONT:STAT OFF")
class LambdaPS(PS): models = ["PS", r"GENH\d\d-\d\d"] def __init__(self, name, adapter, **kwargs): super(LambdaPS, self).__init__(name, adapter, **kwargs) self.write('SYST:ERR:ENABLE') # mode = Instrument.control("SYST:SET?", "SYST:SET %s", "Output state, REM or LOC", # strict_discrete_set, ["REM", "LOC"]) # output = Instrument.control("OUTP:STAT?", "OUTP:STAT %s", "Output state, ON or OFF", # strict_discrete_set, ["ON", "OFF"]) # voltage = Instrument.control("VOLT?", "VOLT %d", "DC voltage, in Volts") # meas_voltage = Instrument.measurement("MEAS:VOLT?", "DC voltage, in Volts") # current = Instrument.control("CURR?", "CURR %d", "DC current, in Amps") # meas_current = Instrument.measurement("MEAS:CURR?", "DC current, in Amps") def cmd_mode(self, mode=None): if mode == None: return self.ask('SYST:SET?') elif mode in self._MODES: self.write('SYST:SET ' + mode) else: print("Mode (" + mode + ") not in " + str(self._MODES)) def output_mode(self): return self.ask('SOUR:MODE?') def output_state(self, output=None): if output == None: return self.ask('OUTP:STAT?') elif output in self._ONOFF: self.write('OUTP:STAT ' + str(output)) else: print("Output state (" + output + ") not in " + str(self._ONOFF)) out_en = Instrument.control(":OUTP:STAT?;", "OUTP:STAT %s;", "OUTPUT, ON or OFF", strict_discrete_set, [0, 1, "ON", "OFF"]) def overcurrent_state(self, output=None): if output == None: return self.ask('SOUR:CURR:PROT:STAT?') elif output in self._ONOFF: self.write('SOUR:CURR:PROT:STAT ' + output) else: print("Output state (" + output + ") not in " + str(self._ONOFF)) curr = Instrument.control("MEAS:CURR?", "SOUR:CURR {}", "Current, Amps") def current(self, c=None, meas=True): if c == None: if meas == True: return self.ask('MEAS:CURR?') else: return self.ask('SOUR:CURR?') else: self.write('SOUR:CURR ' + str(c)) volt = Instrument.control("MEAS:VOLT?", "SOUR:VOLT {}", "Voltage, Volts") def voltage(self, v=None, meas=True): if v == None: if meas == True: return self.ask('MEAS:VOLT?') else: return self.ask('SOUR:VOLT?') else: self.write('SOUR:VOLT ' + str(v)) def overcurrent(self, oc=None): if oc == None: return self.ask('SOUR:CURR:PROT:LEV?') else: self.write('SOUR:CURR:PROT:LEV ' + str(oc)) def overvoltage(self, ov=None): if ov == None: return self.ask('SOUR:VOLT:PROT:LEV?') else: self.write('SOUR:VOLT:PROT:LEV ' + str(ov)) def undervoltage(self, uv=None): if uv == None: return self.ask('SOUR:VOLT:LIM:LOW?') else: self.write('SOUR:VOLT:LIM:LOW ' + str(uv)) def tripped(self): return self.tripped_OVP() or self.tripped_OCP() def tripped_OVP(self): return self.ask('SOUR:VOLT:PROT:TRIP?') def tripped_OCP(self): return self.ask('SOUR:CURR:PROT:TRIP?')
class XantrexPS(PS): models = ["PS", r"HPD\d\d-\d\d"] def __init__(self, name, adapter, **kwargs): nm = ["Xantrex", name[1], name[2]] super(XantrexPS, self).__init__(nm, adapter, **kwargs) def clear(self): """ Resets the instrument to power on state. """ self.write("CLR") curr = Instrument.control("ISET?", "ISET {}", "Current, Amps") def current(self, c=None): if c == None: return self.ask('ISET?') else: self.write('ISET ' + str(c)) def meascurrent(self): return self.ask('IOUT?') def maxcurrent(self, c=None): if c == None: return self.ask('IMAX?') else: self.write('IMAX ' + str(c)) def delay(self, t=None): if t == None: return self.ask('DLY?') else: self.write('DLY ' + str(t)) def fold(self, m=None): if m == None: return self.ask('FOLD?') else: self.write('FOLD ' + str(m)) def hold(self, m=None): if m == None: return self.ask('HOLD?') elif m in self._ONOFF: self.write('HOLD ' + str(m)) else: print("Hold state (" + m + ") not in " + str(self._ONOFF)) def output_state(self, output=None): if output == None: return self.ask('OUT?') elif output in self._ONOFF: self.write('OUT ' + str(output)) else: print("Output state (" + output + ") not in " + str(self._ONOFF)) def overvoltage(self, ov=None): if ov == None: return self.ask('OVSET?') else: self.write('OVSET ' + str(ov)) volt = Instrument.control("VSET?", "VSET {}", "Voltage, Volts") def voltage(self, v=None): if v == None: return self.ask('VSET?') else: self.write('VSET ' + str(v)) def measvoltage(self): return self.ask('VOUT?')
class GSG(Instrument): models = ["GPS", r"GSG-\d\d"] SIGNAL_MODE_LETTER = ["U", "M", "P"] # Unmodulated / Modulated / PRN signal GNSS_LETTER = {'G' : "GPS", 'R': "GLONASS", 'E': "GALILEO", 'C': "BEIDOU", 'J': "QZSS", 'I': "IRNSS", 'S': "SBAS"} SIGNAL_TYPE = ['GPSL1CA','GPSL1P','GPSL1PY','GPSL2P','GPS L2PY', # GPS 'GLOL1', 'GLOL2', # GLONASS 'GALE1', 'GALE5a', 'GALE5b', # GALILEO 'BDSB1', 'BDSB2', # BeiDou 'QZSSL1CA', 'QZSSL1SAIF', 'QZSSL2C', 'QZSSL5', # QZSS 'IRNSSL5' # IRNSS ] ENVIRONMENTS = ['URBAN','SUBURBAN','RURAL','OPEN'] def __init__(self, name, adapter, enableSCPI=True, **kwargs): super(GSG, self).__init__(name, adapter, enableSCPI, **kwargs) status = Instrument.control(":SOUR:ONECHN:CONT?;", "SOUR:ONECHN:CONT %s%s%d;", "Sig Gen execution, START / STOP / ARM", strict_discrete_set, ["START", "STOP", "ARM"] ) sat_id = Instrument.control(":SOUR:ONECHN:SAT?;", "SOUR:ONECHN:SAT %s;", "Satelite ID", ) signal = Instrument.control(":SOUR:ONECHN:SIGNAL?;", "SOUR:ONECHN:SIGNAL %s;", "Signal Type", strict_discrete_set, SIGNAL_TYPE) start = Instrument.control(":SOUR:ONECHN:START?;", "SOUR:ONECHN:START %s;", "Start Time, DD/MM/YYYY hh:mm") ephemeris = Instrument.control(":SOUR:ONECHN:EPH?;", "SOUR:ONECHN:EPH %s;", "Ephemeris, filename") atten = Instrument.control(":OUTP:EXTATT?;", "OUTP:EXTATT %g;", "Attenuation, in dB") ext_ref = Instrument.control(":SOUR:EXTREF?;", "SOUR:EXTREF %s;", "External Reference Clock, ON or OFF", strict_discrete_set, ["ON", "OFF"] ) noise_en = Instrument.control(":SOUR:NOISE:CONT?;", "SOUR:NOISE:CONT %s;", "Noise simulation, ON or OFF", strict_discrete_set, ["ON", "OFF"] ) noise_density = Instrument.control(":SOUR:NOISE:CNO?;", "SOUR:NOISE:CNO %g", "Carrier/Noise density, [0.0, 56.0]", strict_range, [0, 56] ) freq_offset = Instrument.control(":SOUR:ONECHN:FREQ?;", ":SOUR:ONECHN:FREQ %s;", """ A floating point property that represents the output frequency (Hz).""") freq_offset_range = Instrument.control(":SOUR:ONECHN:FREQ?;", ":SOUR:ONECHN:FREQ %d;", """ A floating point property that represents the output frequency (Hz).""", strict_range, [-6e6, 6e6]) power = Instrument.control("SOUR:POW?;", "SOUR:POW %g;", """ A floating point property that represents the amplitude (dBm).""") refpower = Instrument.control("SOUR:REFPOW?;", "SOUR:REFPOW %g;", """ A floating point property that represents the reference power (dBm).""") pps = Instrument.control(":SOUR:PPSOUT?;", "SOUR:PPSOUT %d;", "PPS OUTPUT, ON or OFF", strict_discrete_set, [1, 10, 100, 1000]) prop_env = Instrument.control(":SOUR:SCEN:PROP?;", "SOUR::SCEN:PROP %s;", "Propagation environment", strict_discrete_set, ENVIRONMENTS)
class SpecAnalyzer(Instrument): models = ["SpA", r"E440\dB"] def __init__(self, name, adapter, **kwargs): super(SpecAnalyzer, self).__init__(name, adapter, **kwargs) start_frequency = Instrument.control(":SENS:FREQ:STAR?;", ":SENS:FREQ:STAR %e Hz;", """ A floating point property that represents the start frequency (Hz).""" ) stop_frequency = Instrument.control(":SENS:FREQ:STOP?;", ":SENS:FREQ:STOP %e Hz;", """ A floating point property that represents the stop frequency (Hz).""" ) frequency_points = Instrument.control(":SENSe:SWEEp:POINts?;", ":SENSe:SWEEp:POINts %d;", """ An integer property that represents the number of frequency points in the sweep [101,8192]. """, validator=truncated_range,values=[101, 8192],cast=int ) frequency_step = Instrument.control(":SENS:FREQ:CENT:STEP:INCR?;", ":SENS:FREQ:CENT:STEP:INCR %g Hz;", """ A floating point property that represents the frequency step (Hz).""" ) center_frequency = Instrument.control(":SENS:FREQ:CENT?;", ":SENS:FREQ:CENT %e Hz;", """ A floating point property that represents the center frequency (Hz).""" ) sweep_time = Instrument.control(":SENS:SWE:TIME?;", ":SENS:SWE:TIME %.2e;", """ A floating point property that represents the sweep time (seconds).""" ) @property def frequencies(self): """ Returns a numpy array of frequencies in Hz that correspond to the current settings of the instrument. """ return np.linspace(self.start_frequency, self.stop_frequency, self.frequency_points, dtype=np.float64 ) def trace(self, number=1): """ Returns a numpy array of the data for a particular trace based on the trace number (1, 2, or 3). """ self.write(":FORMat:TRACe:DATA ASCII;") data = np.loadtxt(StringIO(self.ask(":TRACE:DATA? TRACE%d;" % number)), delimiter=',', dtype=np.float64 ) return data def trace_df(self, number=1): """ Returns a pandas DataFrame containing the frequency and peak data for a particular trace, based on the trace number (1, 2, or 3). """ return pd.DataFrame({ 'Frequency (GHz)': self.frequencies*1e-9, 'Peak (dB)': self.trace(number) }) def set_frequency_range(self, start, stop): self.write(':SENS1:FREQ:STAR ' + str(start)) self.write(':SENS1:FREQ:STOP ' + str(stop)) def set_frequency_center_span(self, center, span=None): self.write('SENS1:FREQ:CENT ' + str(center)) if not span == None: self.write('SENS1:FREQ:SPAN ' + str(span)) def set_sweep_parameters(self, number_of_points, power): self.write(':SENS1:SWE:POIN ' + str(number_of_points)) self.write(':SOUR1:POW ' + str(power)) def set_averaging(self, enable, number_of_averages=None): if enable: scpi_parameter = 'ON' else: scpi_parameter = 'OFF' self.write(':SENS:AVER ' + scpi_parameter) if not number_of_averages == None: self.write(':SENS:AVER:COUN ' + str(number_of_averages)) def restart_averaging(self): self.write(':SENS:AVER:CLE') def get_sweep_time(self): return float(self.ask(':SENS1:SWE:TIME?')) def configure_display_scale(self, reference_value, reference_position=None, number_of_divisions=None, scale_per_division=None): self.write('DISP:WIND1:TRAC1:Y:RLEV ' + str(reference_value)) if not reference_position == None: self.write('DISP:WIND1:TRAC1:Y:RPOS ' + str(reference_position)) if not number_of_divisions == None: self.write('DISP:WIND1:Y:DIV ' + str(number_of_divisions)) if not scale_per_division == None: self.write('DISP:WIND1:TRAC1:Y:PDIV ' + str(scale_per_division)) def set_background_color(self, red, green, blue): ''' Colors are integers of range 0 through 5''' self.write('DISP:COL:BACK ' + str(red) + ',' + str(green) + ',' + str(blue)) def set_graticule_color(self, red, green, blue): ''' Colors are integers of range 0 through 5''' self.write('DISP:COL:GRAT ' + str(red) + ',' + str(green) + ',' + str(blue)) def set_grid_color(self, red, green, blue): ''' Colors are integers of range 0 through 5''' self.write('DISP:COL:GRAT2 ' + str(red) + ',' + str(green) + ',' + str(blue)) def get_bandwidth_measure(self, dB_down=None): self.write(':CALC1:MARK1:BWID ON') if not dB_down == None: self.write(':CALC1:MARK1:BWID:THR ' + str(dB_down)) return [float(i) for i in (self.ask(':CALC1:MARK:BWID:DATA?').split(','))] def peak_search(self): ''' Enable peak search, find peak, and return X and Y positions''' self.write(':CALC:MARK1:FUNC:TYPE PEAK') self.write(':CALC:MARK1:FUNC:EXEC') return float(self.ask(':CALC:MARK1:X?')), float(self.ask(':CALC:MARK1:Y?').split(',')[0]) def max_search(self, marker=None): ''' Enable max search, find max, and return X and Y positions''' if marker == None: marker = 1 marker_text = 'MARK' + str(marker) self.write(':CALC:' + marker_text + ' ON') self.write(':CALC:' + marker_text + ':FUNC:TYPE MAX') self.write(':CALC:' + marker_text + ':FUNC:EXEC') return (float(self.ask(':CALC:' + marker_text + ':X?')), float(self.ask(':CALC:' + marker_text + ':Y?').split(',')[0])) def min_search(self, marker=None): '''Enable min search, find min, and return X and Y positions''' if marker == None: marker = 1 marker_text = 'MARK' + str(marker) self.write(':CALC:' + marker_text + ' ON') self.write(':CALC:' + marker_text + ':FUNC:TYPE MIN') self.write(':CALC:' + marker_text + ':FUNC:EXEC') return (float(self.ask(':CALC:' + marker_text + ':X?')), float(self.ask(':CALC:' + marker_text + ':Y?').split(',')[0])) def get_trace(self): freqList = [float(i) for i in self.ask(':SENS1:FREQ:DATA?').split(',')] amplList = [float(i) for i in self.ask(':CALC1:DATA:FDAT?').split(',')[::2]] return np.transpose([freqList, amplList]) def set_marker(self, freq, marker=None): if marker == None: marker = 1 marker_text = 'MARK' + str(marker) self.write(':CALC:' + marker_text + ':X ' + str(freq)) return float(self.ask(':CALC:' + marker_text + ':Y?').split(',')[0]) def get_marker_value(self, marker=None): if marker == None: marker = 1 marker_text = 'MARK' + str(marker) return float(self.ask(':CALC:' + marker_text + ':Y?').split(',')[0]) def save_trace(self, filename): np.savetxt(filename, self.get_trace(), delimiter='\t') return 0 def save_screen(self, filename): urllib.request.urlretrieve('http://' + self.host + '/image.asp', filename) urllib.request.urlretrieve('http://' + self.host + '/disp.png', filename)