pounder_test/stabilizer.py

106 lines
3.1 KiB
Python
Raw Normal View History

2019-05-28 02:44:01 +08:00
import json
import asyncio
2019-05-28 17:49:07 +08:00
from collections import OrderedDict as OD
2019-05-28 02:44:01 +08:00
import logging
import numpy as np
logger = logging.getLogger()
class StabilizerError(Exception):
pass
class StabilizerConfig:
async def connect(self, host, port=1235):
self.reader, self.writer = await asyncio.open_connection(host, port)
async def set(self, channel, iir):
2019-05-28 17:49:07 +08:00
up = OD([("channel", channel), ("iir", iir.as_dict())])
2019-05-28 02:44:01 +08:00
s = json.dumps(up, separators=(",", ":"))
assert "\n" not in s
logger.debug("send %s", s)
self.writer.write(s.encode() + b"\n")
r = (await self.reader.readline()).decode()
logger.debug("recv %s", r)
2019-05-28 17:49:07 +08:00
ret = json.loads(r, object_pairs_hook=OD)
2019-05-28 02:44:01 +08:00
if ret["code"] != 200:
raise StabilizerError(ret)
return ret
class IIR:
t_update = 2e-6
def __init__(self):
self.ba = np.zeros(5, np.float32)
self.y_offset = 0.
self.y_min = -float(1 << 15)
self.y_max = float(1 << 15) - 1
def as_dict(self):
2019-05-28 17:49:07 +08:00
iir = OD()
2019-05-28 02:44:01 +08:00
iir["ba"] = [float(_) for _ in self.ba]
iir["y_offset"] = self.y_offset
iir["y_min"] = self.y_min
iir["y_max"] = self.y_max
return iir
def configure_pi(self, kp, ki, g=0.):
ki = np.copysign(ki, kp)*self.t_update*2
g = np.copysign(g, kp)
eps = np.finfo(np.float32).eps
if abs(ki) < eps:
a1, b0, b1 = 0., kp, 0.
else:
if abs(g) < eps:
c = 1.
else:
c = 1./(1. + ki/g)
a1 = 2*c - 1.
b0 = ki*c + kp
b1 = ki*c - a1*kp
if abs(b0 + b1) < eps:
raise ValueError("low integrator gain and/or gain limit")
self.ba[0] = b0
self.ba[1] = b1
self.ba[2] = 0.
self.ba[3] = a1
self.ba[4] = 0.
def set_x_offset(self, o):
2019-05-28 17:49:07 +08:00
b = self.ba[:3].sum()*((1 << 15) - 1)
2019-05-28 02:44:01 +08:00
self.y_offset = b*o
if __name__ == "__main__":
import argparse
p = argparse.ArgumentParser()
p.add_argument("-s", "--stabilizer", default="10.0.16.99")
p.add_argument("-c", "--channel", default=0, type=int,
help="Stabilizer channel to configure")
p.add_argument("-o", "--offset", default=0., type=float,
2019-05-28 17:49:07 +08:00
help="input offset, in units of full scale")
2019-05-28 02:44:01 +08:00
p.add_argument("-p", "--proportional-gain", default=1., type=float,
2019-05-28 17:49:07 +08:00
help="Proportional gain, in units of 1")
2019-05-28 02:44:01 +08:00
p.add_argument("-i", "--integral-gain", default=0., type=float,
2019-05-28 17:49:07 +08:00
help="Integral gain, in units of Hz, "
"sign taken from proportional-gain")
2019-05-28 02:44:01 +08:00
args = p.parse_args()
loop = asyncio.get_event_loop()
# loop.set_debug(True)
logging.basicConfig(level=logging.DEBUG)
async def main():
i = IIR()
i.configure_pi(args.proportional_gain, args.integral_gain)
i.set_x_offset(args.offset)
s = StabilizerConfig()
await s.connect(args.stabilizer)
2019-05-28 17:49:07 +08:00
r = await s.set(args.channel, i)
2019-05-28 02:44:01 +08:00
loop.run_until_complete(main())