PID的微分部分及其低通滤波时域

时间:2019-04-04 10:03:26

标签: matlab simulink pid

我在MATLAB中编写了PID:

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

并使用随机低通滤波器作为工厂对其进行了测试:

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')

请注意,参数设置为kp=0;ki=1;kd=1;。我只在这里测试差分部分。结果是非常错误的:

enter image description here

请注意,Y轴的缩放比例为10 ^ 307。该值太大,以至于〜1.6s之后PID值超出了双精度范围,因此曲线停止。

我确保P和I部件都能正常工作(请参阅this question I asked a while ago)。

从D分量的曲线(见下图),可以清楚地看到它从一开始就开始剧烈振荡;第五个时间戳记0.04s后,其值达到> 50k:

enter image description here

我几乎可以肯定,在实现低通滤波器时一定犯了一个错误,但是我也注意到,即使去掉了低通滤波器,微分值的表现仍然相似。


为了提供某种参考和比较,我还使用完全相同的PID增益(即kp=0;ki=1;kd=1;)对同一系统进行了Simulink仿真。下面是方框图(左),输入和输出图(右上图)以及PID值(右下图)

enter image description here

请注意,增益块中没有上限/下限,并且初始输入/输出设置为零。

这些PID增益远未达到优化,但在仿真和编码PID中却给出了完全不同的结果。

因此,最大的问题是我在这里做错了吗?为什么两个结果之间有差异?

1 个答案:

答案 0 :(得分:2)

低通滤波器的实现不正确。低通滤波器的差分方程如下所示:

eq1: LowPass

getResponse函数的调用看起来像这样:

pid = PID(0,1,1,input(1),t(2)-t(1)); 
for i = 2:ss
    rPID(i) = pid.update(measured, t(i));   
    alpha = getResponse(0.25,0.01);
    output(i) = rPID(i)*alpha+(1-alpha)*output(i-1);   
    measured = output(i);
end

因此getResponse等于alpha

function r = getResponse(wc,Ts)
    r = 1 - exp(-wc*Ts);
end

此外,您必须在PID类中修改lowPass函数。

    function output = update(obj, measuredValue)
        err = obj.SetPoint - measuredValue;
        P = obj.getP(err);
        I = obj.getI(err);
        val = lowPass(obj,err,0.1,0.01);
        D = obj.getD(val);
        output = P + I + D;
    end
    % ...
    function val = lowPass(obj,err,wc,Ts)
        alpha = getResponse(wc,Ts);
        output = err*alpha+(1-alpha)*obj.output_1;  
        obj.output_1 = output;
        val = output;
    end

The resulting plot: