I programmed PID in MATLAB:

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

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

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

        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;

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

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

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

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

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

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

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);
hold on;

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?

  • \$\begingroup\$ I think this question is too general for EE and actually best fit in Signal Processing Stack Exchange here. \$\endgroup\$ – Unknown123 Apr 4 at 3:17
  • \$\begingroup\$ @Unknown123 I thought this is more related to control system than signal processing since it is dealing with PID. \$\endgroup\$ – Anthony Apr 4 at 7:54
  • \$\begingroup\$ 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. \$\endgroup\$ – Unknown123 Apr 4 at 8:11
  • \$\begingroup\$ @Unknown123 thanks, I'm trying SO, since signal processing has only 6 post tagged with PID and engineering seems too broad. \$\endgroup\$ – 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.

  • \$\begingroup\$ 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. \$\endgroup\$ – Anthony Apr 4 at 7:43
  • \$\begingroup\$ 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? \$\endgroup\$ – Anthony Apr 4 at 23:41
  • \$\begingroup\$ You need to edit getResponse to match the given difference equation. \$\endgroup\$ – TimWescott Apr 5 at 0:06
  • \$\begingroup\$ 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! \$\endgroup\$ – Anthony Apr 5 at 0:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.