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

MATLABpid controllersimulink

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:

enter image description here

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:

enter image description here

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:

enter image description here

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?

Best Answer

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.