changes while testing MA6

This commit is contained in:
2026-10-07 14:31:34 +02:00
parent 09fd5cc8f4
commit e45d87e86c
9 changed files with 442 additions and 97 deletions
+172
View File
@@ -0,0 +1,172 @@
Node('ma6test.psi.ch',
'MA6 test',
'tcp://5000'
)
IO('io_lsc', 'ldmprep2-ls:7777')
IO('io_ccu', 'ldmprep12-ts:3011')
IO('io_hepump', 'ldmprep12-ts:3012')
IO('io_ilm', 'ma6-ts:3001')
IO('io_ips', 'ma6-ts:3002')
pumptype = 'xds35'
Mod('lsc',
'frappy_psi.lakeshore336.Device',
'lakeshore device',
io='io_lsc',
curve_handling=True,
)
Mod('Tm',
'frappy_psi.lakeshore336.Loop',
'VTI temperature',
device='lsc',
channel='A',
calcurve='x48581',
output_module='htr',
)
Mod('Ts',
'frappy_psi.lakeshore336.Sensor', #
'Sample temperature',
device='lsc',
channel='C',
calcurve='x63161',
)
Mod('Ts2',
'frappy_psi.lakeshore336.Sensor', #
'Sample2 temperature',
device='lsc',
channel='D',
calcurve='x174782',
)
Mod('htr',
'frappy_psi.lakeshore336.MainOutput',
'VTI heater',
io='io_lsc',
max_heater='80W',
resistance=40,
)
Mod('nv',
'frappy_psi.ccu4.NeedleValveFlow',
'flow from flow sensor or pump pressure',
io='io_ccu',
flow_sensor='flowsensor',
pressure='pumppressure',
pump_type=pumptype,
)
Mod('pumppressure',
'frappy_psi.ccu4.Pressure',
'He pump pressure',
io='io_ccu')
Mod('he_pump',
'frappy_psi.hepump.HePump',
'He pump',
pump_type=pumptype,
valvemotor='he_mot',
valve='hevalve',
)
Mod('he_mot',
'frappy_psi.hepump.Motor',
'He pump valve motor',
io='io_hepump',
maxcurrent=2.8,
output1=Param(export=True),
)
Mod('hevalve',
'frappy_psi.butterflyvalve.Valve',
'He pump valve',
motor='he_mot',
)
Mod('flowsensor',
'frappy_psi.sensirion.FlowSensor',
'needle valve flow sensor',
io='io_hepump',
nsamples=160,
)
Mod('T_cryo',
'frappy_psi.cryostat.Cryostat',
'combined cryostat temperature',
vti='Tm',
sample='Ts',
nv='nv',
dblctrl=0,
overshoot=0,
meaning=('temperature', 10),
#Ta_now=-999,
)
Mod('avtable',
'frappy_psi.cryostat.AvtimeTable',
'table for T_cryo.avtime',
xpar='T_cryo.target',
ymod='T_cryo',
avtime=[(2, 1), (10, 10), (50, 300), (120, 500), (300, 900)],
)
Mod('pidtable',
'frappy_psi.cryostat.PidTable',
'table for T_itvti PIDs',
xpar='Tm.target',
ymod='Tm',
pid_p=[(2, 25), (20, 25), (50, 100), (300, 5)],
pid_i=[(2, 100), (20, 25), (300, 2)],
)
Mod('N2Level',
'frappy_psi.oiclassic.N2Level',
'Nitrogen Level',
io='io_ilm',
)
Mod('N2FillValve',
'frappy_psi.ccu4.N2FillValve',
'Nitrogen Fill Valve',
io='io_ccu',
)
Mod('N2LevelAutomatic',
'frappy_psi.autofill.AutoFill',
'Nitrogenlevel Autofill',
valve='N2FillValve',
level='N2Level')
Mod('HeLevel',
'frappy_psi.oiclassic.HeLevel',
'Helium Level',
io='io_ilm',
)
Mod('HeFillValve',
'frappy_psi.ccu4.HeFillValve',
'Helium Fill Valve',
io='io_ccu',)
Mod('HeLevelAutomatic',
'frappy_psi.autofill.AutoFill',
'Heliumlevel Autofill',
valve='HeFillValve',
level='HeLevel')
Mod('MagField',
'frappy_psi.oiclassic.Field',
'Magentic Field',
io='io_ips',
target_max=0.1,
)
#max 0.1T, pws off und dann on, grosser stecker, geht lange, quenching
#
+26 -12
View File
@@ -19,7 +19,7 @@
#
# *****************************************************************************
import time
import time#
from frappy.core import Attached, Readable, Writable, Parameter, Command, \
IDLE, BUSY, DISABLED, ERROR
from frappy.datatypes import FloatRange, StatusType, TupleOf, EnumType
@@ -30,20 +30,20 @@ class AutoFill(HasStates, Readable):
level = Attached(Readable)
valve = Attached(Writable)
status = Parameter(datatype=StatusType(Readable, 'BUSY'))
mode = Parameter('auto mode', EnumType(disabled=0, auto=30), readonly=False)
mode = Parameter('auto mode', EnumType(disabled=0, auto=30), readonly=False, default=0)
fill_level = Parameter('low threshold triggering start filling',
FloatRange(unit='%'), readonly=False)
FloatRange(unit='%'), readonly=False, default=10)
full_level = Parameter('high threshold triggering stop filling',
FloatRange(unit='%'), readonly=False)
FloatRange(unit='%'), readonly=False, default=90)
fill_minutes_range = Parameter('range of possible fill rate',
TupleOf(FloatRange(unit='min'), FloatRange(unit='min')),
readonly=False)
readonly=False, default=(8,60))
hold_hours_range = Parameter('range of possible consumption rate',
TupleOf(FloatRange(unit='h'), FloatRange(unit='h')),
readonly=False)
readonly=False, default=(12, 96))
fill_delay = Parameter('delay for cooling the transfer line',
FloatRange(unit='min'), readonly=False)
FloatRange(unit='min'), readonly=False, default=3)
def read_status(self):
if self.mode == 'DISABLED':
@@ -52,24 +52,33 @@ class AutoFill(HasStates, Readable):
if vstatus[0] // 100 != IDLE // 100:
self.stop_machine(vstatus)
return vstatus
status = self.level.read_status(self)
status = self.level.read_status()
if status[0] // 100 == IDLE // 100:
return HasStates.read_status(self)
self.stop_machine(status)
return status
def read_value(self):
return self.level.read_value()
def write_mode(self, mode):
if mode == 'DISABLED':
if mode == 'disabled':
self.stop_machine((DISABLED, ''))
elif mode == 'AUTO':
elif mode == 'auto':
self.start_machine(self.watching)
return mode
def write_fill_level(self, level):
self.write_mode(self.mode)
return level
@status_code(BUSY)
def watching(self, state):
if state.init:
self.valve.write_target(0)
delta = state.delta(10)
if delta is None:
return Retry
raw = self.level.value
if raw > self.value:
self.value -= delta / (3600 * self.hold_hours_range[1])
@@ -87,6 +96,8 @@ class AutoFill(HasStates, Readable):
state.fillstart = state.now
self.valve.write_target(1)
delta = state.delta(1)
if delta is None:
return Retry
raw = self.level.value
if raw > self.value:
self.value += delta / (60 * self.fill_minutes_range[0])
@@ -103,6 +114,8 @@ class AutoFill(HasStates, Readable):
@status_code(BUSY)
def filling(self, state):
delta = state.delta(1)
if delta is None:
return Retry
raw = self.level.value
if raw > self.value:
self.value += delta / (60 * self.fill_minutes_range[0])
@@ -119,11 +132,12 @@ class AutoFill(HasStates, Readable):
self.valve.write_target(0)
except Exception:
pass
super().on_cleanup()
super().on_cleanup(state)
@Command()
def fill(self):
self.mode = 'AUTO'
"""start filling manually"""
self.mode = 'auto'
self.start_machine(self.precooling, fillstart=time.time())
@Command()
+15 -10
View File
@@ -384,7 +384,7 @@ def Table(miny=None, maxy=None):
return ArrayOf(TupleOf(FloatRange(), FloatRange(miny, maxy)))
class NeedleValveFlow(HasStates, Base, Drivable):
class NeedleValveFlow(HasStates, Base, Drivable): #
flow_sensor = Attached(Readable, mandatory=False)
pressure = Attached(Pressure, mandatory=False)
use_pressure = Parameter('flag (use pressure instead of flow meter)', BoolType(),
@@ -405,7 +405,7 @@ class NeedleValveFlow(HasStates, Base, Drivable):
default=30, readonly=False)
control_active = Parameter('control active flag', BoolType(), readonly=False, default=1)
min_open_pulse = Parameter('minimal open step', FloatRange(0, unit='s'),
readonly=False, default=0.02)
readonly=False, default=0.02) #deafult+ 0.02
min_close_pulse = Parameter('minimal close step', FloatRange(0, unit='s'),
readonly=False, default=0.0)
flow_closed = Parameter('flow when needle valve is closed', FloatRange(unit='ln/min'),
@@ -480,20 +480,21 @@ class NeedleValveFlow(HasStates, Base, Drivable):
def write_target(self, value):
self.log.debug('change target')
self.start_machine(self.change_target, target=value, try_close=True)
self.log.info("wrote Target for nv")
def write_pump_type(self, value):
self.pressure_scale = self.FLOW_SCALE[value.name]
def write_prop_open(self, value):
self._prop_open = Interpolation(value)
self._prop_open = Interpolation(value, False, False)
return self._prop_open
def write_prop_close(self, value):
self._prop_close = Interpolation(value)
self._prop_close = Interpolation(value, False, False)
return self._prop_close
def write_tolerance(self, value):
self._tolerance = Interpolation(value)
self._tolerance = Interpolation(value, False, False)
return self._tolerance
@status_code(BUSY)
@@ -520,7 +521,7 @@ class NeedleValveFlow(HasStates, Base, Drivable):
tol = self._tolerance(self.target)
dif = self._dif_medians()
if sm.init:
self.log.debug('restart controlling')
self.log.info('restart controlling')
direction = math.copysign(1, dif[1])
if direction != self._dir:
self.log.debug('new dir %g dif=%g', direction, dif[1])
@@ -533,15 +534,15 @@ class NeedleValveFlow(HasStates, Base, Drivable):
# self._prev_dif = dif
expected_dif = sm.ref_dif * math.exp((sm.ref_time - sm.now) / self.deriv)
if np.all(difdir < tol):
if np.all(difdir < tol): #wenn every element of difdir < tol its true
if np.all(difdir < -tol):
self.log.debug('overshoot %r', dif)
return self.controlling
if not np.any(difdir < -tol):
if not np.any(difdir < -tol):#do wemmer here, well do semmer ferig
# within tolerance
self.log.debug('at target %r tol %g', dif, tol)
return self.at_target
if np.all(difdir > expected_dif):
if np.all(difdir > expected_dif): #difdir sollte ungefahr exponentionell fallen, wenn nicht stimm was nciht
# not enough progress
if sm.now > sm.last_progress + self.deriv:
lim = self.flow_closed + 0.5
@@ -550,6 +551,7 @@ class NeedleValveFlow(HasStates, Base, Drivable):
self.command(mp=-60)
sm.after_close = self.open_until_flow_increase
self.log.debug('go to closing / open_until_flow_increase')
print('closing closing closing')
return self.closing
if sm.no_progress_pulse:
pulse = abs(sm.no_progress_pulse[self._dir < 0]) * self._dir
@@ -562,7 +564,7 @@ class NeedleValveFlow(HasStates, Base, Drivable):
difd = min(difdir[:2])
sm.last_pulse_time = sm.now
if self._dir > 0:
minstep = self.min_open_pulse
minstep = self.min_open_pulse
prop = self._prop_open(self._value)
else:
minstep = self.min_close_pulse
@@ -579,7 +581,9 @@ class NeedleValveFlow(HasStates, Base, Drivable):
step *= self._dir
self.log.debug('MP %g dif=%g tol=%g', step, difd * self._dir, tol)
self.command(mp=step)
print('step for motor is set to the value of', step, minstep)
self._speed_sum += step
print('2demfall isch do jett aber ebbis id hose')
return Retry
# still approaching
difmax = max(difdir)
@@ -588,6 +592,7 @@ class NeedleValveFlow(HasStates, Base, Drivable):
sm.ref_dif = difmax
# self.log.info('new ref %g', sm.ref_dif)
sm.last_progress = sm.now
print('1wieso zom gugus isch jetzt do au ebbis id hose?')
return Retry # progressing: no pulse needed
@status_code(IDLE)
+163 -44
View File
@@ -23,6 +23,7 @@ mainly for temperature control
import time
import numpy as np
import math
from frappy.lib import clamp
from frappy.lib.numeric import LimitedBuffer
from frappy.core import Attached, Drivable, Parameter, Readable, Writable
@@ -41,10 +42,10 @@ class Cryostat(HasConvergence, Drivable):
deltatemp = Parameter(
'temperature delta',
ArrayOf(FloatRange(0, unit='K')), readonly=False, value=(1, 2, 4, 8))
ArrayOf(FloatRange(0, unit='K')), readonly=False, value=(0, 2, 4, 8))
flowpars = Parameter(
'flows for lowering T',
ArrayOf(FloatRange(0, unit='ln/min')), readonly=False, default=(1, 5, 20))
ArrayOf(FloatRange(0, unit='ln/min')), readonly=False, default=(0, 1, 5, 20))
sample_weight = Parameter(
'weight of sample for averaging',
FloatRange(0,1), readonly=False, default=0.5)
@@ -70,6 +71,10 @@ class Cryostat(HasConvergence, Drivable):
# FloatRange(unit='K'), default=0)
avtime = Parameter('average time from simsam',
FloatRange(unit='s'), readonly=False, default=30)
_Ta_now = Parameter('first order lowpass', FloatRange(unit='K'), readonly=False, default=0)
_Tb_now = Parameter('second order lowpass', FloatRange(unit='K'), readonly=False, default=0)
_Tc_now = Parameter('thirth order lowpass', FloatRange(unit='K'), readonly=False, default=0)
_hist_range = None
_dif_range = 0
_dif_ranges = None
@@ -93,6 +98,14 @@ class Cryostat(HasConvergence, Drivable):
_avsize = False
__vti_write_target = None
__pid_i_tol = 0
dif_last = []
index_flow = None
undershot = False
#Ta_now = None
Tm_now = None
tc = 10
_checkdiff = []
offset_dblctr = 0
def initModule(self):
super().initModule()
@@ -148,10 +161,11 @@ class Cryostat(HasConvergence, Drivable):
def doPoll(self):
super().doPoll()
vti = self.vti
vti = self.vti #temp regeler
now = time.time()
ts = min(m.parameters['value'].timestamp for m in (vti, self.sample))
if ts < self._last_ts + 0.8:
ts = min(m.parameters['value'].timestamp for m in (vti, self.sample)) #entw vti//smaple.value.timestamp:wann wurde zulaetzt aktualisiert
dif_t = 0
if ts < self._last_ts + 0.8: #letzte messung ist zu neu
return
if not self._last_ts:
try:
@@ -181,42 +195,125 @@ class Cryostat(HasConvergence, Drivable):
self._sam_hist.add(self._sam_temp)
self._count_since_change += 1
self._offset_range = self.offset_range(self._avsize)
self.read_value()
if self.control_active and self._count_since_change >= 3:
if self.control_active and self._count_since_change >= 3: #csc sollt true sein, weil csc nur bei write target aufgerufen wird.
sample_vti = (self._sam_temp - self._vti_temp)
mean_t = vti.value + sample_vti * self.sample_weight
dif = mean_t - max(10, self.target) # use low flow below 10 K
ndif = len(self.deltatemp)
flow_range = self._flow_range
for _ in range(3):
if dif < self._dif_ranges[self._dif_range - 1]:
if self._dif_range > 1 - ndif:
self._dif_range -= 1
flow_range = clamp(0, self._dif_range, len(self.flowpars)-1)
elif dif > self._dif_ranges[self._dif_range + 1]:
if self._dif_range < ndif - 1:
flow_range = clamp(0, self._dif_range, len(self.flowpars)-1)
self._dif_range += 1
else:
break
mean_t = vti.value + sample_vti * self.sample_weight #durchschnitt zwischen Tm und Ts
#dif = mean_t - max(10, self.target) # use low flow below 10 K
if self.overshoot and not self.undershot and mean_t > self.target:
#idee ist, dass die TDifferenz erhoht wird um dadurch langer auf hohen flowwerten zu bleiben.
#ausserdem soll ein geiwsser mindestwet immer erhalten bleiben, solange das target nicht erreicht resp unterboten wird
dif_t = max(mean_t - self.target + 5, 2 * (mean_t - self.target))
else:
self.undershot = True #otherwise hysteresis might not ork anymore
dif_t = mean_t - self.target
#ndif = len(self.deltatemp)
flow_range = self._flow_range
index_flow = self.index_flow
print(index_flow, self.index_flow, dif_t, self.flowpars, mean_t)
if index_flow is None and dif_t != 0:
print('inside')
try:
for element in reversed(self.deltatemp):
if element < dif_t:
index_flow = self.deltatemp.index(element)
break
except Exception as e:
print('Fehler indexing:', repr(e))
try:
for _ in range(len(self.flowpars)): #falls die temperatur extrem schnell sinkt, ansonsten hinkt der wert nach
upper = clamp(0, index_flow + 1, len(self.flowpars) - 1)
down = clamp(0, index_flow - 1, len(self.flowpars) - 1)
if dif_t < self.deltatemp[down]:
if index_flow > 0:
index_flow -= 1
elif dif_t > self.deltatemp[upper]:
if index_flow < len(self.flowpars) - 1:
index_flow += 1
else:
break
except Exception as e:
print('Fehler:', repr(e))
target = self.target
# self.log.info('size %g dif_range %d', size, self._dif_range)
if self.overshoot and abs(self._dif_range) > 1:
target = self.target - sample_vti * (1 - self.sample_weight)
#
# if self.overshoot and abs(self._dif_range) > 1:
# target = self.target - mean_t
# target = self.target - sample_vti * (1 - self.sample_weight)
if self.dblctrl:
if self._offset_range is not None:
minof, maxof = self._offset_range
if not minof < self.offset < maxof:
# use the averaged value
self.offset = clamp(self.offset, self.offset_lo, self.offset_hi)
target += self.offset
if abs(target - vti.target) * (now - self._last_change) > (target + vti.target) * 0.001:
# threshold for update depends on product of time since last change and relative difference
self._last_change = now
self.__vti_write_target(target)
else:
flow_range = 0
if self._Tm_now is None:
simulation_1 = [self.vti.read_value(), self.vti.read_value(), self.vti.read_value(), self.vti.read_value()]
simulation_1 = [self.vti.read_value(), self.vti.read_value(), self.vti.read_value(), self.vti.read_value()]
#tm, ta, tb, tc
self._Tm_now = self.vti.read_value()
def simulation(order, w, parameters):
last_sim = None
for ordr in range(order):
last_sim_new = parameters[ordr + 1]
if last_sim is None:
last_sim = parameters[0]
parameters[0] = self.vti.read_value()
parameters[ordr + 1] = parameters[ordr + 1] + w * (parameters[ordr] - last_sim)
last_sim = last_sim_new
return parameters
simulation_1 = simulation(1, 5/self.tc, simulation_1)
simulation_2 = simulation(1, 5/self.tc, simulation_2)
range = sorted([self.sample.read_value() - simulation_1[1], self.sample.read_value() - simulation_2[1]]) #temp differenz
if len(self._checkdiff) < math.ceil(self.tc/5): #built list mit abweichungen
self._checkdiff.append(self._Tm_now - self.vti.target)
else:
del self._checkdiff[0]
self._checkdiff.append(self._Tm_now - self.vti.target).
if np.median(self._checkdiff) < self._toll:
#schauen, ob intervalle sich uberschneiden mit beruck. von offset, das nur tun wenn abweichung klein ist
if max(simulation_1[0], simulation_2[0]) < min([self._Tm_now + self.offset_dblctr - self._tol, self._Tm_now + self.offset_dblctr + self._tol]):
self.offset_dblctr = max(simulation_1[1], simulation_2[1]) + self._tol - self._Tm_now #index anpassen je nach ordnung
target += self.offset_dblctr
self.__vti_write_target(target)
elif min(simulation_1[0], simulation_2[0]) > max([self._Tm_now + self.offset_dblctr - self._tol, self._Tm_now + self.offset_dblctr + self._tol]):
self.offset_dblctr = min(simulation_1[1], simulation_2[1]) - self._tol - self._Tm_now #index anpassen je nach ordnung
target += self.offset_dblctr
self.__vti_write_target(target)
# if self.offset > range[1]:
# self.offset = range[1]
# target += self.offset
# self.__vti_write_target(target)
# elif self.offset < range[0]:
# self.offset = range[0]
# target += self.offset
# self.__vti_write_target(target)
# if self.dblctrl:
# if self._offset_range is not None:
# minof, maxof = self._offset_range
# if not minof < self.offset < maxof:
# # use the averaged value
# self.offset = clamp(self.offset, self.offset_lo, self.offset_hi)
# target += self.offset
# if abs(target - vti.target) * (now - self._last_change) > (target + vti.target) * 0.001:
# # threshold for update depends on product of time since last change and relative difference
# self._last_change = now
# self.__vti_write_target(target)
# else:
# flow_range = 0
red = getattr(vti, 'reduce_pid_i', 1)
if red != 1:
vtidif = abs(vti.value - vti.target)
@@ -228,15 +325,26 @@ class Cryostat(HasConvergence, Drivable):
self.log.debug('reduce_pid_i %g %g', self.__pid_i_tol, vtidif)
vti.write_reduce_pid_i(self.__pid_i_tol / vtidif)
if self.auto_flow and flow_range != self._flow_range:
self.nv.write_target(self.flowpars[flow_range])
self._flow_range = flow_range
self.log.info('flowtarget %g', self.nv.target)
if self.auto_flow and index_flow != self.index_flow:
self.nv.write_target(self.flowpars[index_flow])
self.index_flow = index_flow
#self.log.info('flowtarget %g', self.nv.target)
# def write_deltatemp(self, value):
# self._dif_ranges = dict(enumerate((0,) + tuple(value)))
# self._dif_ranges.update((-1-i, -v) for i, v in enumerate(value))
# self.log.info('dif_ranges %r', self._dif_ranges)
def write_deltatemp(self, value):
self._dif_ranges = dict(enumerate((0,) + tuple(value)))
self._dif_ranges.update((-1-i, -v) for i, v in enumerate(value))
self.log.info('dif_ranges %r', self._dif_ranges)
self._dif_ranges_rising = dict()
self._dif_ranges_falling = dict()
for a, b in zip(value[:-1], self.flowpars):
self._dif_ranges_rising[a] = b
self._dif_ranges_rising[value[-1]] = self.flowpars[-1]
self._dif_ranges_falling[value[0]] = self.flowpars[0]
for a, b in zip(value[1:], self.flowpars):
self._dif_ranges_falling[a] = b
def write_target(self, target):
self.write_control_active(True)
@@ -255,6 +363,11 @@ class Cryostat(HasConvergence, Drivable):
# self.__pid_i_tol = tol
# self.vti.write_reduce_pid_i(0.1)
self.__vti_write_target(target)
self.dif_last.clear()
self.undershot = False
#is needed otherwise after restart weirdelemts in list might distract autoregulation of nv
self._Tm_now = None
def write_avtime(self, value):
self._avsize = None
@@ -263,3 +376,9 @@ class Cryostat(HasConvergence, Drivable):
class AvtimeTable(Table):
logarithmic = True
avtime = Curve()
class PidTable(Table):
logarithmic = True
pid_p = Curve()
pid_i = Curve()
+1 -1
View File
@@ -47,7 +47,7 @@ class HePump(Writable):
def read_value(self):
if self.has_feedback and self.valvemotor.io.is_connected:
return not self.valvemotor.read_input3()
return not self.valvemotor.read_home()
return self.target
def read_eco_mode(self):
+26 -7
View File
@@ -232,11 +232,8 @@ class Device(HasLscIO, Module):
self.disable_channel(ch)
def configure_display(self, disp_dict):
"""Configure display
disp_dict: dict <channel> of 1, 2, 3 (Kelvin, Celsius, raw)"""
pass
def configure_display(self):
"""Configure display"""
def read_status(self):
status = IDLE, ''
@@ -635,7 +632,7 @@ class SensorBase(Base, Readable):
value = Parameter(unit='K')
status = Parameter(datatype=StatusType(Readable, 'DISABLED', 'BUSY'))
channel = Property('used channel', StringType()) # input
enabled = Parameter('enable flag', BoolType(), readonly=False)
enabled = Parameter('enable flag', BoolType(), readonly=False, value=True)
filter = Parameter('no. of filter points', datatype=FloatRange(2, 64, unit='points'), readonly=False)
curve_no = None
STATUS_BIT_LABELS = 'invalid_reading old_reading b2 b3 t_under t_over units_zero units_overrange'.split()
@@ -658,7 +655,7 @@ class SensorBase(Base, Readable):
value_error = None
if self.enabled:
rdgst, raw, value = self.get_internal_data()
# self.log.info('rdgst %r, raw %r', rdgst, raw)
self.log.info('rdgst %r, raw %r value %r', rdgst, raw, value)
rdgst &= 0xfd # suppress old reading
if rdgst:
statuslist = formatStatusBits(rdgst, self.STATUS_BIT_LABELS)
@@ -1096,3 +1093,25 @@ class Device2(Device):
user_curves = (21, 60) # the last curve is 59
max_raw_unit = 99999
TYPES = {'DT': 1, 'TG': 1, 'PT': 2, 'RF': 2, 'CX': 3, 'RX': 3, 'CC': 3, 'GE': 3, 'TC': 4}
def configure_display(self):
enabled_sensors = {k: v for k, v in self._all_sensors.items() if v.enabled}
#no_fields = min(2, len(enabled_sensors) // 2)
no_fields = min(2, round(len(enabled_sensors) / 2) - 1)
#otherwise its always the setting with 4 displays
self.command('DISPLAY', 4, no_fields, 1) # custom, no. fields, main loop TODO: customize
for loc, (ch, sens) in enumerate(enabled_sensors.items(), 1):
if loc > 8:
return
self.command(f'DISPFLD {loc}', ord(ch) - ord('A') + 1, sens.DISPLAY_UNIT)
#in welchem Feld von display, von welchem input, welche einheit
self.command(f'INNAME {ch}', sens.name)
number = 2**(no_fields + 1) #TODO: dg angepasst
for zusatz in range(number - len(enabled_sensors)):
print("whats going on", zusatz + 1 + len(enabled_sensors))
self.command(f'DISPFLD {zusatz + 1 + len(enabled_sensors)}', 0, sens.DISPLAY_UNIT)
self.command(f'INNAME {zusatz + 1 + len(enabled_sensors)}', 'None')
#
+1 -1
View File
@@ -98,7 +98,7 @@ class Device(ls.Device):
if loc > 8:
return
self.command(f'DISPFLD {loc}', ch, sens.DISPLAY_UNIT)
self.command('INNAME', sens.name)
self.command(f'INNAME {ch}', sens.name)
class Switcher(ls.HasLscIO, ChannelSwitcher):
+10 -7
View File
@@ -16,7 +16,7 @@
# Module authors:
# Markus Zolliker <markus.zolliker@psi.ch>
# *****************************************************************************
"""generic persistent magnet driver"""
"""generic persistent magnet driver"""#
import time
from frappy.core import Drivable, Parameter, BUSY, Limit
@@ -94,8 +94,12 @@ class SimpleMagfield(HasStates, Drivable):
def checkProperties(self):
dt = self.parameters['target'].datatype
max_ = dt.max
#max_ = self.target_max
if max_ == UNLIMITED.max:
raise ConfigError('target.max not configured')
try:
max_ = self.target_max
except Exception:
raise ConfigError('target.max not configured') from None
if dt.min == UNLIMITED.min: # not given: assume bipolar symmetric
dt.min = -max_
self.target_min = max(dt.min, self.target_min)
@@ -156,7 +160,6 @@ class SimpleMagfield(HasStates, Drivable):
raise NotImplementedError
def handle_train_mode(self):
self.log.info('handle %r %r', self.trained, self.value)
if self.trained[0] < self.value < self.trained[1]:
trainmode = 'off'
else:
@@ -230,10 +233,10 @@ class Magfield(SimpleMagfield):
def doPoll(self):
if self.init_persistency:
if self.read_switch_heater() and self.mode != Mode.DRIVEN:
# switch heater is on on startup: got to persistent mode
# switch heater is on on startup: go to persistent mode
# do this after some delay, so the user might continue
# driving without delay after a restart
self.start_machine(self.go_persistent_soon, mode=self.mode)
self.start_machine(self.go_persistent_soon, mode=self.mode, try_cnt=0)
self.init_persistency = False
super().doPoll()
@@ -252,7 +255,7 @@ class Magfield(SimpleMagfield):
elif value == Mode.PERSISTENT:
func = self.start_switch_off
self.target = target
self.start_machine(func, target=target, mode=value)
self.start_machine(func, target=target, mode=value, try_cnt=0)
return value
def write_target(self, target):
@@ -261,7 +264,7 @@ class Magfield(SimpleMagfield):
if target == 0:
return 0
raise DisabledError('disabled')
self.start_machine(self.start_field_change, target=target, mode=self.mode)
self.start_machine(self.start_field_change, target=target, mode=self.mode, try_cnt=0)
return target
def on_error(self, sm): # sm is short for statemachine
+28 -15
View File
@@ -37,7 +37,11 @@ def bit(x, pos):
class OxBase(HasIO):
def query(self, cmd, scale=None):
def query(self, cmd, scale=1):
"""send cmd and reply numeric value
scale=None:return int
else: return scaled float"""
pat = cmd[0] + r'([-+]?\d+\.?\d*)$'
value = self.io.request(cmd, pat)
if scale is None:
@@ -50,10 +54,14 @@ class OxBase(HasIO):
def change(self, cmd, value, scale=None):
try:
self.io.request('C3', 'C$')
self.io.request(f'{cmd}{round(value / scale)}', cmd)
if scale is None:
self.io.request(f'{cmd}{value}', cmd)
else:
self.io.request(f'{cmd}{round(value / scale)}', cmd) #
finally:
self.io.request('C0', 'C$')
def command(self, *cmds):
try:
self.io.request('C3', 'C$')
@@ -67,11 +75,11 @@ class OI_IO(StringIO):
def request(self, cmd, pattern):
reply = None
for _ in range(5):
try:
reply = self.communicate(cmd)
except Exception as e:
self.log.warn('commerror %r', e)
continue
# try:
reply = self.communicate(cmd)
#except Exception as e:
# self.log.warn('commerror %r', e)
# continue
match = re.match(pattern, reply)
if match:
result = match.groups()
@@ -213,7 +221,7 @@ class Field(OxBase, Magfield):
return self.switch_heater
def read_status(self):
self._status, action, sw = self.io.request('X', r'X(\d\d)A(\d)C\dH(\d)M\d\dP\d\d')
self._status, action, sw, sweep_mode = self.io.request('X', r'X(\d\d)A(\d)C\dH(\d)M\d(\d)P\d\d')
self.action = int(action)
self.switch_heater = sw == '1'
if self._status[0] != '0':
@@ -221,7 +229,10 @@ class Field(OxBase, Magfield):
return status_map.get(self._status[0], (ERROR, f'bad status: {self._status}'))
if self._status[1] != '0':
return limit_map.get(self._status[1], (ERROR, f'bad status: {self._status}')) # need to stop sm too?
return super().read_status()
status = super().read_status()
if int(sweep_mode) >= 2:
return status[0], status[1] + " (sweep limited)"
return status
def write_switch_heater(self, value):
if value == self.read_switch_heater():
@@ -234,7 +245,9 @@ class Field(OxBase, Magfield):
return int(value)
def set_and_go(self, value):
print('set and go', value)
self.change('J', value)
print('set and go', value)
self.setpoint = self.read_current()
assert self.write_action(Action.hold) == Action.hold
assert self.write_action(Action.run_to_set) == Action.run_to_set
@@ -348,7 +361,7 @@ class Field(OxBase, Magfield):
return Retry
def write_trainmode(self, value):
self.change('M', '5' if value == 'off' else '1')
self.change('M', '1' if value == 'off' else '5')
class ILM_IO(OI_IO):
@@ -501,7 +514,7 @@ class Valve(OxBase, Writable):
def write_target(self, target):
# open: 2N, close: 2N + 1
self.change('P', (2 * self.addr.value + 1 - int(target)), 1)
self.change('P', (2 * self.addr.value + 1 - int(target)))
class PulsedValve(Valve):
@@ -515,7 +528,7 @@ class PulsedValve(Valve):
self.setFastPoll(True, 0.01)
else:
self.setFastPoll(False)
self.change('P', (2 * self.addr.value + 1 - int(target)), 1)
self.change('P', (2 * self.addr.value + 1 - int(target)))
def doPoll(self):
super().doPoll()
@@ -655,7 +668,7 @@ class SorbPower(OxBase, Writable):
return 0
def write_target(self, target):
self.change('O', self.io._heater_status & 1 | 4 * (target > 0), 1)
self.change('O', self.io._heater_status & 1 | 4 * (target > 0))
self.change('B', target, self.scale)
def read_status(self):
@@ -685,7 +698,7 @@ class StillPower(OxBase, Writable):
return 0
def write_target(self, target):
self.change('O', self.io._heater_status & 6 | (target > 0), 1)
self.change('O', self.io._heater_status & 6 | (target > 0))
self.change('S', target, self.scale)
def read_status(self):
@@ -722,7 +735,7 @@ class Pump(Valve):
def write_target(self, target):
# open: 2 * 24, close: 2 * 24 + 1
self.change('P', 2 * self.addr.value + 1 - target, 1)
self.change('P', 2 * self.addr.value + 1 - target)
self.value = target
def read_status(self):