fixes on picontrol and tdkpower

Change-Id: Ia891e7df23d8408b857dac795ed0ad9973ccf993
This commit is contained in:
zolliker 2025-04-08 17:15:17 +02:00
parent 09dce1aabd
commit fcf867675e
3 changed files with 33 additions and 66 deletions

View File

@ -6,7 +6,7 @@ Node('fi.psi.ch',
Mod('htr_io', Mod('htr_io',
'frappy_psi.tdkpower.IO', 'frappy_psi.tdkpower.IO',
'powersupply communicator', 'powersupply communicator',
uri='serial:///dev/ttyUSB0', uri='serial:///dev/ttyUSB0?baudrate=9600',
) )
Mod('htr', Mod('htr',
@ -16,7 +16,7 @@ Mod('htr',
) )
Mod('out', Mod('out',
'frappy_psi.bkpower.Output', 'frappy_psi.tdkpower.Output',
'heater output', 'heater output',
io='htr_io', io='htr_io',
maxvolt=8, maxvolt=8,
@ -54,7 +54,7 @@ Mod('T',
'frappy_psi.furnace.PI', 'frappy_psi.furnace.PI',
'controlled Temperature', 'controlled Temperature',
input='T_htr', input='T_htr',
output='out', output='htr',
relais='relais', relais='relais',
p=2, p=2,
i=0.01, i=0.01,

View File

@ -60,7 +60,7 @@ example cfg:
import time import time
import math import math
from frappy.core import Readable, Writable, Parameter, Attached, IDLE from frappy.core import Readable, Writable, Parameter, Attached, IDLE, Property
from frappy.lib import clamp from frappy.lib import clamp
from frappy.datatypes import LimitsType, EnumType, BoolType, FloatRange from frappy.datatypes import LimitsType, EnumType, BoolType, FloatRange
from frappy.mixins import HasOutputModule from frappy.mixins import HasOutputModule
@ -71,8 +71,9 @@ class PImixin(HasOutputModule, Writable):
p = Parameter('proportional term', FloatRange(0), readonly=False) p = Parameter('proportional term', FloatRange(0), readonly=False)
i = Parameter('integral term', FloatRange(0), readonly=False) i = Parameter('integral term', FloatRange(0), readonly=False)
# output_module is inherited # output_module is inherited
output_range = Parameter('min output', output_range = Property('legacy output range', LimitsType(FloatRange()), default=(0,0))
LimitsType(FloatRange()), default=(0, 0), readonly=False) output_min = Parameter('min output', FloatRange(), default=0, readonly=False)
output_max = Parameter('max output', FloatRange(), default=0, readonly=False)
output_func = Parameter('output function', output_func = Parameter('output function',
EnumType(lin=0, square=1), readonly=False, default=0) EnumType(lin=0, square=1), readonly=False, default=0)
value = Parameter(unit='K') value = Parameter(unit='K')
@ -80,6 +81,11 @@ class PImixin(HasOutputModule, Writable):
_lasttime = 0 _lasttime = 0
_clamp_limits = None _clamp_limits = None
def initModule(self):
super().initModule()
if self.output_range != (0, 0): # legacy !
self.output_min, self.output_max = self.output_range
def doPoll(self): def doPoll(self):
super().doPoll() super().doPoll()
if self._clamp_limits is None: if self._clamp_limits is None:
@ -93,8 +99,8 @@ class PImixin(HasOutputModule, Writable):
self._clamp_limits = lambda v, o=out: clamp(v, 0, o.read_limit()) self._clamp_limits = lambda v, o=out: clamp(v, 0, o.read_limit())
else: else:
self._clamp_limits = lambda v: v self._clamp_limits = lambda v: v
if self.output_range == (0.0, 0.0): if self.output_min == 0 and self.output_max == 0:
self.output_range = (0, self._clamp_limits(float('inf'))) self.output_max = self._clamp_limits(float('inf'))
if not self.control_active: if not self.control_active:
return return
self.status = IDLE, 'controlling' self.status = IDLE, 'controlling'
@ -114,7 +120,7 @@ class PImixin(HasOutputModule, Writable):
if self.output_func == 'square': if self.output_func == 'square':
output = output ** 2 output = output ** 2
output = self._clamp_limits(output) output = self._clamp_limits(output)
out.update_target(self.name, clamp(output, *self.output_range)) out.update_target(self.name, clamp(output, self.output_min, self.output_max))
def write_control_active(self, value): def write_control_active(self, value):
if not value: if not value:
@ -125,61 +131,6 @@ class PImixin(HasOutputModule, Writable):
self.activate_control() self.activate_control()
# quick fix by Marek:
class PIobsolete(Writable):
"""temporary, but working version from Marek"""
input = Attached(Readable, 'the input module')
output = Attached(Writable, 'the output module')
output_max = Parameter('max output value', FloatRange(0), readonly=False)
p = Parameter('proportional term', FloatRange(0), readonly=False)
i = Parameter('integral term', FloatRange(0), readonly=False)
control_active = Parameter('control flag', BoolType(), readonly=False, default=False)
value = Parameter(unit='K')
tlim = Parameter('max Temperature', FloatRange(0), readonly=False)
_lastdiff = None
_lasttime = 0
_lastvalue = 0
def doPoll(self):
super().doPoll()
if not self.control_active:
return
self.value = self.input.value
self.status = IDLE, 'controlling'
now = time.time()
deltat = min(10.0, now-self._lasttime)
self._lasttime = now
if self.value != self._lastvalue:
diff = self.target - self.value # calculate the difference to target
self._lastvalue = self.value
# else ? (diff is undefined!)
if self.value > self.tlim:
self.write_control_active(False)
return
if self._lastdiff is None:
self._lastdiff = diff
deltadiff = diff - self._lastdiff # calculate the change in deltaT
self._lastdiff = diff
output = self.output.target
output += self.p * deltadiff + self.i * deltat * diff
if output > self.output_max:
output = self.output_max
elif output < 0:
output = 0
self.output.write_target(output)
def write_control_active(self, value):
if not value:
self.output.write_target(0)
def write_target(self, value):
self.control_active = True
# proposal for replacing above PI class, inheriting from PImixin
# additional features:
# - is a Drivable, using the convergence criteria from HasConvergence
# - tries to determine the output limits automatically
# unchecked! # unchecked!
class PI(HasConvergence, PImixin): class PI(HasConvergence, PImixin):
@ -190,3 +141,18 @@ class PI(HasConvergence, PImixin):
def read_status(self): def read_status(self):
return self.input_module.status return self.input_module.status
class PI2(PI):
maxovershoot = Parameter('max. overshoot', FloatRange(0, 100, unit='%'), readonly=False, default=20)
def doPoll(self):
self.output_max = self.target * (1 + 0.01 * self.maxovershoot)
self.output_min = self.target * (1 - 0.01 * self.maxovershoot)
super().doPoll()
def write_target(self, target):
if not self.control_active:
self.output.write_target(target)
super().write_target(target)

View File

@ -24,10 +24,11 @@ from frappy.datatypes import BoolType, EnumType, FloatRange
class IO(StringIO): class IO(StringIO):
end_of_line = ('OK\r', '\r') end_of_line = '\r'
default_settings = {'baudrate': 9600} default_settings = {'baudrate': 9600}
identification = [('ADR 0', 'OK'), ('IDN?', r'LAMBDA,GEN8-400')]
class Power(HasIO, Readable): class Power(HasIO, Readable):
value = Parameter(datatype=FloatRange(0,3300,unit='W')) value = Parameter(datatype=FloatRange(0,3300,unit='W'))