上一帖我们主要介绍了PID的概念,增量式PID算法和积分分离算法,这一贴我们主要讲PID的其他几种进阶算法。
一:抗积分饱和的PID控制
所谓的积分饱和现象是指如果系统存在一个方向的偏差,PID控制器的输出由于积分作用的不断累加而加大,从而导致执行机构达到极限位置,若控制器输出U(k)继续增大,执行器开度不可能再增大,此时计算机输出控制量超出了正常运行范围而进入饱和区。一旦系统出现反向偏差,u(k)逐渐从饱和区退出。进入饱和区越深则退出饱和区时间越长。在这段时间里,执行机构仍然停留在极限位置而不随偏差反向而立即做出相应的改变,这时系统就像失控一样,造成控制性能恶化,这种现象称为积分饱和现象或积分失控现象。
防止积分饱和的方法之一就是抗积分饱和法,该方法的思路是在计算u(k)时,首先判断上一时刻的控制量u(k-1)是否已经超出了极限范围: 如果u(k-1)>umax,则只累加负偏差; 如果u(k-1)<umin,则只累加正偏差。从而避免控制量长时间停留在饱和区。
C语言代码如下: - <font size="3">#include<stdio.h>
- #include<stdlib.h>
- #include<math.h>
- double IncreasementSpeed;
- int count;
- double Speed;
- struct _pid
- {
- double SetSpeed;//定义设定值
- double ActualSpeed;//定义实际值
- double err;//定义误差
- double err_last;//定义上上一次误差
- double Ki,Kp,Kd;//定义三个比例系数
- double err_next;//定义上一次误差
- double umax;
- double umin;
- double voltage;//定义执行机构的电压值
- double intergral;//定义积分值
- }pid;
- void pid_init()
- {
- pid.ActualSpeed=0.0;
- pid.err=0.0;
- pid.err_last=0.0;
- pid.err_next=0.0;
- pid.SetSpeed=0.0;
- pid.Kp=0.2;
- pid.Ki=0.1;
- pid.Kd=0.2;
- pid.umax=400;
- pid.umin=-200;
- }
- double PID_realize(double Speed)
- {
- int index;
- pid.SetSpeed=Speed;
- pid.err=pid.SetSpeed-pid.ActualSpeed;
- if(pid.ActualSpeed>pid.umax)
- {
- if(fabs(pid.err)>200)
- index=0;
- else
- {
- index=1;
- if(pid.err<0)
- pid.intergral+=pid.err;
- }
- }
- else if(pid.ActualSpeed<pid.umin)
- {
- if(fabs(pid.err)>200)
- index=0;
- else
- {
- index=1;
- if(pid.err>0)
- pid.intergral+=pid.err;
- }
- }
- else
- {
- if(fabs(pid.err)>200)
- index=0;
- else
- {
- index=1;
- pid.intergral+=pid.err;
- }
- }
- pid.voltage=pid.Kp*pid.err+index*pid.Ki*pid.intergral+pid.Kd*(pid.err-pid.err_last);
- pid.err_last=pid.err;
- pid.ActualSpeed=pid.voltage;
- return pid.ActualSpeed;
- }
- int main()
- {
- pid_init();
- while(count<1500)
- {
- double Speed=PID_realize(200.0);
- printf("%lf\t",Speed);
- count++;
- }
- return 0;
- }</font>
复制代码
结论:前后两次对比,我们发现系统的稳定速度明显加快。
二:积分优化——梯形积分
首先,我们要阐述一下什么是梯形积分。我们用的积分都是矩形积分,而梯形积分积分的优势就是可以消除余差,提高运算精度。画一个图理解 file:///C:\Users\john\AppData\Local\Temp\ksohtml\wpsC48D.tmp.png
b
a
矩形我们对其积分是∫(a+b)/2 dx,换成梯形积分为∫(c+a)/2,积分空出来的那两个地方就是余差。
我们仅仅需要改动一个地方:pid.voltage=pid.Kp*pid.err+index*pid.Ki*pid.integral/2+pid.Kd*(pid.err-pid.err_last); 代码就不贴了,可以发现积分精度提高了不少。
三:变积分的PID控制算法C语言实现 变积分PID可以看成是积分分离的PID算法的更一般的形式。在普通的PID控制算法中,由于积分系数ki是常数,所以在整个控制过程中,积分增量是不变的。但是,系统对于积分项的要求是,系统偏差大时,积分作用应该减弱甚至是全无,而在偏差小时,则应该加强。积分系数取大了会产生超调,甚至积分饱和,取小了又不能短时间内消除静差。因此,根据系统的偏差大小改变积分速度是有必要的。
变积分PID的基本思想是设法改变积分项的累加速度,使其与偏差大小相对应:偏差越大,积分越慢; 偏差越小,积分越快。
当abs(err)<180时,index=1; 当180<abs(err)<200时,index=(200-abs(err))/20;(此时快要达到阈值,放缓积分速度) 当abs(err)>200时,index=0; 最终的比例环节的比例系数值为ki*index;
- <font size="3"> #include<stdio.h>
- #include<stdlib.h>
- #include<math.h>
- double IncreasementSpeed;
- int count;
- double Speed;
- struct _pid
- {
- double SetSpeed;//定义设定值
- double ActualSpeed;//定义实际值
- double err;//定义误差
- double err_last;//定义上上一次误差
- double Ki,Kp,Kd;//定义三个比例系数
- double err_next;//定义上一次误差
- double voltage;//定义执行机构的电压值
- double intergral;//定义积分值
- }pid;
- void pid_init()
- {
- pid.ActualSpeed=0.0;
- pid.err=0.0;
- pid.err_last=0.0;
- pid.err_next=0.0;
- pid.SetSpeed=0.0;
- pid.Kp=0.4;
- pid.Ki=0.2;
- pid.Kd=0.2;
- }
- double PID_realize(double Speed)
- {
- double index;
- pid.SetSpeed=Speed;
- pid.err=pid.SetSpeed-pid.ActualSpeed;
- if(fabs(pid.err)>200)
- index=0;
- else if(fabs(pid.err)<180)
- {
- index=1;
- pid.intergral+=pid.err;
- }
- else
- {
- index=(200-fabs(pid.err))/20;
- pid.intergral+=pid.err;
- }
- pid.voltage=pid.Kp*pid.err+index*pid.Ki*pid.intergral+pid.Kd*(pid.err-pid.err_last);
- pid.err_last=pid.err;
- pid.ActualSpeed=pid.voltage;
- return pid.ActualSpeed;
- }
- int main()
- {
- pid_init();
- while(count<1500)
- {
- double Speed=PID_realize(200.0);
- printf("%lf\t",Speed);
- count++;
- }
- return 0;
- }</font>
复制代码
结论:系统稳定的时间非常快! 今天写到这里结束,PID的所有算法已经介绍完毕,下一篇介绍模糊算法和专家算法的控制理念。
|