New driver for lock-in amplifier SR830
Change-Id: I45c5a06460f4b84cade0eae53188b058510c4473
This commit is contained in:
parent
e405783716
commit
e89bc07759
171
frappy_psi/SR830.py
Normal file
171
frappy_psi/SR830.py
Normal file
@ -0,0 +1,171 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# *****************************************************************************
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation; either version 2 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# Module authors: Oksana Shliakhtun <oksana.shliakhtun@psi.ch>
|
||||
# *****************************************************************************
|
||||
|
||||
import re
|
||||
from frappy.core import StringIO, HasIO, Parameter, EnumType, FloatRange, TupleOf, ERROR, IDLE, WARN
|
||||
|
||||
|
||||
class SR830_IO(StringIO):
|
||||
end_of_line = b'\r' # should be <if> or <cr>
|
||||
identification = [('*IDN?', r'Stanford_Research_Systems,.*')]
|
||||
|
||||
|
||||
class XY(HasIO):
|
||||
XY = Parameter('X, Y', datatype=TupleOf(FloatRange(unit='V'), FloatRange(unit='V')))
|
||||
# channel = Property('output channel')
|
||||
amp = Parameter('oscill. amplit. control', FloatRange(4e-3, 5), unit='V', readonly=False)
|
||||
freq = Parameter('oscill. frequen. control', FloatRange(1e-3, 102000), unit='Hz', readonly=False)
|
||||
phase = Parameter('reference phase control', FloatRange(-360, 729), unit='deg', readonly=False)
|
||||
|
||||
sen_range = ['2nV', '5nV', '10nV', '20nV', '50nV', '100nV', '200nV', '500nV',
|
||||
'1uV', '2uV', '5uV', '10uV', '20uV', '50uV', '100uV', '200uV', '500uV',
|
||||
'1mV', '2mV', '5mV', '10mV', '20mV', '50mV', '100mV', '200mV', '500mV',
|
||||
'1V']
|
||||
|
||||
irange = Parameter('sensitivity index', EnumType('sensitivity index range',
|
||||
{name: idx for idx, name in enumerate(sen_range)}))
|
||||
|
||||
range = Parameter('sensitivity value', FloatRange(2e-9, 1), unit='V', default=1, readonly=False)
|
||||
|
||||
time_const = {name: value for value, name in enumerate(
|
||||
['10us', '30us', '100us', '300us', '1ms', '3ms', '10ms', '30ms', '100ms', '300ms',
|
||||
'1s', '3s', '10s', '30s', '100s', '300s', '1ks', '3ks', '10ks', '30ks']
|
||||
)}
|
||||
|
||||
tc = Parameter('time const. value', FloatRange(1e-6, 3e4), unit='s', readonly=False)
|
||||
itc = Parameter('time const. index', EnumType('time const. index range', time_const), readonly=False)
|
||||
|
||||
ioClass = SR830_IO
|
||||
|
||||
status_messages = [
|
||||
(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
|
||||
def read_status(self):
|
||||
status_values = [
|
||||
int(self.communicate('*STB?')), # serial poll status byte
|
||||
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):
|
||||
value = status_values[vi-1]
|
||||
|
||||
for status_type, status_msg, curr_vi, bit in self.status_messages:
|
||||
if curr_vi == vi and value & (1 << bit):
|
||||
# conv_status = HasConvergence.read_status(self)
|
||||
return status_type, status_msg
|
||||
|
||||
def string_to_value(self, value):
|
||||
value_with_unit = re.compile(r'(\d+)([pnumkMG]?)')
|
||||
value, pfx = value_with_unit.match(value).groups()
|
||||
pfx_dict = {'p': 1e-12, 'n': 1e-9, 'u': 1e-6, 'm': 1e-3, 'k': 1e3, 'M': 1e6, 'G': 1e9}
|
||||
if pfx in pfx_dict:
|
||||
value = round(float(value) * pfx_dict[pfx], 12)
|
||||
return float(value)
|
||||
|
||||
def read_value(self):
|
||||
self.XY = self.communicate('SNAP? 1, 2')
|
||||
return XY
|
||||
|
||||
def read_irange(self):
|
||||
return int(self.communicate('SENS?'))
|
||||
|
||||
def read_range(self):
|
||||
idx = self.read_irange()
|
||||
name = self.sen_range[idx]
|
||||
value = self.string_to_value(name)
|
||||
return value
|
||||
|
||||
def write_irange(self, irange):
|
||||
value = int(irange)
|
||||
self.communicate(f'SENS {value}')
|
||||
return value
|
||||
|
||||
def write_range(self, target):
|
||||
target = float(target)
|
||||
cl_idx = None
|
||||
cl_value = float('-inf')
|
||||
|
||||
for idx, sen_value in enumerate(self.sen_range):
|
||||
value = self.string_to_value(self.sen_range)
|
||||
|
||||
if target >= value > cl_value:
|
||||
cl_value = value
|
||||
cl_idx = idx
|
||||
|
||||
self.communicate(f'SENS {cl_idx}')
|
||||
return cl_value
|
||||
|
||||
def read_tc(self):
|
||||
return float(self.communicate('OFLT?'))
|
||||
|
||||
def write_tc(self, target):
|
||||
self.communicate(f'OFLT {target}')
|
||||
|
||||
def read_itc(self):
|
||||
return int(self.communicate(f'OFLT?'))
|
||||
|
||||
def write_itc(self, target):
|
||||
self.communicate(f'OFLT {target}')
|
||||
return self.read_itc()
|
||||
|
||||
def read_phase(self):
|
||||
return float(self.communicate('PHAS?'))
|
||||
|
||||
def write_phase(self, value):
|
||||
self.communicate(f'PHAS {value}')
|
||||
return value
|
||||
|
||||
def read_freq(self):
|
||||
return float(self.communicate('FREQ?'))
|
||||
|
||||
def write_freq(self, value):
|
||||
self.communicate(f'FREQ {value}')
|
||||
return value
|
||||
|
||||
def read_amp(self):
|
||||
return float(self.communicate('SLVL?'))
|
||||
|
||||
def write_amp(self, value):
|
||||
self.communicate(f'SLVL {value}')
|
||||
return value
|
||||
|
||||
def auto_phase(self):
|
||||
return self.communicate('APHS')
|
||||
|
Loading…
x
Reference in New Issue
Block a user