Autogain function for SR830 lock-in driver

Change-Id: If07ec9182e5153e1237b9818ce555162f54e0ae5
This commit is contained in:
Oksana Shliakhtun 2023-11-20 13:20:28 +01:00 committed by Markus Zolliker
parent 1bd188e326
commit 416cdd5a88

View File

@ -19,7 +19,11 @@
# ***************************************************************************** # *****************************************************************************
import re import re
from frappy.core import StringIO, HasIO, Parameter, EnumType, FloatRange, TupleOf, ERROR, IDLE, WARN import time
from frappy.core import StringIO, HasIO, Parameter, EnumType, FloatRange, TupleOf, ERROR, IDLE, WARN, StatusType, \
Readable, BUSY
from frappy.errors import IsBusyError
def string_to_value(value): def string_to_value(value):
@ -36,7 +40,7 @@ class SR830_IO(StringIO):
identification = [('*IDN?', r'Stanford_Research_Systems,.*')] identification = [('*IDN?', r'Stanford_Research_Systems,.*')]
class StanfRes(HasIO): class StanfRes(HasIO, Readable):
def set_par(self, cmd, *args): def set_par(self, cmd, *args):
head = ','.join([cmd] + [a if isinstance(a, str) else f'{a:g}' for a in args]) head = ','.join([cmd] + [a if isinstance(a, str) else f'{a:g}' for a in args])
tail = cmd.replace(' ', '? ') tail = cmd.replace(' ', '? ')
@ -74,6 +78,8 @@ class XY(StanfRes):
autorange = Parameter('autorange_on', EnumType('autorange', off=0, soft=1, hard=2), autorange = Parameter('autorange_on', EnumType('autorange', off=0, soft=1, hard=2),
readonly=False, default=0) readonly=False, default=0)
status = Parameter(datatype=StatusType(Readable, 'BUSY'))
SEN_RANGE = ['2nV', '5nV', '10nV', '20nV', '50nV', '100nV', '200nV', '500nV', SEN_RANGE = ['2nV', '5nV', '10nV', '20nV', '50nV', '100nV', '200nV', '500nV',
'1uV', '2uV', '5uV', '10uV', '20uV', '50uV', '100uV', '200uV', '500uV', '1uV', '2uV', '5uV', '10uV', '20uV', '50uV', '100uV', '200uV', '500uV',
'1mV', '2mV', '5mV', '10mV', '20mV', '50mV', '100mV', '200mV', '500mV', '1mV', '2mV', '5mV', '10mV', '20mV', '50mV', '100mV', '200mV', '500mV',
@ -96,51 +102,65 @@ class XY(StanfRes):
ioClass = SR830_IO ioClass = SR830_IO
status_messages = [ _autogain_started = 0
(ERROR, 'execution error', 2, 4),
(ERROR, 'illegal command', 2, 5),
(ERROR, 'reserve/input overload', 3, 0),
(ERROR, 'tc overload', 3, 1),
(ERROR, 'output overload', 3, 2),
(WARN, 'input queue overflow, cleared', 2, 0),
(WARN, 'output queue overflow, cleared', 2, 2),
(WARN, 'reference unlock', 3, 3),
(WARN, 'freq crosses 200 Hz', 3, 4),
(IDLE, 'no scan in progress', 1, 0),
(IDLE, 'no command execution in progress', 1, 1),
(IDLE, 'unused', 1, 7),
(IDLE, '', 2, 1),
(IDLE, '', 2, 3),
(IDLE, '', 3, 7),
(IDLE, '', 4, 0),
(IDLE, '', 4, 3),
]
# status = serial poll status byte, standard event status byte, lock-in status byte, error status byte # status = serial poll status byte, standard event status byte, lock-in status byte, error status byte
def read_status(self): def read_status(self):
status_values = [ if time.time() < self._autogain_started + self.tc * 10:
int(self.communicate('*STB?')), # serial poll status byte return BUSY, 'changing gain'
int(self.communicate('*ESR?')), # standard event status byte
int(self.communicate('LIAS?')), # lock-in status byte
int(self.communicate('ERRS?')), # error status byte
]
for vi in range(1, 5): stb = int(self.communicate('*STB?')) # serial poll status byte
value = status_values[vi - 1] esr = int(self.communicate('*ESR?')) # standard event status byte
lias = int(self.communicate('LIAS?')) # lock-in status byte
errs = int(self.communicate('ERRS?')) # error status byte
for status_type, status_msg, curr_vi, bit in self.status_messages: if lias & (1 << 2):
if curr_vi == vi and value & (1 << bit): return ERROR, 'output overload'
# conv_status = HasConvergence.read_status(self) if lias & (1 << 1):
return status_type, status_msg return ERROR, 'tc overload'
if lias & (1 << 0):
return ERROR, 'reserve/input overload'
if esr & (1 << 5):
return ERROR, 'illegal command'
if esr & (1 << 4):
return ERROR, 'execution error'
if errs & (1 << 1):
return ERROR, 'backup error'
if errs & (1 << 2):
return ERROR, 'RAM error'
if errs & (1 << 4):
return ERROR, 'ROM error'
if errs & (1 << 5):
return ERROR, 'GRIB error'
if errs & (1 << 6):
return ERROR, 'DSP error'
if errs & (1 << 7):
return ERROR, 'internal math error'
if esr & (1 << 0):
return WARN, 'input queue overflow, cleared'
if esr & (1 << 2):
return WARN, 'output queue overflow, cleared'
if lias & (1 << 3):
return WARN, 'reference unlock'
if lias & (1 << 4):
return WARN, 'freq crosses 200 Hz'
if not stb & (1 << 0):
return BUSY, 'scan in progress'
if not stb & (1 << 1):
return BUSY, 'command execution in progress'
return IDLE, ''
def read_value(self): def read_value(self):
if self.read_status()[0] == BUSY:
raise IsBusyError('changing gain')
reply = self.get_par('SNAP? 1, 2') reply = self.get_par('SNAP? 1, 2')
value = tuple(float(x) for x in reply) value = tuple(float(x) for x in reply)
x, y = value x, y = value
maxxy = max(abs(x), abs(y))
if self.autorange == 1: if self.autorange == 1:
if max(abs(x), abs(y)) >= 0.9 * self.range and self.irange < 26: if maxxy >= 0.9 * self.range and self.irange < 26:
self.write_irange(self.irange + 1) self.write_irange(self.irange + 1)
elif max(abs(x), abs(y)) <= 0.3 * self.range and self.irange > 0: elif maxxy <= 0.3 * self.range and self.irange > 0:
self.write_irange(self.irange - 1) self.write_irange(self.irange - 1)
return value return value
@ -155,6 +175,8 @@ class XY(StanfRes):
def write_irange(self, irange): def write_irange(self, irange):
value = int(irange) value = int(irange)
self.set_par(f'SENS {value}') self.set_par(f'SENS {value}')
self._autogain_started = time.time()
self.read_range()
return value return value
def write_range(self, target): def write_range(self, target):