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
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?