up to date with develop/mlz

Change-Id: I5ea71bc99a2f0dffc3dbe37e1119eb188ef8a3f0
This commit is contained in:
2023-05-31 14:27:36 +02:00
parent c5d429346d
commit 9a6421a54f
8 changed files with 149 additions and 160 deletions

View File

@ -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,46 +31,65 @@ 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):
ioClass = SR_IO
def comm(self, cmd):
reply, status, overload = self.communicate(cmd).split(b';')
if overload != b'0':
self.status = (self.Status.WARN, f'overload {overload}')
self.status = (self.Status.IDLE, '')
return reply
class XY(Ametek, Readable):
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('noise control mode', 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 = {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')]
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(';')
if overload != '0':
self.status = (self.Status.WARN, f'overload {overload}')
self.status = (self.Status.IDLE, '')
return reply
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=''))

View File

@ -20,10 +20,10 @@
# *****************************************************************************
import math
from frappy.core import Readable, Parameter, IntRange, EnumType, FloatRange, \
from frappy.core import Readable, Parameter, IntRange, FloatRange, \
StringIO, HasIO, StringType, Property, Writable, Drivable, IDLE, ERROR, \
Attached, StructOf, WARN, Done, BoolType, Enum
StructOf, WARN, Done, BoolType, Enum
from frappy.errors import RangeError
from frappy_psi.convergence import HasConvergence
from frappy.mixins import HasOutputModule, HasControlledBy
@ -233,7 +233,7 @@ class HeaterOutput336(HeaterOutput):
else:
self._range = 1
user_current = max_current * math.sqrt(100)
self.set_par(f'HTRSET {self.loop}', <1 or 2>, 0, user_current, 1)
self.set_par(f'HTRSET {self.loop}', 1 if self.resistance < 50 else 2, 0, user_current, 1)
max_power = max_current ** 2 * self.resistance
self._max_power = max_power
self.set_range()

View File

@ -86,6 +86,29 @@ class ThermFishIO(StringIO):
class SensorA10(HasIO, Readable):
ioClass = ThermFishIO
value = Parameter('internal temperature', unit='degC')
status_messages = [
(ERROR, 'high tempr. cutout fault', 2, 0),
(ERROR, 'high RA tempr. fault', 2, 1),
(ERROR, 'high temperature fixed fault', 3, 7),
(ERROR, 'low temperature fixed fault', 3, 6),
(ERROR, 'high temperature fault', 3, 5),
(ERROR, 'low temperature fault', 3, 4),
(ERROR, 'low level fault', 3, 3),
(ERROR, 'circulator fault', 4, 5),
(ERROR, 'high press. cutout', 5, 2),
(ERROR, 'motor overloaded', 5, 1),
(ERROR, 'pump speed fault', 5, 0),
(WARN, 'open internal sensor', 1, 7),
(WARN, 'shorted internal sensor', 1, 6),
(WARN, 'high temperature warn', 3, 2),
(WARN, 'low temperature warn', 3, 1),
(WARN, 'low level warn', 3, 0),
(IDLE, 'max. heating', 5, 5),
(IDLE, 'heating', 5, 6),
(IDLE, 'cooling', 5, 4),
(IDLE, 'max cooling', 5, 3),
(IDLE, '', 4, 3),
]
def get_par(self, cmd):
"""
@ -112,37 +135,11 @@ class SensorA10(HasIO, Readable):
result_str = self.communicate('RUFS') # read unit fault status
values_str = result_str.strip().split()
values_int = [int(val) for val in values_str]
v1, v2, v3, v4, v5 = values_int #[:5]
status_messages = [
(ERROR, 'high tempr. cutout fault', 2, 0),
(ERROR, 'high RA tempr. fault', 2, 1),
(ERROR, 'high temperature fixed fault', 3, 7),
(ERROR, 'low temperature fixed fault', 3, 6),
(ERROR, 'high temperature fault', 3, 5),
(ERROR, 'low temperature fault', 3, 4),
(ERROR, 'low level fault', 3, 3),
(ERROR, 'circulator fault', 4, 5),
(ERROR, 'high press. cutout', 5, 2),
(ERROR, 'motor overloaded', 5, 1),
(ERROR, 'pump speed fault', 5, 0),
(WARN, 'open internal sensor', 1, 7),
(WARN, 'shorted internal sensor', 1, 6),
(WARN, 'high temperature warn', 3, 2),
(WARN, 'low temperature warn', 3, 1),
(WARN, 'low level warn', 3, 0),
(IDLE, 'max. heating', 5, 5),
(IDLE, 'heating', 5, 6),
(IDLE, 'cooling', 5, 4),
(IDLE, 'max cooling', 5, 3),
(IDLE, '', 4, 3),
]
for status_type, status_msg, vi, bit in status_messages:
for status_type, status_msg, vi, bit in self.status_messages:
if values_int[vi-1] & (1 << bit):
print(status_type, status_msg, vi, bit)
return status_type, status_msg
return WARN, 'circulation off'
return WARN, 'circulation off'
class TemperatureLoopA10(SensorA10, Drivable):