changes while testing MA6
This commit is contained in:
@@ -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
@@ -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
@@ -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
@@ -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()
|
||||
@@ -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
@@ -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')
|
||||
|
||||
|
||||
|
||||
#
|
||||
@@ -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
@@ -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
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user