From 564620e9e3229a346617061dd29bd09ffec93aca Mon Sep 17 00:00:00 2001 From: Oksana Shliakhtun Date: Tue, 30 May 2023 18:23:33 +0200 Subject: [PATCH] Test for lockin driver Change-Id: I9db745088efdef182154b71e019a0f6f83644278 --- frappy_psi/SR.py | 177 ++++++++++++++++++++--------------------------- 1 file changed, 76 insertions(+), 101 deletions(-) diff --git a/frappy_psi/SR.py b/frappy_psi/SR.py index c5f5906..7463e93 100644 --- a/frappy_psi/SR.py +++ b/frappy_psi/SR.py @@ -22,6 +22,7 @@ from frappy.core import Readable, Parameter, FloatRange, TupleOf, \ HasIO, StringIO, IntRange, BoolType, Writable, EnumType +from frappy.errors import RangeError class SR_IO(StringIO): @@ -30,13 +31,59 @@ class SR_IO(StringIO): def communicate(self, cmd): # remove dash from terminator reply = super().communicate(cmd) - status = self._conn.readbytes(2, 0.1) # get the 2 status bytes + status = self._conn.readbytes(2, timeout=0.1) # get the 2 status bytes return reply + ';%d;%d' % tuple(status) -class Ametek(StringIO, HasIO): +class XY(HasIO, Readable): + value = Parameter('X, Y', datatype=TupleOf(FloatRange(unit='V'), FloatRange(unit='V'))) + vmode = Parameter('control mode', EnumType(both_grounded=0, A=1, B=2, A_B_diff=3), readonly=False) + range = Parameter('sensitivity value', FloatRange(0.00, 1), unit='V', default=1) + autosen_on = Parameter('is auto sensitivity on', BoolType(), readonly=False) + noise_control = Parameter('is noise control mode on', BoolType(), readonly=False) + phase = Parameter('reference phase control', FloatRange(-360, 360), unit='deg', readonly=False) + frequency = Parameter('oscill. frequen. control', FloatRange(0.001, 250e3), unit='Hz', readonly=False, + group='frequency') + amplitude = Parameter('oscill. amplit. control', FloatRange(0.00, 5), unit='V_rms', readonly=False) + #filter = Parameter('line frequency filter', unit='Hz') + + sen_range = {name: value + 1 for value, name in enumerate( + ['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', sen_range), readonly=False) + + time_const = {name: value for value, name in enumerate( + ['10us', '20us', '50us', '100us', '200us', '500us', '1ms', '2ms', '5ms', '10ms', + '20ms', '50ms', '100ms', '200ms', '500ms', '1s', '2s', '5s', '10s', '20s', '50s', + '100s', '200s', '500s', '1ks', '10ks', '20ks', '50ks', '100ks'] + )} + + tc = Parameter('time const. value', FloatRange(0.00005, 100000), unit='s', readonly=False) + itc = Parameter('time const. index', EnumType('time const. index range', time_const), readonly=False) ioClass = SR_IO + def comparison(self, curr_value, new_value, value_dict): + c_ind = None # closest index + c_diff = None # closets difference + + for index, value in value_dict.items(): + if c_diff is None or diff < c_diff: + c_ind = index + c_diff = c_diff + + if abs(curr_value - new_value) < c_diff: + return c_ind + else: + for index, value in value_dict.items(): + diff = abs(new_value - value) + if c_diff is None or diff < c_diff: + c_ind = index + c_diff = diff + return c_ind + def comm(self, cmd): reply, status, overload = self.communicate(cmd).split(b';') if overload != b'0': @@ -44,33 +91,6 @@ class Ametek(StringIO, HasIO): self.status = (self.Status.IDLE, '') return reply - -class XY(Ametek, Readable): - value = Parameter('X, Y', datatype=TupleOf(FloatRange(unit='V'), FloatRange(unit='V'))) - vmode = Parameter('control mode', EnumType(both_grounded=0, A=1, B=2, A_B_diff=3), readonly=False) - range = Parameter('sensitivity value', FloatRange(0.00, 1), unit='V', default=1) - autosen_on = Parameter('is auto sensitivity on', BoolType(), readonly=False) - noise_control = Parameter('noise control mode', BoolType(), readonly=False) - phase = Parameter('reference phase control', FloatRange(-360, 360), unit='deg', readonly=False) - - sen_range = {name: value + 1 for value, name in enumerate( - ['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', sen_range), readonly=False) - - time_const = {value: name for value, name in enumerate( - [('10us', 'N/A'), ('20us', 'N/A'), ('50us', 'N/A'), ('100us', 'N/A'), - ('200us', 'N/A'), ('500us', '500us'), ('1ms', '1ms'), ('2ms', '2ms'), - ('5ms', '5ms'), ('10ms', '10ms'), ('20ms', 'N/A'), ('50ms', 'N/A'), - ('100ms', 'N/A'), ('200ms', 'N/A'), ('500ms', 'N/A'), ('1s', 'N/A'), - ('2s', 'N/A'), ('5s', 'N/A'), ('10s', 'N/A'), ('20s', 'N/A'), ('50s', 'N/A'), - ('100s', 'N/A'), ('200s', 'N/A'), ('500s', 'N/A'), ('1ks', 'N/A'), - ('10ks', 'N/A'), ('20ks', 'N/A'), ('50ks', 'N/A'), ('100ks', 'N/A')] - )} - itc = Parameter('time const. index', EnumType('time const. index range', time_const), readonly=False) - def read_vmode(self): return self.comm('VMODE') @@ -97,25 +117,11 @@ class XY(Ametek, Readable): return self.comm('SEN.') # range value def write_range(self): - self.comm(f'IMODE {0}') + self.comm(f'IMODE 0') curr_value = self.read_range() new_value = self.value - c_ind = None # closest parameters - c_diff = None - for index, value in self.sen_range.items(): - diff = abs(curr_value - value) - if c_diff is None or diff < c_diff: - c_ind = index - c_diff = diff - if abs(curr_value - new_value) < c_diff: - return self.comm(f'SEN {c_ind}') - else: - for index, value in self.sen_range.items(): - diff = abs(new_value - value) - if c_diff is None or diff < c_diff: - c_ind = index - c_diff = diff - return self.comm(f'SEN {c_ind}') + c_ind = self.comparison(curr_value, new_value, self.sen_range) + return self.comm(f'SEN {c_ind}') def read_noise_control(self): return self.comm('NOISEMODE') @@ -126,15 +132,24 @@ class XY(Ametek, Readable): def read_tc(self): return self.comm('TC.') - def read_itc(self): - return self.comm(f'TC') + def write_tc(self): + pass - # def write_tc(self, itc): - # if self.noise_control == 0: - # self.itc = self. + def read_itc(self): + return self.comm('TC') + + def write_itc(self, new_itc): + curr_value = self.read_itc() + new_value = self.time_const[self.itc] + c_ind = self.comparison(curr_value, new_value, self.time_const) + + if abs(curr_value - new_value) < c_diff: + if self.read_noise_control() == 1 and (5e-4 <= self.time_const[new_itc] <= 1e-2): + raise RangeError('not allowed with noisemode=1') + return self.comm(f'TC {new_itc}') def read_value(self): - reply = self.comm('XY.').split(',') + reply = self.comm('XY.').split(b',') x = float(reply[0]) y = float(reply[1]) return x, y @@ -142,68 +157,28 @@ class XY(Ametek, Readable): def write_value(self, value): return self.comm(f'XY {value}') - -class Frequency(XY, Writable): - value = Parameter('oscill. frequen. control', FloatRange(0.001, 250e3), unit='Hz', readonly=False) - target = Parameter('target frequency', FloatRange(0.001, 250e3), unit='Hz', readonly=False) - - def read_value(self): + def read_frequency(self): return self.comm('OF.') - def write_target(self,): - target = self.target() - return self.comm(f'OF. {target}') + def write_frequency(self, frequency): + frequency = self.frequency + return self.comm(f'OF. {frequency}') - -class Amplitude(XY, Writable): - value = Parameter('oscill. amplit. control', FloatRange(0.00, 5), unit='V_rms', readonly=False) - target = Parameter('target amplit.', FloatRange(0.00, 5), unit='V_rms', readonly=False) - - # unify the following - # dac = Parameter('output DAC channel value', datatype=TupleOf(IntRange(1, 4), FloatRange(0.0, 5000, unit='mV')), - # readonly=False, initwrite=True, default=(3,0)) - # dac = Parameter('output DAC channel value', FloatRange(-10000, 10000, unit='mV'), - # readonly=False, initwrite=True, default=0) - # oscillator amplitude module - - def read_value(self): + def read_amplitude(self): return self.comm('OA.') - def write_target(self): - target = self.target() - return self.comm(f'OA. {target}') - - # external output DAC - # def read_dac(self): - # # reply = self.comm('DAC %g' % channel) # failed to add the DAC channel you want to control - # reply = self.comm('DAC 3') # stack to channel 3 - # return reply - - # def write_dac(self, value): - # # self.comm('DAC %g %g' % channel % value) - # self.comm('DAC 3 %g' % value) - # return value + def write_amplitude(self, amplitude): + return self.comm(f'OA. {amplitude}') # phase and autophase def read_phase(self): - reply = self.comm('REFP.') - return reply + return self.comm('REFP.') def write_phase(self, value): self.comm(f'REFP {round(1000 * value)}') - self.read_phase() - return value + return self.read_phase() def aphase(self): """auto phase""" self.read_phase() return self.comm('AQN') - -# class Comp(Ametek, Readable): -# enablePoll = False -# value = Parameter(datatype=FloatRange(unit='V')) -# -# -# class arg(Ametek, Readable): -# enablePoll = False -# value = Parameter(datatype=FloatRange(unit=''))