I am not sure whether I have chosen correct forum for my question. The question regards the implementation of a digital PID controller. From my point of view it is a kind of digital filter which is a chapter of the DSP.
I have implemented a digital version of the PID controller. The controller is implemented in the velocity (incremental) form. The implementation additionally includes the setpoint-weighting, the filtering of the derivative action and the bumpless transition between two control loops. The source code in the C language looks like that (let's look away from the fact that the function has a lot of parameters which can be gathered into the struct along with the controller state variables)
/**
* r - reference value (setpoint)
* y - controlled value
* t - tracking input
* T - execution period in seconds
* Kp - proportional gain
* b - weighting factor of the proportional component
* Ti - integration time constant in seconds
* Td - derivative time constant in seconds
* Nd - derivative filter coefficient
* u_min - minimum value of the action
* u_max - maximum value of the action
*/
float calculate(float r,
float y,
float t,
float T,
float Kp,
float b,
float Ti,
float Td,
float Nd,
float u_min,
float u_max)
{
static float r1 = 0.0; // previous value of the reference i.e. r(k-1)
static float y1 = 0.0; // previous value of the controlled variable i.e. y(k-1)
static float y2 = 0.0; // beforlast value fo the controlled variable i.e. y(k-2)
static float e1 = 0.0; // previous value of the error i.e. e(k-1)
static float u1 = 0.0; // previous value of the action i.e. u(k-1)
static float ud1 = 0.0; // previous value of the derivative component i.e. ud(k-1)
static float ud2 = 0.0; // beforelast value of the derivative component i.e. ud(k-2)
// integration gain
float Ki = Kp * T / (2.0f * Ti);
// weighting coefficient of the derivative component in derivative increment
// calculation
float ad;
// weighting coefficient of the controlled variable in derivative increment
// calculation
float bd;
if (Td > 0.0) {
ad = Td / (Nd * T + Td);
bd = (Kp * Td * Nd) / (Nd * T + Td);
} else {
ad = 0.0;
bd = 0.0;
}
// e(k) = r(k) - y(k)
float e = r - y;
// last action actually influencing the plant
u1 = t;
// dup(k)= kp*b*[r(k) - r(k-1)] - kp*[y(k) - y(k-1)]
float dup = Kp * b * (r - r1) - Kp * (y - y1);
// dui(k) = ki*[e(k) + e(k-1)]
float dui = Ki * (e + e1);
// dud(k) = ad*[ud(k-1) - ud(k-2)] - bd*[y(k) - 2*y(k-1) + y(k-2)]
float dud = ad * (ud1 - ud2) - bd * (y - 2.0f * y1 + y2);
// ud(k) = ud(k-1) + dud(k)
float ud = ud1 + dud;
// du(k) = dup(k) + dui(k)
float du = dup + dui + dud;
// u(k) = u(k-1) + du(k)
float u = u1 + du;
// anti-windup
if (u > u_max) {
u = u_max;
} else if (u < u_min) {
u = u_min;
}
// r(k-1) = r(k)
r1 = r;
// y(k-2) = y(k-1)
y2 = y1;
// y(k-1) = y(k)
y1 = y;
// e(k-1) = e(k)
e1 = e;
// u(k-1) = u(k)
u1 = u;
// ud(k-2) = ud(k-1)
ud2 = ud1;
// ud(k-1) = ud(k)
ud1 = ud;
return u;
}
I am not sure whether my implementation of the PID controller is correct. I have test it in a simulation in the Scilab and I have encountered following behavior. In case there is a constant reference value $r$ such that $r > y$ and the control error has negative sign (the controller has opposite action i.e. increase of the control error results in decrease of the action) the action is at the minimum of the controller output (let's say 0). In case there is some noise present on the signal of the controlled value $y$ there can occur a situation where the $\Delta u$ sign change occurrs. It means that the controller action leave its minimum and a spike of the action occurs.
For better understanding of the phenomenon I have described please see the output of my Scilab simulation with the PID controller with following parameters: $T = 100\cdot 10^{-6}\,\mathrm{s}, K_p = 0.003\,\mathrm{V^{-1}}, b = 1.0, T_i = 0.0024\,\mathrm{s}, T_d = 0.0\,\mathrm{s}, N_d = 0.0, u_{\mathrm{min}} = 0.0, u_{\mathrm{max}} = 1.0$
1. The reference and the actual value
2. The increments of the action
3. The action
From the graphs above it is obvious that the spikes on the action waveform are present in the points of time where the $\Delta u$ sign change occurs (the green waveform in the increments of the action near $0.004\,\mathrm{s}$ and $0.01\,\mathrm{s}$).
My question is whether the behavior I have described above is correct behavior of the PID controller or not. It seems to me that the phenomenom I have observed is rather related with inappropriate selection of the PID controller gains in respect to the plant than wrong implementation of the controller.
Derivation of the $\Delta u_p$
In case I have analog PID controller the proportional term with the setpoint-weighting will be implemented according to the below given formula
$$ u_p(t) = K_p\cdot [b\cdot r(t) - y(t)] $$
In case I have digital PID controller $t = k\cdot T$ i.e. the proportional term with the setpoint-weighting will have this form
$$ u_p(k) = K_p\cdot[b\cdot r(k) - y(k)] $$
The last formula is the valid formula for the position form of the digital PID controller but I have chosen different approach - the incremental (velocity) formula where only the increments of the action are calculated
$$ \Delta u_p(k) = u_p(k) - u_p(k-1) = K_p\cdot b\cdot [r(k)-r(k-1)] - K_p\cdot [y(k)-y(k-1)] $$