Source code for QInstrument.instruments.StanfordResearch.SR844.instrument

import logging
from QInstrument.lib.QSerialInstrument import QSerialInstrument


logger = logging.getLogger(__name__)


[docs] class QSR844(QSerialInstrument): '''SRS SR844 RF Lock-in Amplifier Properties ========== Reference and Phase ------------------- frequency : float [Hz] Reference frequency for the internal oscillator. Rounded to 5 significant digits or 0.0001 Hz, whichever is greater. Range: 25 MHz <= frequency <= 200 MHz harmonic : int Detection harmonic. Range: 1 <= harmonic < 20000, frequency * harmonic <= 200 MHz internal_reference : bool True: use internal reference source. False: use external reference source. phase : float [degrees] Reference phase shift. Range: -360 <= phase <= 729.99 reference_impedance : int Reference input impedance. 0: 50 Ohm, 1: 10 kOhm Signal Input ------------ input_impedance : int Signal input impedance. 0: 50 Ohm, 1: 1 MOhm wide_reserve : int Wide-band dynamic reserve mode. 0: high reserve, 1: normal, 2: low noise Gain and Time Constant ---------------------- close_reserve : int Close-in dynamic reserve mode. 0: high reserve, 1: normal, 2: low noise low_pass_slope : int 0: 6 dB/octave, 1: 12 dB/octave, 2: 18 dB/octave, 3: 24 dB/octave sensitivity : int 0: 100 nVrms / -127 dBm 8: 1 mVrms / -47 dBm 1: 300 nVrms / -117 dBm 9: 3 mVrms / -37 dBm 2: 1 μVrms / -107 dBm 10: 10 mVrms / -27 dBm 3: 3 μVrms / -97 dBm 11: 30 mVrms / -17 dBm 4: 10 μVrms / -87 dBm 12: 100 mVrms / -7 dBm 5: 30 μVrms / -77 dBm 13: 300 mVrms / +3 dBm 6: 100 μVrms / -67 dBm 14: 1 Vrms / +13 dBm 7: 300 μVrms / -57 dBm time_constant : int Input filter time constant. 0: 100 μs 9: 3 s 1: 300 μs 10: 10 s 2: 1 ms 11: 30 s 3: 3 ms 12: 100 s 4: 10 ms 13: 300 s 5: 30 ms 14: 1 ks 6: 100 ms 15: 3 ks 7: 300 ms 16: 10 ks 8: 1 s 17: 30 ks ''' comm = dict(baudRate=QSerialInstrument.BaudRate.Baud19200, dataBits=QSerialInstrument.DataBits.Data8, stopBits=QSerialInstrument.StopBits.OneStop, parity=QSerialInstrument.Parity.NoParity, flowControl=QSerialInstrument.FlowControl.NoFlowControl, eol='\r') def _registerProperties(self) -> None: '''Register all instrument properties via ``registerProperty()``. Called automatically by ``QAbstractInstrument.__init__``. Subclasses that extend the property set should call ``super()._registerProperties()`` first. ''' # Reference and Phase self._register('frequency', 'FREQ', float) self._register('harmonic', 'HARM', int) self._register('internal_reference', 'FMOD', bool) self._register('phase', 'PHAS', float) self._register('reference_impedance', 'REFZ', int) # Signal Input self._register('input_impedance', 'INPZ', int) self._register('wide_reserve', 'WRSV', int) # Gain and Time Constant self._register('close_reserve', 'CRSV', int) self._register('low_pass_slope', 'OFSL', int) self._register('sensitivity', 'SENS', int) self._register('time_constant', 'OFLT', int) def _registerMethods(self) -> None: '''Register all instrument methods via ``registerMethod()``. Called automatically by ``QAbstractInstrument.__init__``. Subclasses that add methods should call ``super()._registerMethods()`` first. ''' self.registerMethod('reset', self.reset) self.registerMethod('auto_gain', self.auto_gain) self.registerMethod('auto_close_reserve', self.auto_close_reserve) self.registerMethod('auto_wide_reserve', self.auto_wide_reserve) self.registerMethod('auto_phase', self.auto_phase) self.registerMethod('auto_offset_x', self.auto_offset_x) self.registerMethod('auto_offset_y', self.auto_offset_y) self.registerMethod('auto_offset_r', self.auto_offset_r) def _register(self, name: str, cmd: str, dtype: type = float) -> None: '''Register a standard instrument property. Builds getter and setter from the SR844 command convention: query is ``cmd + '?'``, set is ``cmd + value``. Bool properties are transmitted as integers (0/1) per the instrument protocol. Parameters ---------- name : str Property name passed to ``registerProperty``. cmd : str SR844 command mnemonic (e.g. ``'FREQ'``). dtype : type, optional Value type: ``float`` (default), ``int``, or ``bool``. ''' if dtype is bool: def getter(): return bool(self.getValue(f'{cmd}?', int)) def setter(v): self.transmit(f'{cmd}{int(bool(v))}') else: def getter(): return self.getValue(f'{cmd}?', dtype) def setter(v): self.transmit(f'{cmd}{dtype(v)}') self.registerProperty(name, getter=getter, setter=setter, ptype=dtype)
[docs] def identify(self) -> bool: '''Return True if the connected device identifies as an SR844. Queries the instrument identification string (``*IDN?``) and checks for the ``'SR844'`` model token in the response. ''' return 'SR844' in self.handshake('*IDN?')
[docs] def report(self) -> list[float]: '''Return the current frequency, magnitude, and phase simultaneously. Uses the SNAP command for simultaneous capture, avoiding the timing errors that would result from three sequential queries. Returns ------- list[float] [frequency [Hz], R [V], theta [degrees]] ''' response = self.handshake('SNAP?9,3,4') return list(map(float, response.split(',')))
[docs] def reset(self) -> None: '''Reset the SR844 to its factory default settings.''' self.transmit('*RST')
[docs] def auto_gain(self) -> None: '''Automatically adjust the sensitivity (autorange gain).''' self.transmit('AGAN')
[docs] def auto_close_reserve(self) -> None: '''Automatically adjust the close-in dynamic reserve.''' self.transmit('ACRS')
[docs] def auto_wide_reserve(self) -> None: '''Automatically adjust the wide-band dynamic reserve.''' self.transmit('AWRS')
[docs] def auto_phase(self) -> None: '''Automatically adjust the reference phase.''' self.transmit('APHS')
[docs] def auto_offset_x(self) -> None: '''Automatically offset the X output channel to zero.''' self.auto_offset(1)
[docs] def auto_offset_y(self) -> None: '''Automatically offset the Y output channel to zero.''' self.auto_offset(2)
[docs] def auto_offset_r(self) -> None: '''Automatically offset the R output channel to zero.''' self.auto_offset(3)
[docs] def auto_offset(self, channel: int) -> None: '''Automatically offset the specified output channel to zero. Parameters ---------- channel : int 1: X, 2: Y, 3: R ''' if channel not in (1, 2, 3): logger.warning(f'auto_offset: channel must be 1, 2, or 3 (got {channel})') return self.transmit(f'AOFF{channel}')
if __name__ == '__main__': QSR844.example() __all__ = ['QSR844']