Source code for tam.dsa815

#
import time
from .visa import VisaDevice


[docs]class DSA815(VisaDevice): MIN_FREQUENCY = 0.0 MAX_FREQUENCY = 1500.0 MIN_SPAN = 0.0001 MAX_REF_LEVEL = 20.0 MIN_REF_LEVEL = -100.0 REF_LEVEL_STEP = 1.0 MIN_ATT = 0.0 MAX_ATT = 30.0 ATT_STEP = 1.0 MIN_MAXMIXER_LEVEL = -30.0 MAX_MAXMIXER_LEVEL = 0.0 MAXMIXER_LEVEL_STEP = 1.0 DETECTOR_MODES = {'POS': 0, 'NORM': 1, 'NEG': 2, 'SAMP': 3} def __init__(self, visa_rm, visa_id): """Create an instance of :py:class:`DSA815`. :param visa_rm: A reference to a Visa resource manager. As returned (for example) by a call to :py:`pyvisa.ResourceManager()`. :type visa_rm: :param visa_id: The ID of the analyzer to connect with. :type visa_id: str """ super().__init__(visa_rm, visa_id) def local(self): if self.inst: self.inst.control_ren(0) def clear(self): pass @property def ident(self): return self.inst.query("IDN?") @property def vavg(self): """The number of sweeps to average over. """ return int(self.inst.query(":TRAC:AVER:COUN?")) @property def ref_level(self): """The analyzer reference level in dBm. """ return float(self.inst.query(":DISP:WIN:TRAC:Y:SCAL:RLEV?")) @property def freq(self): """The analyzer sweep centre frequency in MHz. """ return float(self.inst.query(":SENS:FREQ:CENT?")) / 1e6 @property def start_freq(self): """The analyzer sweep start frequency in MHz. """ return float(self.inst.query(":SENS:FREQ:STAR?")) / 1e6 @property def stop_freq(self): """The analyzer sweep stop frequency in MHz. """ return float(self.inst.query(":SENS:FREQ:STOP?")) / 1e6 @property def fspan(self): """The analyzer sweep frequency span in MHz. """ return float(self.inst.query(":SENS:FREQ:SPAN?")) / 1e6 @property def rbw(self): """The analyzer resolution bandwidth in Hz. """ return float(self.inst.query(":SENS:BAND:RES?")) @property def rbw_auto(self): """The auto setting mode for the resolution bandwidth. """ return bool(self.inst.query(":SENS:BAND:RES:AUTO?")) @property def sweep_time(self): """The analyzer sweep time in seconds. """ return float(self.inst.query(":SENS:SWEEP:TIME?")) @property def vbw(self): """The analyzer video bandwidth in Hz. """ return float(self.inst.query(":SENS:BAND:VID?")) @property def atten(self): """The analyzer input attenuator setting in dB. """ return float(self.inst.query(":SENS:POW:RF:ATT?")) @property def atten_auto(self): """The auto setting mode for the analyzer input attenuation. """ return bool(self.inst.query(":SENS:POW:RF:ATT:AUTO?")) @property def scale(self): """The scale of the analyzer power axis in dB. The valid range of values is 0.1 to 20 dB. """ return float(self.inst.query(":DISP:WIN:TRAC:Y:SCAL:PDIV?")) @property def unit(self): """The unit of measurement for the analyzer y-axis. This should be one of :py:`[DBM, DBMV, DBUV, V, W]`. """ return self.inst.query(":UNIT:POW?") @property def mixer_level(self): """The maximum power (in dBm) at the input mixer. The valid range of values is -30 to 0 dBm in increments of 10 dB. """ return float(self.inst.query(":SENS:POW:RF:MIX:RANG:UPP?")) @property def detector_mode(self): """The analyzer detector type. This should be one of :py:`['NEG', 'NORM', 'POS', 'RMS', 'SAMP', 'VAV', 'QPE']` """ return self.query(":SENS:DET:FUNC?") @vavg.setter def vavg(self, vavg): if self.inst: self.write(":TRAC:AVER:COUN {}".format(vavg)) @ref_level.setter def ref_level(self, level): if self.inst: self.write(":DISP:WIN:TRAC:Y:SCAL:RLEV {}".format( level)) @freq.setter def freq(self, f): if self.inst: self.write(":SENS:FREQ:CENT {}".format(f * 1e6)) @start_freq.setter def start_freq(self, f): if self.inst: self.write(":SENS:FREQ:STAR {}".format(f * 1e6)) @stop_freq.setter def stop_freq(self, f): if self.inst: self.write(":SENS:FREQ:STOP {}".format(f * 1e6)) @fspan.setter def fspan(self, span): if self.inst: self.write(":SENS:FREQ:SPAN {}".format(span * 1e6)) @rbw.setter def rbw(self, res): if self.inst: self.write(":SENS:BAND:RES {}".format(res)) @rbw_auto.setter def rbw_auto(self, auto): if auto: self.write(":SENS:BAND:RES:AUTO ON") else: self.write(":SENS:BAND:RES:AUTO OFF") @sweep_time.setter def sweep_time(self, t): if self.inst: self.write(":SENS:SWEEP:TIME {}".format(t)) @vbw.setter def vbw(self, v): if self.inst: self.write(":SENS:BAND:VID {}".format(v)) @atten.setter def atten(self, att): if self.inst: self.write(":SENS:POW:RF:ATT {}".format(att)) @atten_auto.setter def atten_auto(self, auto): if auto: self.write(":SENS:POW:RF:AUTO ON") else: self.write(":SENS:POW:RF:AUTO OFF") @scale.setter def scale(self, s): if self.inst: self.write(":DISP:WIN:TRAC:Y:SCAL:PDIV {}".format(s)) @unit.setter def unit(self, u): if self.inst: self.write(":UNIT:POW {}".format(u)) @mixer_level.setter def mixer_level(self, lvl): if self.inst: self.write(":SENS:POW:RF:MIX:RANG:UPP {}".format(lvl)) @detector_mode.setter def detector_mode(self, det): if self.inst: self.write(":SENS:DET:FUNC {}".format(det))
[docs] def initialize(self): """Initialize the analyzer state. Sets the analyzer to single sweep mode, sets the sweep averaging mode and number of sweeps to average over. Also sets the reference level to the default value. """ super().initialize() if self.inst is not None: self.write(":SYST:PRES") self.write(":TRAC1:AVER:TYPE VID") self.write(":INIT:CONT OFF")
def reset(self): self.write(":SYST:PRES") self.write(":INIT:CONT ON")
[docs] def sweep(self): """Carry out a sweep using the currently set analyzer settings. """ self.write(":TRAC:AVER:CLE") avg_count = int(self.query(":TRAC:AVER:COUN?")) curr_avg_count = 0 sweep_time = float(self.query(":SENS:SWE:TIME?")) while avg_count > curr_avg_count: self.write(":INIT:IMM") time.sleep(sweep_time * 1.1) curr_avg_count = int(self.query(":TRAC:AVER:COUN:CURR?"))
[docs] def trace_data(self): """Retrieve the current analyzer trace data. :return: A list of :py:`float` values. """ tstr = self.query(":TRAC:DATA? TRACE1") count_len = int(tstr[1]) tdata = [float(tval) for tval in tstr[count_len+3:-1].split(', ')] return tdata
[docs] def measure_pwr(self, freq): """Measure the signal power of the peak near the specified frequency. This makes use of the spectrum analyzer peak search function to find the maximum signal value in the currently set span. This assumes that the relevant spectrum analyzer configuration has already been set. For example: .. code-block:: python >>> sa.vavg = 5 >>> sa.fspan = 0.1 >>> sa.ref_level = 10.0 >>> sa.measure_pwr(250.0) (2.732128, 250.000166) :param freq: The centre frequency to make the measurement (in MHz). :type freq: float :return: A tuple of :py:`(pwr, freq)` where :py:`pwr` is the measured power (in dBm) of the signal at frequency :py:`freq` (in MHz). """ self.freq = freq self.write(":TRAC:AVER:CLE") avg_count = int(self.query(":TRAC:AVER:COUN?")) curr_avg_count = int(self.query(":TRAC:AVER:COUN:CURR?")) sweep_time = float(self.query(":SENS:SWE:TIME?")) while curr_avg_count < avg_count: self.write(":INIT:IMM") time.sleep(sweep_time * 1.1) curr_avg_count = int(self.query(":TRAC:AVER:COUN:CURR?")) self.write(":CALC:MARK1:MAX:MAX") mkr_pwr = float(self.query(":CALC:MARK1:Y?")) mkr_freq = float(self.query(":CALC:MARK1:X?")) / 1e6 return mkr_pwr, mkr_freq
[docs] def measure_next_pwr(self): """Measure the power and freq. of the next highest peak. This assumes that the :py:`measure_pwr` method has already been called. For example: .. code-block:: python >>> sa.vavg = 5 >>> sa.fspan = 0.1 >>> sa.ref_level = 10.0 >>> sa.measure_pwr(250.0) (2.732128, 250.000166) >>> sa.measure_next_pwr() (1.986321, 250.050134) Note that if the analyzer cannot find another peak the cal to :py:`measure_next_pwr` will return the power and frequency values for the first peak. :return: A tuple of two floats with the power (in dBm) of next highest peak being first and the second being the frequency (in MHz) of the peak. """ self.write(":CALC:MARK1:MAX:NEXT") mkr_pwr = float(self.query(":CALC:MARK1:Y?")) mkr_freq = float(self.query(":CALC:MARK1:X?")) / 1e6 return mkr_pwr, mkr_freq