关于增量式PID的代码(C语言)实现的详细说明
网上可以找到很多关于增量式PID的一些解释说明;
最终都可以得到如下的公式:
Δu=Kp·{e(n)-e(n-1)}+Ki·e(n)+Kd·{e(n)-2·e(n-1)+e(n-2)} ;
最终转换成代码有很多是
typedef struct
{
float Kp; //比例系数Proportional
float Ki; //积分系数Integral
float Kd; //微分系数Derivative
float Ek; //当前误差
float Ek1; //前一次误差 e(k-1)
float Ek2; //再前一次误差 e(k-2)
}PID_IncTypeDef;
//非本人编写
float PID_Inc(float SetValue, float ActualValue, PID_IncTypeDef *PID)
{
float PIDInc; //增量
PID->Ek = SetValue - ActualValue;
PIDInc = (PID->Kp * PID->Ek) - (PID->Ki * PID->Ek1) + (PID->Kd * PID->Ek2);
PID->Ek2 = PID->Ek1;
PID->Ek1 = PID->Ek; return PIDInc;
}
有些人对代码存在一定的疑惑,其实代码是没有问题的;
公式为:
Δu=Kp·{e(n)-e(n-1)}+Ki·e(n)+Kd·{e(n)-2·e(n-1)+e(n-2)}
整理为:
Δu=(Kp+Ki)·e(n)-(Kp+2)·e(n-1)+Kd·e(n-2)
由于Pid需要整定参数、因而可以将上式三项误差前的数当作一个整体;
即表示为:
Δu=KP·e(n)-KI·e(n-1)+KD·e(n-2)
将上式对比代码、则可以得出、代码是符合公式的
当然我们也可以将代码完全按照公式来描述
typedef struct{
float limit; //输出限幅
float target; //目标输出量
float feedback; //实际输出量
float Kp;
float Ki;
float Kd;
float e_0; //当前误差
float e_1; //上一次误差
float e_2; //上上次误差
}PID;
#define max(a, b) (a>b? a:b)
#define min(a, b) (a<b? a:b)
#define range(x, a, b) (min(max(x, a), b))
#define exchange(a, b, tmp) (tmp=a, a=b, b=tmp)
#define myabs(x) ((x<0)? -x:x)
float pid_calc(PID *pid)
{
float out;
float ep, ei, ed;
pid->e_0 = pid->target - pid->feedback;
ep = pid->e_0 - pid->e_1;
ei = pid->e_0;
ed = pid->e_0 - 2*pid->e_1 + pid->e_2;
out = pid->Kp*ep + pid->Ki*ei + pid->Kd*ed;
out = range(out, -pid->limit, pid->limit);
pid->e_2 = pid->e_1;
pid->e_1 = pid->e_0;
return out;
}
个人还是比较建议第二种写法!调参的时候也更加直观一点;