diff --git a/cfg/main/ma6test_cfg.py b/cfg/main/ma6test_cfg.py new file mode 100644 index 00000000..775bc933 --- /dev/null +++ b/cfg/main/ma6test_cfg.py @@ -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 +# \ No newline at end of file diff --git a/frappy_psi/autofill.py b/frappy_psi/autofill.py index 0e3e12fa..4d59f47b 100644 --- a/frappy_psi/autofill.py +++ b/frappy_psi/autofill.py @@ -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() diff --git a/frappy_psi/ccu4.py b/frappy_psi/ccu4.py index ea79ec2d..502e7346 100644 --- a/frappy_psi/ccu4.py +++ b/frappy_psi/ccu4.py @@ -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) diff --git a/frappy_psi/cryostat.py b/frappy_psi/cryostat.py index 17d71499..51d328b3 100644 --- a/frappy_psi/cryostat.py +++ b/frappy_psi/cryostat.py @@ -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() \ No newline at end of file diff --git a/frappy_psi/hepump.py b/frappy_psi/hepump.py index 6e9eb4fb..bc0de486 100644 --- a/frappy_psi/hepump.py +++ b/frappy_psi/hepump.py @@ -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): diff --git a/frappy_psi/lakeshore.py b/frappy_psi/lakeshore.py index bfa37fe2..7d7de0d9 100644 --- a/frappy_psi/lakeshore.py +++ b/frappy_psi/lakeshore.py @@ -232,11 +232,8 @@ class Device(HasLscIO, Module): self.disable_channel(ch) - def configure_display(self, disp_dict): - """Configure display - - disp_dict: dict 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') + + + +# \ No newline at end of file diff --git a/frappy_psi/lakeshore372.py b/frappy_psi/lakeshore372.py index afc6a1d4..ec4d2f88 100644 --- a/frappy_psi/lakeshore372.py +++ b/frappy_psi/lakeshore372.py @@ -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): diff --git a/frappy_psi/magfield.py b/frappy_psi/magfield.py index 145a13fb..c545ba5f 100644 --- a/frappy_psi/magfield.py +++ b/frappy_psi/magfield.py @@ -16,7 +16,7 @@ # Module authors: # Markus Zolliker # ***************************************************************************** -"""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 diff --git a/frappy_psi/oiclassic.py b/frappy_psi/oiclassic.py index 8f25b139..f5d253b0 100644 --- a/frappy_psi/oiclassic.py +++ b/frappy_psi/oiclassic.py @@ -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):