Skip to content
Snippets Groups Projects
Commit e7b0ad55 authored by Daniele Nicolodi's avatar Daniele Nicolodi
Browse files

si5servo: Implement anti-windup compensation

parent 344d4881
No related branches found
No related tags found
No related merge requests found
...@@ -35,3 +35,50 @@ class PI2: ...@@ -35,3 +35,50 @@ class PI2:
self.acc1 += error * self.i1 self.acc1 += error * self.i1
self.acc2 += self.acc1 * self.i2 self.acc2 += self.acc1 * self.i2
return self.p * (error + self.acc1 + self.acc2) + self.o return self.p * (error + self.acc1 + self.acc2) + self.o
def clamp(v, vmin, vmax):
if v < vmin:
return vmin
if v > vmax:
return vmax
return v
class AntiWindupPI:
"""A PI control loop with anti-windup compensation.
Implement the back-calculation and tracking technique described in
K.J. Astrom, Control System Design, 2002, section 6.5, page 226.
https://www.cds.caltech.edu/~murray/courses/cds101/fa02/caltech/astrom-ch6.pdf
"""
def __init__(self, setpoint, vmin, vmax, p=0.0, i=0.0, o=0.0):
self.setpoint = setpoint
self.p = p
self.i = i
self.o = o
self.vmin = vmin
self.vmax = vmax
self.acc = 0.0
@property
def params(self):
return self.p, self.i, self.o
def update(self, value):
# Simple PI controller.
error = value - self.setpoint
self.acc += error * self.i
v = self.p * (error + self.acc) + self.o
# Actuator model.
u = clamp(v, self.vmin, self.vmax)
# Apply anti-windup compensation. There is no derivative gain
# and minimum measurement noise, thus it should be safe to Use
# unity tracking gain.
self.acc += (u - v) / self.p
return u
...@@ -65,10 +65,18 @@ def main(setpoint, params, frequency, amplitude, source, datadir, dataname): ...@@ -65,10 +65,18 @@ def main(setpoint, params, frequency, amplitude, source, datadir, dataname):
# Get output device. # Get output device.
output = rpc.Client(cryo124k.ADDRESS, cryo124k.TIMEOUT) output = rpc.Client(cryo124k.ADDRESS, cryo124k.TIMEOUT)
# Configure control loop. # Control loop parameters.
args = {name: float(value) for name, value in (param.split('=') for param in params)} args = {name: float(value) for name, value in (param.split('=') for param in params)}
args.setdefault('o', output.attr('output')) args.setdefault('o', output.attr('output'))
servo = control.PI2(setpoint=setpoint, **args)
# PI control loop with anti-windup. With the cryofan speed set to
# zero, there is no He circulation and the gas in the He circuit
# warms up to a temperature above the system temperature. When the
# He starts circulating again, the system temperature increases
# quickly instead of decreasing. To avoid this effect, always keep
# a minimum He flow by setting the minimum cryofan control voltage
# to 0.1 V.
servo = control.AntiWindupPI(setpoint=setpoint, vmin=0.1, vmax=10.0, **args)
# Log loop parameters. # Log loop parameters.
data = datalogger.open_data_file(datadir, dataname, None) data = datalogger.open_data_file(datadir, dataname, None)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment