Source code for hwtLib.logic.pid
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from hwt.code import Add
from hwt.interfaces.std import VectSignal
from hwt.interfaces.utils import addClkRstn
from hwt.synthesizer.hObjList import HObjList
from hwt.synthesizer.param import Param
from hwt.synthesizer.unit import Unit
[docs]class PidController(Unit):
"""
The PID Control block compares the input to the target
and calculates an error. Based on this error, a output value is calculated
that should result in a smaller error on the next iteration of the loop,
assuming your parameters are tuned properly.
u(k) = u(k-1) + a0*e(k) + a1*y(k) + a2*y(k-1) + a3*y(k-2)
e(k): error in this step (= target value - input)
y(k): input in step k
ax: PID coeficient
The PID parameter inputs for this equation are slightly different
from the traditional K_p, K_i, and K_d.
a0 = K_i * T_s
a1 = -K_p - K_d / T_s
a2 = K_p + 2K_d/T_s
a3 = - K_d / T_s
:note: You can obtain coeficiet e.g. by Ziegler-Nichols method.
.. hwt-autodoc::
"""
def _config(self):
self.DATAIN_WIDTH = Param(16)
self.DATAOUT_WIDTH = Param(16)
self.COEF_WIDTH = Param(16)
[docs] @staticmethod
def compute_coefs(K_p, K_i, K_d, T_s):
a0 = K_i * T_s
a1 = -K_p - K_d / T_s
a2 = K_p + 2 * K_d / T_s
a3 = -K_d / T_s
return [ int(x) for x in [a0, a1, a2, a3]]
def _declr(self):
addClkRstn(self)
self.input = VectSignal(self.DATAIN_WIDTH, signed=True)
self.output = VectSignal(self.DATAIN_WIDTH, signed=True)._m()
self.target = VectSignal(self.DATAIN_WIDTH, signed=True)
self.coefs = HObjList(
VectSignal(self.COEF_WIDTH, signed=True)
for _ in range(4)
)
def _impl(self):
u = self._reg("u", dtype=self.output._dtype, def_val=0)
err = self._sig("err", dtype=self.input._dtype)
err(self.input - self.target)
# create y-pipeline
y = [self.input, ]
for i in range(2):
_y = self._reg(f"y{i:d}", dtype=self.input._dtype, def_val=0)
_y(y[-1])
y.append(_y)
a = self.coefs
def trim(signal):
return signal._reinterpret_cast(self.output._dtype)
u(Add(u, a[0] * err, a[1] * y[0], a[2] * y[1], a[3] * y[2], key=trim))
self.output(u)
if __name__ == "__main__":
from hwt.synthesizer.utils import to_rtl_str
print(to_rtl_str(PidController()))