dil5: working alfa version

Change-Id: Ib6bf2234633cc760fc771a3f5c0beb4cb63a0f6d
This commit is contained in:
2025-06-05 17:47:48 +02:00
parent 2b7ee0a72c
commit d85d80ba36
3 changed files with 102 additions and 54 deletions

View File

@ -55,38 +55,42 @@ class Dilution(HasStates, Drivable):
condense_valve = Attached() condense_valve = Attached()
dump_valve = Attached() dump_valve = Attached()
circulate_pump = Attached() forepump = Attached()
compressor = Attached(mandatory=False) compressor = Attached(mandatory=False)
turbopump = Attached(mandatory=False) turbopump = Attached(mandatory=False)
condenseline_valve = Attached() condenseline_valve = Attached()
circuitshort_valve = Attached() circuitshort_valve = Attached()
still_pressure = Attached() still_pressure = Attached()
still_pressure_turbo = Attached(mandatory=False)
value = Parameter('current state', EnumType(T), default=0) value = Parameter('current state', EnumType(T), default=0)
target = Parameter('target state', EnumType(T), default=0) target = Parameter('target state', EnumType(T), default=0)
sorbpumped = Parameter('sorb pump done', BoolType(), default=False) sorbpumped = Parameter('sorb pump done', BoolType(), default=False)
dump_pressure = Attached()
#ls372 = Attached() #ls372 = Attached()
V5 = Attached() #Name noch ändern!!!
p1 = Attached() #Name noch ändern!!! condensing_p_low = Parameter('Lower limit for condenseline pressure',
FloatRange(unit='mbar'), readonly=False, default=1200)
condensing_p_low = Parameter('Lower limit for condenseline pressure', FloatRange(unit='mbar')) condensing_p_high = Parameter('Higher limit for condenseline pressure',
condensing_p_high = Parameter('Higher limit for condenseline pressure', FloatRange(unit='mbar')) FloatRange(unit='mbar'), readonly=False, default=1500)
dump_target = Parameter('low dump pressure limit indicating end of condensation phase', dump_target = Parameter('low dump pressure limit indicating end of condensation phase',
FloatRange(unit='mbar'), default=20) FloatRange(unit='mbar * min'), readonly=False, default=100)
pulse_factor = Parameter('factor for calculating V9 pulse length',
FloatRange(unit='mbar'), readonly=False, default=20)
end_condense_pressure = Parameter('low condense pressure indicating end of condensation phase', end_condense_pressure = Parameter('low condense pressure indicating end of condensation phase',
FloatRange(unit='mbar'), default=500) FloatRange(unit='mbar'), readonly=False, default=500)
turbo_condense_pressure = Parameter('low condense pressure before turbo start', turbo_condense_pressure = Parameter('low condense pressure before turbo start',
FloatRange(unit='mbar'), default=900) FloatRange(unit='mbar'), readonly=False, default=900)
turbo_still_pressure = Parameter('low still pressure before turbo start', safe_turbo_pressure = Parameter('low still pressure before turbo start',
FloatRange(unit='mbar'), default=10) FloatRange(unit='mbar'), readonly=False, default=10)
turbo_off_delay = Parameter('wait time after switching turbo off',
FloatRange(unit='s'), default=300)
turbo_off_speed = Parameter('speed to wait for after switching turbo off', turbo_off_speed = Parameter('speed to wait for after switching turbo off',
FloatRange(unit='s'), default=60) FloatRange(unit='Hz'), readonly=False, default=200)
end_remove_still_pressure = Parameter('pressure reached before end of remove', end_remove_turbo_pressure = Parameter('pressure reached before end of remove (before turbo)',
FloatRange(unit='mbar'), default=1e-4) FloatRange(unit='mbar'), readonly=False, default=1e-4)
end_remove_pressure = Parameter('pressure reached before end of remove (before fore pump)',
FloatRange(unit='mbar'), readonly=False, default=0.02)
st = StringType() st = StringType()
valve_set = StructOf(close=st, open=st, check_open=st, check_closed=st) valve_set = StructOf(close=st, open=st, check_open=st, check_closed=st)
condense_valves = Parameter('valve to act when condensing', valve_set) condense_valves = Parameter('valve to act when condensing', valve_set)
@ -105,10 +109,16 @@ class Dilution(HasStates, Drivable):
self.value = Targetstates.SORBPUMP self.value = Targetstates.SORBPUMP
return self.value return self.value
""" """
if self.value == self.target: self.log.info('start %s', target.name)
if self.value == target:
return target # not sure if this is correct. may be a step wants to be repeated? return target # not sure if this is correct. may be a step wants to be repeated?
self.start_machine(getattr(self, target.name, None)) try:
self.start_machine(getattr(self, target.name, None))
except Exception as e:
self.log.exception('error')
self.log.info('started %s', target.name)
return target return target
""" """
@ -150,22 +160,40 @@ class Dilution(HasStates, Drivable):
def condense(self, state): def condense(self, state):
"""Führt das Kondensationsverfahren durch.""" """Führt das Kondensationsverfahren durch."""
if state.init: if state.init:
self.value = V.condensing # self.value = V.condensing
pumpstate = self.forepump.read_value()
if self.turbopump:
self.turbopump.write_target(0)
self.handle_valves(**self.condense_valves) self.handle_valves(**self.condense_valves)
self._start_time = state.now
if not pumpstate: # wait longer for starting fore pump
self._start_time += 10
return Retry return Retry
if self.wait_valves(): if self.wait_valves():
return Retry return Retry
self.check_valve_result() self.check_valve_result()
return Retry return self.condensing
@status_code(BUSY) @status_code(BUSY)
def condensing(self, state): def condensing(self, state):
if self.condenseline_pressure.read_value() < self.condensing_p_low: pdump = self.dump_pressure.value # or self.dump_pressure.read_value() ?
self.condense_valve.write_target(1) pcond = self.condenseline_pressure.read_value()
elif self.condenseline_pressure.read_value() > self.condensing_p_high: v9 = self.condense_valve.read_value()
self.condense_valve.write_target(0) if v9:
if pcond > self.condensing_p_high:
if self.p1.read_value() > self.dump_target: self.log.info('shut V9')
self.condense_valve.write_target(0)
elif pcond < self.condensing_p_low and state.now > self._start_time + 5:
pulse_time = 60 * self.pulse_factor / pdump
if pulse_time > 59:
self.log.info('open V9')
self.condense_value.write_target(1)
else:
self.log.info('V9 pulse %r', pulse_time)
self._start_time = state.now
self.condense_valve.pulse(pulse_time)
if pdump > self.dump_target:
return Retry return Retry
self.condense_valve.write_target(1) self.condense_valve.write_target(1)
@ -175,6 +203,14 @@ class Dilution(HasStates, Drivable):
return self.wait_for_condense_line_pressure return self.wait_for_condense_line_pressure
@status_code(BUSY, 'condense (wait before starting turbo)')
def condense_wait_before_turbo_start(self, state):
if (self.condenseline_pressure.read_value() > self.turbo_condense_pressure
and self.still_pressure.read_value() > self.safe_turbo_pressure):
return Retry
self.turbopump.write_target(1)
return self.wait_for_condense_line_pressure
@status_code(BUSY) @status_code(BUSY)
def wait_for_condense_line_pressure(self, state): def wait_for_condense_line_pressure(self, state):
if self.condenseline_pressure.read_value() > self.end_condense_pressure: if self.condenseline_pressure.read_value() > self.end_condense_pressure:
@ -182,14 +218,6 @@ class Dilution(HasStates, Drivable):
self.condense_valve.write_target(0) self.condense_valve.write_target(0)
return self.circulate return self.circulate
@status_code(BUSY, 'condense (wait before starting turbo)')
def condense_wait_before_turbo_start(self, state):
if (self.condenseline_pressure.read_value() > self.turbo_condense_pressure
and self.still_pressure.read_value() > self.turbo_still_pressure):
return Retry
self.turbopump.write_target(1)
return self.wait_for_condense_line_pressure
@status_code(BUSY) @status_code(BUSY)
def circulate(self, state): def circulate(self, state):
"""Zirkuliert die Mischung.""" """Zirkuliert die Mischung."""
@ -206,20 +234,17 @@ class Dilution(HasStates, Drivable):
"""Entfernt die Mischung.""" """Entfernt die Mischung."""
if state.init: if state.init:
self.condenseline_valve.write_target(0) self.handle_valves(**self.remove_valves)
self.dump_valve.write_target(1)
if self.turbopump is not None: if self.turbopump is not None:
self._start_time = state.now self._start_time = state.now
self.turbopump.write_target(0) self.turbopump.write_target(0)
return Retry return Retry
if self.turbopump is not None: if self.turbopump is not None:
self.turbopump.write_target(0) # if (state.now - self._start_time < self.turbo_off_delay or
if self.turbopump.read_speed() > self.turbo_off_speed:
if (state.now - self._start_time < self.turbo_off_delay
or self.turbopump.read_speed() > self.turbo_off_speed):
return Retry return Retry
self.circuitshort_valve.write_target(1) self.circuitshort_valve.write_target(1)
if self.turbopump is not None: if self.turbopump is not None:
@ -229,27 +254,30 @@ class Dilution(HasStates, Drivable):
@status_code(BUSY, 'remove (wait for still pressure low)') @status_code(BUSY, 'remove (wait for still pressure low)')
def remove_wait_for_still_pressure(self, state): def remove_wait_for_still_pressure(self, state):
if self.still_pressure.read_value() > self.turbo_still_pressure: if self.still_pressure.read_value() > self.safe_turbo_pressure:
return Retry return Retry
self.turbopump.write_target(1) self.turbopump.write_target(1)
return self.remove_endsequence return self.remove_endsequence
@status_code(BUSY) @status_code(BUSY)
def remove_endsequence(self, state): def remove_endsequence(self, state):
if self.still_pressure.read_value() > self.end_remove_still_pressure: if (self.still_pressure_turbo and
self.still_pressure_turbo.read_value() > self.end_remove_turbo_pressure):
return Retry
if self.still_pressure.read_value() > self.end_remove_pressure:
return Retry return Retry
self.circuitshort_valve.write_target(0) self.circuitshort_valve.write_target(0)
self.dump_valve.write_target(0) self.dump_valve.write_target(0)
if self.compressor is not None: if self.compressor is not None:
self.compressor.write_target(0) self.compressor.write_target(0)
self.circulate_pump.write_target(0)
return self.close_valves_after_remove return self.close_valves_after_remove
@status_code(BUSY) @status_code(BUSY)
def close_valves_after_remove(self, state): def close_valves_after_remove(self, state):
if state.init: if state.init:
self.handle_valves(**self.valves_after_remove) self.handle_valves(**self.valves_after_remove)
self.turbopump.write_target(0)
if self.wait_valves(): if self.wait_valves():
return Retry return Retry
self.check_valve_result() self.check_valve_result()
@ -313,7 +341,13 @@ class DIL5(Dilution):
'close': 'V2 V4 V9', 'close': 'V2 V4 V9',
'check_closed': 'MV10 MV13 MV8 MVB MV2', 'check_closed': 'MV10 MV13 MV8 MVB MV2',
'check_open': 'MV1 MV3a MV3b GV1 MV9 MV11 MV12 MV14', 'check_open': 'MV1 MV3a MV3b GV1 MV9 MV11 MV12 MV14',
'open': 'V1 V5 compressor pump', 'open': 'V1 V5 compressor forepump',
}
remove_valves = {
'close': 'V1 V2 V9',
'check_closed': 'MV10 MV13 MV8 MVB MV2',
'check_open': 'MV1 MV3a MV3b GV1 MV9 MV11 MV12 MV14',
'open': 'V4 V5 compressor forepump',
} }
valves_after_remove = { valves_after_remove = {
'close': 'V1 V2 V4 V5 V9', 'close': 'V1 V2 V4 V5 V9',
@ -330,6 +364,7 @@ class DIL5(Dilution):
class Interlock(LogoMixin, AddrMixin, Readable): class Interlock(LogoMixin, AddrMixin, Readable):
dil = Attached()
value = AddrParam('interlock state (bitmap)', value = AddrParam('interlock state (bitmap)',
IntRange(0, 31), addr='V414', readonly=False) IntRange(0, 31), addr='V414', readonly=False)
p5lim = AddrParam('safety limit on p5 to protect forepump', p5lim = AddrParam('safety limit on p5 to protect forepump',
@ -349,6 +384,15 @@ class Interlock(LogoMixin, AddrMixin, Readable):
reset_param = Property('addr for reset', StringType(), default='V418.1') reset_param = Property('addr for reset', StringType(), default='V418.1')
_mismatch = None _mismatch = None
_prefix = '' _prefix = ''
_actuators = None
def initModule(self):
super().initModule()
self._actuators = {}
for actions in self.conditions.values():
for modname in actions:
if modname not in self._actuators:
self._actuators[modname] = self.secNode.modules[modname]
def doPoll(self): def doPoll(self):
self.read_status() # this includes read_value self.read_status() # this includes read_value
@ -362,9 +406,8 @@ class Interlock(LogoMixin, AddrMixin, Readable):
"""reset the interlock""" """reset the interlock"""
self._prefix = '' self._prefix = ''
self.set_vm_value(self.reset_param, 1) self.set_vm_value(self.reset_param, 1)
for actions in self.conditions.values(): for actuator in self._actuators.values():
for mname in actions: actuator.reset_fault()
self.secNode.modules[mname].reset_fault()
if self.read_value() != 0: if self.read_value() != 0:
raise HardwareError('can not clear status byte') raise HardwareError('can not clear status byte')
self.set_vm_value(self.reset_param, 0) self.set_vm_value(self.reset_param, 0)
@ -375,13 +418,14 @@ class Interlock(LogoMixin, AddrMixin, Readable):
self._mismatch = set() self._mismatch = set()
bits = self.read_value() bits = self.read_value()
if bits: if bits:
self.dil.stop()
keys = formatStatusBits(bits, self.conditions, 1) keys = formatStatusBits(bits, self.conditions, 1)
statustext = [] statustext = []
for key in keys: for key in keys:
actions = self.conditions[key] actions = self.conditions[key]
statustext.append(f"{' and '.join(actions)} {key}") statustext.append(f"{' and '.join(actions)} {key}")
for module, value in actions.items(): for module, value in actions.items():
modobj = self.secNode.modules[module] modobj = self._actuators[module]
if modobj.target != value: if modobj.target != value:
self._prefix = 'switched ' self._prefix = 'switched '
modobj.set_fault(value, f'switched {key}') modobj.set_fault(value, f'switched {key}')

View File

@ -118,7 +118,7 @@ class DigitalActuator(LogoMixin, Writable):
def initialReads(self): def initialReads(self):
super().initialReads() super().initialReads()
self.target = self.value self.target = self.read_value()
def set_fault(self, value, statustext): def set_fault(self, value, statustext):
"""on a fault condition, set target to value """on a fault condition, set target to value
@ -229,6 +229,10 @@ class Value(LogoMixin, Readable):
return IDLE, '' return IDLE, ''
class DigitalValue(Value):
value = Parameter('airpressure state', datatype=BoolType())
# TODO: the following classes are too specific, they have to be moved # TODO: the following classes are too specific, they have to be moved
class Pressure(LogoMixin, Drivable): class Pressure(LogoMixin, Drivable):

View File

@ -129,7 +129,7 @@ class PfeifferMixin(HasIO):
class RPT200(PfeifferMixin, Readable): class RPT200(PfeifferMixin, Readable):
value = Parameter('Pressure', FloatRange(unit='hPa')) value = Parameter('Pressure', FloatRange(unit='mbar'))
def read_value(self): def read_value(self):
return self.data_request_u_expo_new(740) return self.data_request_u_expo_new(740)
@ -143,11 +143,11 @@ class RPT200(PfeifferMixin, Readable):
class TCP400(PfeifferMixin, Drivable, Readable): class TCP400(PfeifferMixin, Drivable, Readable):
speed= Parameter('Rotational speed', FloatRange(unit = 'Hz'), readonly = False) speed= Parameter('Rotational speed', FloatRange(unit='Hz'), readonly = False)
target= Parameter('Pumping station', BoolType()) target= Parameter('Pumping station', BoolType())
current= Parameter('Current consumption', FloatRange(unit = '%')) current= Parameter('Current consumption', FloatRange(unit='%'))
value = Parameter('Turbopump state', BoolType()) value = Parameter('Turbopump state', BoolType())
temp = Parameter('temp', FloatRange(unit = 'C')) temp = Parameter('temp', FloatRange(unit='C'))
def read_temp (self): def read_temp (self):
return self.data_request_u_int(326) return self.data_request_u_int(326)