# How to implement low pass filter in the differential part of PID in time domain

I programmed PID in MATLAB:

classdef PID < handle
properties
Kp = 0
Ki = 0
Kd = 0
SetPoint = 1
Dt = 0.01
end

properties (Access = private)
IState = 0
PreErr = 0
end

methods
function obj = PID(Kp, Ki, Kd, SetPoint, Dt)
if nargin == 0
return;
end
obj.Kp = Kp;
obj.Ki = Ki;
obj.Kd = Kd;
obj.SetPoint = SetPoint;
obj.Dt = Dt;
end

function output = update(obj, measuredValue, t)
err = obj.SetPoint - measuredValue;
P = obj.getP(err);
I = obj.getI(err);
val = lowPass(obj,t);
D = obj.getD(err*val);
output = P + I + D;
end

function val = getP(obj, err)
val = obj.Kp*err;
end

function val = getI(obj, err)
obj.IState = obj.IState + err * obj.Dt;
val = obj.Ki * obj.IState;
end

function val = getD(obj, err)
val = obj.Kd * (err - obj.PreErr) / obj.Dt;
obj.PreErr = err;
end

function val = lowPass(obj,t)
N = 10;
val = 1-exp(-N*t);
end
end
end


And tried implementing it using a random low pass filter as the plant:

function r = getResponse(t)
r = 1 - exp(-5*t);
end


The implementation:

sr = 1e2; % sampling rate 100Hz
st = 10; % sampling time 10s
ss = st*sr+1; % sample size
t = 0:1/sr:st; % time

input = ones(1,ss)*100;
output = zeros(1,ss);
measured = 0;

pid = PID(0,1,1,input(1),t(2)-t(1));
for i = 2:ss
rPID(i) = pid.update(measured, t(i));
output(i) = rPID(i)*getResponse(t(i));
measured = output(i);
end
figure
plot(t,output)
hold on;
plot(t,input)
plot(t,rPID)
legend('Output','Input','PID')


Note that the parameters are set to kp=0;ki=1;kd=1;. I'm only testing the differential part here. The result is very wrong:

Notice the Y-axis is scaled by 10^307. It gets too big that after ~1.6s, the PID value exceeds the range of double precision and therefore, no more values for it. D values, in fact, start to oscillate too much from the beginning:

I have made sure that both P and I parts work well enough (see Values got from programmed PID are different from ones simulated in Simulink), so the mistake is only from the differential path. I'm almost certain I must have made a mistake in implementing the low pass filter, but I also noticed that even if I remove the low pass filter, the differential values are still very unstable.

I also made a simulation of the PID in Simulink, using the exact same parameters, and here is the result:

I know these gains for PID are not optimised but they work in the simulation not in my programmatic PID.

Therefore the big question is am I doing something wrong here? Why is there a difference between the simulated result and it obtained with the programmatic PID?

• I think this question is too general for EE and actually best fit in Signal Processing Stack Exchange here. – Unknown123 Apr 4 at 3:17
• @Unknown123 I thought this is more related to control system than signal processing since it is dealing with PID. – Anthony Apr 4 at 7:54
• Unfortunately, it's actually spreaded: stackoverflow, engineering, signal processing, electrical engineering has all PID Q&A available. Still in my opinion, PID can be related into non-electrical or not, depending on the pretext and context. In my opinion for now, if you haven't got any better answer for a given period of time try to ask it in other SE. – Unknown123 Apr 4 at 8:11
• @Unknown123 thanks, I'm trying SO, since signal processing has only 6 post tagged with PID and engineering seems too broad. – Anthony Apr 4 at 10:04

First, you are confused in how to implement a low-pass filter, and you're getting this wrong both for the derivative term and for your plant. A good difference equation to use to implement a 1st-order low-pass filter is $$\x_k = (u_k - x_{k-1})(1-d)\$$, where $$\x_k\$$ is the filter output, $$\u_k\$$ is the filter input, and $$\d\$$ is the filter's pole position in the $$\z\$$ domain (it's up to you to translate this to your quasi-continuous-time model).

A good first approximation for $$\d\$$ for your plant is $$\\left(5\mathrm{\frac{rad}{s}}\right)T_s\$$, where $$\T_s = \frac{1}{100 \mathrm{Hz}}\$$.

Note that the above difference equation does not depend on time, but does depend on the input. If you think you're writing a difference equation for a system, and your equation doesn't depend on the input signal -- you're doing something wrong!

The thing you're computing is the unit step response of a low-pass filter.

As it stands now, you've described a time-varying system that just loops the PID controller back on itself, with a varying gain.

A good test would be to run just the plant simulation, once with a step, and once with a pulse -- you should see markedly different results.

• Thanks for helping. It didn't work without the filter until I lowered it to 0.001, which basically ignores the derivative path. I'm trying to compare my results with the exact same parameters fed into a simulink simulated PID. I believe I should get a similar result but I'm not getting one. – Anthony Apr 4 at 7:43
• Do you mean that I need to plug the returned value from getResponse in the difference equation which would then give me the correct measured value? – Anthony Apr 4 at 23:41
• You need to edit getResponse to match the given difference equation. – TimWescott Apr 5 at 0:06
• reading If you think you're writing a difference equation for a system, and your equation doesn't depend on the input signal -- you're doing something wrong! twice and I now understand. Thank you very much! – Anthony Apr 5 at 0:59