frappy_psi: add jtccr
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
# *****************************************************************************
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation; either version 2 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# Module authors:
|
||||
# Anik Stark <anik.stark@psi.ch>
|
||||
# *****************************************************************************
|
||||
|
||||
from frappy.core import Parameter, Property, Writable, Attached, EnumType, FloatRange, \
|
||||
IDLE, BUSY, WARN
|
||||
|
||||
|
||||
STATES = {'manual': 0,
|
||||
'high_pressure': 1,
|
||||
'circulating': 2,
|
||||
'warmup': 3,
|
||||
}
|
||||
|
||||
|
||||
class JTCCR(Writable):
|
||||
|
||||
compressor = Attached()
|
||||
|
||||
value = Parameter('current state', datatype=EnumType(STATES), default=0)
|
||||
target = Parameter('target state', datatype=EnumType(STATES), default=0)
|
||||
#p1min = Property('lower limit to switch to high pressure mode', dataype=FloatRange(unit='mbar'), default=1.8)
|
||||
p1max = Property('limit to switch to circulating mode', datatype=FloatRange(unit='mbar'), default=2.2)
|
||||
p2min = Property('lower limit to turn compressor off', datatype=FloatRange(unit='mbar'), default=0.12)
|
||||
p2max = Property('upper limit to turn compressor on', datatype=FloatRange(unit='mbar'), default=0.8)
|
||||
#p2lim = Property('do not start compressor if p2 is below this value', datatype=FloatRange(unit='mbar'), default=0.15)
|
||||
pdifmax = Property('max pressure difference of compressor', datatype=FloatRange(unit='mbar'), default=5.0)
|
||||
pdifmargin = Property('safety margin for pressure difference of compressor',
|
||||
datatype=FloatRange(unit='mbar'), default=1.0)
|
||||
p3margin = Property('start compressor when p3 is below pressreg setpoint plus this value',
|
||||
datatype=FloatRange(unit='mbar'), default=0.01)
|
||||
p3reg = Parameter('pressure regulation setpoint', datatype=FloatRange(unit='mbar'))
|
||||
plow = Property('pressure below 5K', datatype=FloatRange(unit='mbar'), default=4.0)
|
||||
|
||||
valves_high_pressure = {
|
||||
'close': 'V3 V4 V5 V6 V7 V8 V10',
|
||||
'open': 'V1 V2 V9 Vm',
|
||||
}
|
||||
valves_circulating = {
|
||||
'close': 'V3 V4 V5 V6 V7 V9 V10',
|
||||
'open': 'V1 V2 V8 Vm',
|
||||
}
|
||||
valves_warmup = {
|
||||
'close': 'V6 V7 V8 V9 V10',
|
||||
'open': 'V1 V2 V3 V4 V5 Vm',
|
||||
}
|
||||
valves_security= {
|
||||
'open': '',
|
||||
'close': 'V1 V9'
|
||||
}
|
||||
valves_overpressure = {
|
||||
'open': 'V10',
|
||||
'close': ''
|
||||
}
|
||||
|
||||
def write_target(self, target):
|
||||
if self.value != target:
|
||||
self.set_mode(STATES.get(target))
|
||||
return target
|
||||
|
||||
def set_mode(self, state):
|
||||
if state == 'high_pressure':
|
||||
self.p3reg = 12
|
||||
self.handle_valves(**self.valves_high_pressure)
|
||||
elif state == 'circulating':
|
||||
self.p3reg = self.plow
|
||||
self.handle_valves(**self.valves_circulating)
|
||||
elif state == 'warmup':
|
||||
self.handle_valves(**self.valves_warmup)
|
||||
self.value = state
|
||||
|
||||
def security_settings(self):
|
||||
self.compressor.write_target(False)
|
||||
self.handle_valves(**self.valves_security)
|
||||
self.set_mode('manual')
|
||||
|
||||
def handle_valves(self, close=(), open=()):
|
||||
"""set given valves. raises ImpossibleError, when checks fails"""
|
||||
self._valves_to_wait_for = {}
|
||||
self._valves_failed = {True: [], False: []}
|
||||
for flag, valves in enumerate([close, open]):
|
||||
for vname in valves.split():
|
||||
valve = self.secNode.modules[vname]
|
||||
valve.write_target(flag)
|
||||
# TODO: do we need to wait for motor valve?
|
||||
|
||||
def doPoll(self):
|
||||
p1 = self.secNode.module['P1'].read_value()
|
||||
p2 = self.secNode.module['P2'].read_value()
|
||||
p3 = self.secNode.module['P3'].read_value()
|
||||
compressor_state = self.compressor.read_value()
|
||||
if self.value == 'manual':
|
||||
return self.set_mode('manual')
|
||||
if p3 >= p2 + self.pdifmax + self.pdifmargin:
|
||||
# overpressure protection
|
||||
self.security_settings()
|
||||
self.status = WARN, 'overpressure: He recovery output closed?'
|
||||
return
|
||||
if p2 < self.p2min and p3 < self.p3reg and self.value != 'high_pressure':
|
||||
# underpressure protection
|
||||
self.security_settings()
|
||||
self.status = WARN, 'underpressure: not enough He'
|
||||
return
|
||||
if self.value == 'circulating':
|
||||
if p3 < self.p3reg and not compressor_state:
|
||||
self.compressor.write_target(True)
|
||||
elif (p3 - p2) > self.pdifmax and compressor_state:
|
||||
self.compressor.write_target(False)
|
||||
# TODO: do we need to skip overpressure protection for one time?
|
||||
if self.value == 'high_pressure' and p1 > self.p1max:
|
||||
self.set_mode('circulating')
|
||||
self.status = IDLE, ''
|
||||
if p2 > self.p2max and not compressor_state:
|
||||
self.compressor.write_target(True)
|
||||
elif p2 < self.p2min and compressor_state:
|
||||
self.compressor.write_target(False)
|
||||
if (p3 - p2) >= self.pdifmax + 0.1:
|
||||
self.handle_valves(**self.valves_overpressure)
|
||||
self.status = BUSY, 'release to recovery'
|
||||
elif self.secNode.modules['V10'].read_value():
|
||||
self.secNode.modules['V10'].write_target(False)
|
||||
self.status = IDLE, 'release finished'
|
||||
self.status = IDLE, ''
|
||||
Reference in New Issue
Block a user