mercury, ips, sea, triton, convergence
after gerrit Change-Id: Iff14047ecc476589aef10c96fae9970133b8bd14
This commit is contained in:
@ -21,7 +21,7 @@
|
||||
"""oxford instruments mercury IPS power supply"""
|
||||
|
||||
import time
|
||||
from frappy.core import Parameter, EnumType, FloatRange, BoolType, IntRange, StringType, Property, BUSY
|
||||
from frappy.core import Parameter, EnumType, FloatRange, BoolType, IntRange, Property, Module
|
||||
from frappy.lib.enum import Enum
|
||||
from frappy.errors import BadValueError, HardwareError
|
||||
from frappy_psi.magfield import Magfield, SimpleMagfield, Status
|
||||
@ -41,16 +41,16 @@ class SimpleField(MercuryChannel, SimpleMagfield):
|
||||
voltage = Parameter('leads voltage', FloatRange(unit='V'), default=0)
|
||||
atob = Parameter('field to amp', FloatRange(0, unit='A/T'), default=0)
|
||||
working_ramp = Parameter('effective ramp', FloatRange(0, unit='T/min'), default=0)
|
||||
channel_type = 'PSU'
|
||||
kind = 'PSU'
|
||||
slave_currents = None
|
||||
classdict = {}
|
||||
|
||||
def __new__(cls, name, logger, cfgdict, srv):
|
||||
base = cls.__bases__[1]
|
||||
def __new__(cls, name, logger, cfgdict, srv): # pylint: disable=arguments-differ
|
||||
nunits = cfgdict.get('nunits', 1)
|
||||
if isinstance(nunits, dict):
|
||||
nunits = nunits['value']
|
||||
if nunits == 1:
|
||||
obj = object.__new__(cls)
|
||||
return obj
|
||||
return Module.__new__(cls, name, logger, cfgdict, srv)
|
||||
classname = cls.__name__ + str(nunits)
|
||||
newclass = cls.classdict.get(classname)
|
||||
if not newclass:
|
||||
@ -62,8 +62,7 @@ class SimpleField(MercuryChannel, SimpleMagfield):
|
||||
|
||||
newclass = type(classname, (cls,), attrs)
|
||||
cls.classdict[classname] = newclass
|
||||
obj = object.__new__(newclass)
|
||||
return obj
|
||||
return Module.__new__(newclass, name, logger, cfgdict, srv)
|
||||
|
||||
def initModule(self):
|
||||
super().initModule()
|
||||
@ -73,34 +72,34 @@ class SimpleField(MercuryChannel, SimpleMagfield):
|
||||
self.log.error('can not set to hold %r', e)
|
||||
|
||||
def read_value(self):
|
||||
return self.query('PSU:SIG:FLD')
|
||||
return self.query('DEV::PSU:SIG:FLD')
|
||||
|
||||
def read_ramp(self):
|
||||
return self.query('PSU:SIG:RFST')
|
||||
return self.query('DEV::PSU:SIG:RFST')
|
||||
|
||||
def write_ramp(self, value):
|
||||
return self.change('PSU:SIG:RFST', value)
|
||||
return self.change('DEV::PSU:SIG:RFST', value)
|
||||
|
||||
def read_action(self):
|
||||
return self.query('PSU:ACTN', hold_rtoz_rtos_clmp)
|
||||
return self.query('DEV::PSU:ACTN', hold_rtoz_rtos_clmp)
|
||||
|
||||
def write_action(self, value):
|
||||
return self.change('PSU:ACTN', value, hold_rtoz_rtos_clmp)
|
||||
return self.change('DEV::PSU:ACTN', value, hold_rtoz_rtos_clmp)
|
||||
|
||||
def read_atob(self):
|
||||
return self.query('PSU:ATOB')
|
||||
return self.query('DEV::PSU:ATOB')
|
||||
|
||||
def read_voltage(self):
|
||||
return self.query('PSU:SIG:VOLT')
|
||||
return self.query('DEV::PSU:SIG:VOLT')
|
||||
|
||||
def read_working_ramp(self):
|
||||
return self.query('PSU:SIG:RFLD')
|
||||
return self.query('DEV::PSU:SIG:RFLD')
|
||||
|
||||
def read_setpoint(self):
|
||||
return self.query('PSU:SIG:FSET')
|
||||
return self.query('DEV::PSU:SIG:FSET')
|
||||
|
||||
def set_and_go(self, value):
|
||||
self.setpoint = self.change('PSU:SIG:FSET', value)
|
||||
self.setpoint = self.change('DEV::PSU:SIG:FSET', value)
|
||||
assert self.write_action(Action.hold) == Action.hold
|
||||
assert self.write_action(Action.run_to_set) == Action.run_to_set
|
||||
|
||||
@ -133,7 +132,7 @@ class SimpleField(MercuryChannel, SimpleMagfield):
|
||||
|
||||
class Field(SimpleField, Magfield):
|
||||
persistent_field = Parameter(
|
||||
'persistent field', FloatRange(unit='$'), readonly=False)
|
||||
'persistent field at last switch off', FloatRange(unit='$'), readonly=False)
|
||||
wait_switch_on = Parameter(
|
||||
'wait time to ensure switch is on', FloatRange(0, unit='s'), readonly=True, default=60)
|
||||
wait_switch_off = Parameter(
|
||||
@ -142,7 +141,7 @@ class Field(SimpleField, Magfield):
|
||||
'manual indication that persistent field is bad', BoolType(), readonly=False, default=False)
|
||||
|
||||
_field_mismatch = None
|
||||
__init = True
|
||||
__persistent_field = None # internal value of persistent field
|
||||
__switch_fixed_until = 0
|
||||
|
||||
def doPoll(self):
|
||||
@ -154,33 +153,41 @@ class Field(SimpleField, Magfield):
|
||||
# will complain and this will be handled in start_ramp_to_field
|
||||
self.switch_on_time = 0
|
||||
self.switch_off_time = 0
|
||||
self.switch_heater = self.query('PSU:SIG:SWHT', off_on)
|
||||
self.switch_heater = self.query('DEV::PSU:SIG:SWHT', off_on)
|
||||
super().startModule(start_events)
|
||||
|
||||
def read_value(self):
|
||||
current = self.query('PSU:SIG:FLD')
|
||||
pf = self.query('PSU:SIG:PFLD')
|
||||
if self.__init:
|
||||
self.__init = False
|
||||
self.persistent_field = pf
|
||||
if self.switch_heater == self.switch_heater.on or self._field_mismatch is None:
|
||||
current = self.query('DEV::PSU:SIG:FLD')
|
||||
if self.switch_heater == self.switch_heater.on:
|
||||
self.__persistent_field = current
|
||||
self.forced_persistent_field = False
|
||||
self._field_mismatch = False
|
||||
return current
|
||||
self._field_mismatch = abs(self.persistent_field - pf) > self.tolerance
|
||||
return pf
|
||||
pf = self.query('DEV::PSU:SIG:PFLD')
|
||||
if self.__persistent_field is None:
|
||||
self.__persistent_field = pf
|
||||
self._field_mismatch = False
|
||||
else:
|
||||
self._field_mismatch = abs(self.__persistent_field - pf) > self.tolerance * 10
|
||||
self.persistent_field = self.__persistent_field
|
||||
return self.__persistent_field
|
||||
|
||||
def _check_adr(self, adr):
|
||||
"""avoid complains about bad slot"""
|
||||
if adr.startswith('DEV:PSU.M'):
|
||||
return
|
||||
super()._check_adr(adr)
|
||||
|
||||
def read_current(self):
|
||||
if self.slave_currents is None:
|
||||
self.slave_currents = [[] for _ in range(self.nunits + 1)]
|
||||
if self.nunits > 1:
|
||||
for i in range(1, self.nunits + 1):
|
||||
curri = self.query('DEV:PSU.M%d:PSU:SIG:CURR' % i)
|
||||
volti = self.query('DEV:PSU.M%d:PSU:SIG:VOLT' % i)
|
||||
setattr(self, 'I%d' % i, curri)
|
||||
setattr(self, 'V%d' % i, volti)
|
||||
curri = self.query(f'DEV:PSU.M{i}:PSU:SIG:CURR')
|
||||
volti = self.query(f'DEV:PSU.M{i}:PSU:SIG:VOLT')
|
||||
setattr(self, f'I{i}', curri)
|
||||
setattr(self, f'V{i}', volti)
|
||||
self.slave_currents[i].append(curri)
|
||||
current = self.query('PSU:SIG:CURR')
|
||||
current = self.query('DEV::PSU:SIG:CURR')
|
||||
self.slave_currents[0].append(current)
|
||||
min_ = min(self.slave_currents[0]) / self.nunits
|
||||
max_ = max(self.slave_currents[0]) / self.nunits
|
||||
@ -194,14 +201,15 @@ class Field(SimpleField, Magfield):
|
||||
if min_i - 0.1 > max_ or min_ > max_i + 0.1: # use an arbitrary 0.1 A tolerance
|
||||
self.log.warning('individual currents mismatch %r', self.slave_currents)
|
||||
else:
|
||||
current = self.query('PSU:SIG:CURR')
|
||||
current = self.query('DEV::PSU:SIG:CURR')
|
||||
if self.atob:
|
||||
return current / self.atob
|
||||
return 0
|
||||
|
||||
def write_persistent_field(self, value):
|
||||
if self.forced_persistent_field:
|
||||
if self.forced_persistent_field or abs(self.__persistent_field - value) <= self.tolerance * 10:
|
||||
self._field_mismatch = False
|
||||
self.__persistent_field = value
|
||||
return value
|
||||
raise BadValueError('changing persistent field needs forced_persistent_field=True')
|
||||
|
||||
@ -212,7 +220,7 @@ class Field(SimpleField, Magfield):
|
||||
return super().write_target(target)
|
||||
|
||||
def read_switch_heater(self):
|
||||
value = self.query('PSU:SIG:SWHT', off_on)
|
||||
value = self.query('DEV::PSU:SIG:SWHT', off_on)
|
||||
now = time.time()
|
||||
if value != self.switch_heater:
|
||||
if now < self.__switch_fixed_until:
|
||||
@ -226,10 +234,10 @@ class Field(SimpleField, Magfield):
|
||||
return value
|
||||
|
||||
def read_wait_switch_on(self):
|
||||
return self.query('PSU:SWONT') * 0.001
|
||||
return self.query('DEV::PSU:SWONT') * 0.001
|
||||
|
||||
def read_wait_switch_off(self):
|
||||
return self.query('PSU:SWOFT') * 0.001
|
||||
return self.query('DEV::PSU:SWOFT') * 0.001
|
||||
|
||||
def write_switch_heater(self, value):
|
||||
if value == self.read_switch_heater():
|
||||
@ -238,20 +246,20 @@ class Field(SimpleField, Magfield):
|
||||
return value
|
||||
self.__switch_fixed_until = time.time() + 10
|
||||
self.log.debug('switch time fixed for 10 sec')
|
||||
result = self.change('PSU:SIG:SWHT', value, off_on, n_retry=0) # no readback check
|
||||
result = self.change('DEV::PSU:SIG:SWHT', value, off_on, n_retry=0) # no readback check
|
||||
return result
|
||||
|
||||
def start_ramp_to_field(self, sm):
|
||||
if abs(self.current - self.persistent_field) <= self.tolerance:
|
||||
self.log.info('leads %g are already at %g', self.current, self.persistent_field)
|
||||
if abs(self.current - self.__persistent_field) <= self.tolerance:
|
||||
self.log.info('leads %g are already at %g', self.current, self.__persistent_field)
|
||||
return self.ramp_to_field
|
||||
try:
|
||||
self.set_and_go(self.persistent_field)
|
||||
self.set_and_go(self.__persistent_field)
|
||||
except (HardwareError, AssertionError) as e:
|
||||
if self.switch_heater:
|
||||
self.log.warn('switch is already on!')
|
||||
return self.ramp_to_field
|
||||
self.log.warn('wait first for switch off current=%g pf=%g %r', self.current, self.persistent_field, e)
|
||||
self.log.warn('wait first for switch off current=%g pf=%g %r', self.current, self.__persistent_field, e)
|
||||
sm.after_wait = self.ramp_to_field
|
||||
return self.wait_for_switch
|
||||
return self.ramp_to_field
|
||||
@ -274,7 +282,7 @@ class Field(SimpleField, Magfield):
|
||||
sm.try_cnt -= 1
|
||||
if sm.try_cnt < 0:
|
||||
raise
|
||||
self.set_and_go(sm.persistent_field)
|
||||
self.set_and_go(self.__persistent_field)
|
||||
return Retry
|
||||
|
||||
def wait_for_switch(self, sm):
|
||||
@ -283,14 +291,14 @@ class Field(SimpleField, Magfield):
|
||||
try:
|
||||
self.log.warn('try again')
|
||||
# try again
|
||||
self.set_and_go(self.persistent_field)
|
||||
except (HardwareError, AssertionError) as e:
|
||||
self.set_and_go(self.__persistent_field)
|
||||
except (HardwareError, AssertionError):
|
||||
return Retry
|
||||
return sm.after_wait
|
||||
|
||||
def wait_for_switch_on(self, sm):
|
||||
self.read_switch_heater() # trigger switch_on/off_time
|
||||
if self.switch_heater == self.switch_heater.OFF:
|
||||
if self.switch_heater == self.switch_heater.off:
|
||||
if sm.init: # avoid too many states chained
|
||||
return Retry
|
||||
self.log.warning('switch turned off manually?')
|
||||
@ -299,7 +307,7 @@ class Field(SimpleField, Magfield):
|
||||
|
||||
def wait_for_switch_off(self, sm):
|
||||
self.read_switch_heater()
|
||||
if self.switch_heater == self.switch_heater.ON:
|
||||
if self.switch_heater == self.switch_heater.on:
|
||||
if sm.init: # avoid too many states chained
|
||||
return Retry
|
||||
self.log.warning('switch turned on manually?')
|
||||
@ -307,6 +315,9 @@ class Field(SimpleField, Magfield):
|
||||
return super().wait_for_switch_off(sm)
|
||||
|
||||
def start_ramp_to_zero(self, sm):
|
||||
pf = self.query('DEV::PSU:SIG:PFLD')
|
||||
if abs(pf - self.value) > self.tolerance * 10:
|
||||
self.log.warning('persistent field %g does not match %g after switch off', pf, self.value)
|
||||
try:
|
||||
assert self.write_action(Action.hold) == Action.hold
|
||||
assert self.write_action(Action.run_to_zero) == Action.run_to_zero
|
||||
|
Reference in New Issue
Block a user