# Digital PID controller implementation

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
// 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 {
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)]$$

• Why not try a PID controller with a static reference at first. Make it work. Then add a varying reference.
– Ben
Commented Nov 29, 2022 at 21:49
• @Ben thank you for your reaction. I am sorry whether my description isn't clear. As you can see on my first graph the simulation includes constant reference value (800.0) and variable controlled value (more or less 660.0 with some noise). As far as the situation when both the reference and the controlled value are constant. I have verified that the suggested algorithm works in such scenario. The problems arised only in the above mentioned case. Commented Nov 29, 2022 at 21:58
• Ok what is this line ? float dup = Kp * b * (r - r1) - Kp * (y - y1); If r = r1 and y = y1. Then no corrective action will occur, right? Are you sure that's what you want?
– Ben
Commented Nov 29, 2022 at 22:10
• @Ben it is the setpoint-weightening algorithm which has been modified for the incremental (velocity) form of the digital PID controller. As far as the situation you have mentioned. In this scenario the corrective action will be given by the dui, dud values and the previous value of the corrective action. Commented Nov 30, 2022 at 9:07
• How about, you implement a simple PID... and make it work? Then add more features like setpoint-weightening and so on...
– Ben
Commented Nov 30, 2022 at 13:07

As Ben says in the comments, if r = r1 and y = y1, then dup will be zero.

More usually (see lines 21 and 27 of this implementation), the think Kp multiplies is the error between the set-point and the reference.

What

float dup = Kp * b * (r - r1) - Kp * (y - y1);


calculates is Kp multiplying the derivative of the set-point minus the derivative of the reference. Here, I'm using derivative loosely, it's the one-sample difference and doesn't take account of the sample rate.

Something more like

float dup = Kp * b * (r - y);


is what I'd expect for the proportional term in your implementation.

• thank you very much for your response. As far as the dup term calculation. It implements the setpoint-weighting algorithm modified for the velocity form of the digital PID controller. I will append its derivation into my question. Commented Nov 30, 2022 at 6:24