1 PID简介
PID即:Proportional(比例)、Integral(积分)、Differential(微分)的缩写。PID控制算法是结合比例、积分和微分三种环节于一体的控制算法。PID算法是连续系统中技术最为成熟、应用最为广泛的一种控制算法。
PID控制算法出现于20世纪30至40年代,适用于对被控对象模型了解不清楚的场合。实际运行的经验和理论的分析都表明,运用这种控制规律对许多工业过程进行控制时,都能得到比较满意的效果。
PID控制的实质就是根据输入的偏差值,按照比例、积分、微分的函数关系进行运算,运算结果用以控制输出。
2 PID控制原理
PID控制是基于反馈的闭环控制,根据控制对象输出反馈来进行校正。在测量出实际与计划发生偏差时,按定额或标准来进行纠正。比如控制一个电机的转速,就得有一个测量转速的传感器,并将结果反馈到控制路线上。
PID是比例 (Proportion) 积分 ,(Integral) 微分 ,(Differential coefficient) 的缩写,分别代表了三种控制算法。通过这三个算法的组合可有效地纠正被控制对象的偏差,从而使其达到一个稳定的状态。
比例KP
KP成比例的反应控制系统的偏差信号,一旦产生偏差,立即会产生控制作用,减小偏差。比例控制器的输出u(t)与输入偏差e(t)成正比,能迅速反映偏差,从而减小偏差,但不能消除静差。静差是指系统控制过程趋于稳定时,给定值与输出量的实测值之差。偏差存在,才能使控制器维持一定的控制量输出,因此比例控制器必然存在着静差。由偏差理论知,增大虽然可以减小偏差,但不能彻底消除偏差。比例控制作用的大小除与偏差e(t)有关之外,还取决于比例系数Kp的大小。比例系数Kp越小,控制作用越小,系统响应越慢;反之,比例系数Kp越大,控制作用也越强,则系统响应越快。但是,Kp过大会使系统产生较大的超调和振荡,导致系统的稳定性能变差。因此,不能将Kp选取过大,应根据被控对象的特性来折中选取Kp,使系统的静差控制在允许的范围内,同时又具有较快的响应速度。
积分KI
积分KI主要用于消除静态误差,提高系统的无差度。积分作用的强弱,取决于积分时间常数Ti,Ti越大积分作用越弱,反之则越强。积分控制作用的存在与偏差e(t)的存在时间有关,只要系统存在着偏差,积分环节就会不断起作用,对输入偏差进行积分,使控制器的输出及执行器的开度不断变化,产生控制作用以减小偏差。在积分时间足够的情况下,可以完全消除静差,这时积分控制作用将维持不变。Ti越小,积分速度越快,积分作用越强。但是,积分作用太强会使系统超调加大,甚至使系统出现振荡。
微分KD
微分KD能反映偏差信号的变化趋势(变化速率),并能在偏差信号的值变得太大之前,在系统中引入一个有效的早期修正信号,从而加快系统的动作速度,减小调节时间。积分控制作用的引入虽然可以消除静差,但是降低了系统的响应速度,特别是对于具有较大惯性的被控对象,用PI控制器很难得到很好的动态调节品质,系统会产生较大的超调和振荡,这时可以引入微分作用。在偏差刚出现或变化的瞬间,不仅根据偏差量作出及时反应(即比例控制作用),还可以根据偏差量的变化趋势(速度)提前给出较大的控制作用(即微分控制作用),将偏差消灭在萌芽状态,这样可以大大减小系统的动态偏差和调节时间,使系统的动态调节品质得以改善。微分环节有助于系统减小超调,克服振荡,加快系统的响应速度,减小调节时间,从而改善了系统的动态性能,但微分时间常数过大,会使系统出现不稳定。微分控制作用一个很大的缺陷是容易引入高频噪声,所以在干扰信号比较严重的系统中不宜引入微分控制作用。微分控制作用的阶跃响应特性对于一个恒定的偏差量,不管其数值有多大,微分控制作用均为零。因此,微分作用不能消除静差,单独使用意义不大,一般需要与比例、积分控制作用配合使用,构成PD或PID控制。
对于PID控制,在控制偏差输入为阶跃信号时,立即产生比例和微分控制中作用。由于在偏差输入的瞬时,变化率非常大,微分控制作用很强,此后微分控制作用迅速衰减,但积分作用越来越大,直至最终消除静差。PID控制综合了比例、积分、微分3种作用,既能加快系统响应速度、减小振荡、克服超调,亦能有效消除静差,系统的静态和动态品质得到很大改善,因而PID控制器在工业控制中得到了最为广泛的应用。
3 PID控制的公式:
在实际应用中,就需要离散化,因为时间t不可能无限小。
位置式PID:(输出的是实际控制值)
增量式PID:(输出的是变化值,需要加上原来的值才是实际控制值)
4 PID调参
在确定PID控制器参数时,可以根据控制器的参数与系统动态性能和稳态性能之间的定性关系,用实验的方法来调节控制器的参数。
PID调试一般原则:
a.在输出不振荡时,增大比例增益P。
b.在输出不振荡时,减小积分时间常数Ti。
c.在输出不振荡时,增大微分时间常数Td。
参数调整一般步骤
由于自动控制系统被控对象的千差万别,PID的参数也必须随之变化,调试PID参数的一般步骤:
a.确定比例增益
确定比例增益P时,首先去掉PID的积分项和微分项,一般是令Ti=0、Td=0,PID为纯比例调节。输入设定为系统允许的最大值的60%70%,由0逐渐加大比例增益P,直至系统出现振荡;再反过来,从此时的比例增益P逐渐减小,直至系统振荡消失,记录此时的比例增益P,设定PID的比例增益P为当前值的60%70%。比例增益P调试完成。
b.确定积分时间常数
比例增益P确定后,设定一个较大的积分时间常数Ti的初值,然后逐渐减小Ti,直至系统出现振荡,之后在反过来,逐渐加大Ti,直至系统振荡消失。记录此时的Ti,设定PID的积分时间常数Ti为当前值的150%~180%。积分时间常数Ti调试完成。
c.确定微分时间常数
微分时间常数Td一般不用设定,为0即可。若要设定,与确定P和Ti的方法相同,取不振荡时的30%。
d.系统空载、带载联调,再对PID参数进行微调,直至满足要求。
PID常用口诀
参数整定寻最佳,从大到小顺次查。
先是比例后积分,最后再把微分加。
曲线振荡很频繁,比例度盘要放大。
曲线漂浮绕大弯,比例度盘往小扳。
曲线偏离回复慢,积分时间往下降。
曲线波动周期长,积分时间再加长。
理想曲线两个波,调节过程高质量。
5 C语言代码实现:
5.1位置式PID控制算法,Kp,Ki,Kd三个参数,调试过程当中,对于要求的控制效果,可以通过调节这三个量直接进行调节。
// 位置式PID控制算法
struct _pid
{float SetSpeed; //定义设定值float ActualSpeed; //定义实际值float err; //定义偏差值float err_last; //定义上一个偏差值float Kp; //定义比例系数float Ki; //定义积分系数float Kd; //定义微分系数float voltage; //定义电压值(控制执行器的变量)float integral; //定义积分值
}pid;
void PID_init()
{pid.SetSpeed=0.0;pid.ActualSpeed=0.0;pid.err=0.0;pid.err_last=0.0;pid.voltage=0.0;pid.integral=0.0;pid.Kp=0.2;pid.Ki=0.015;pid.Kd=0.2;
}
float PID_realize(float speed)
{pid.SetSpeed=speed;pid.err=pid.SetSpeed-pid.ActualSpeed;pid.integral+=pid.err;pid.voltage=pid.Kp*pid.err+pid.Ki*pid.integral+pid.Kd*(pid.err-pid.err_last);pid.err_last=pid.err;pid.ActualSpeed=pid.voltage*1.0;return pid.ActualSpeed;
}int main()
{PID_init();int count=0;while(count<1000){float speed=PID_realize(100.0);printf("%f\n",speed);count++;}return 0;
}
5.2 增量型PID控制算法
struct _pid{float SetSpeed; //定义设定值float ActualSpeed; //定义实际值float err; //定义偏差值float err_next; //定义上一个偏差值float err_last; //定义最上前的偏差值float Kp; //定义比例系数float Ki; //定义积分系数float Kd; //定义微分系数
}pid;void PID_init()
{pid.SetSpeed=0.0;pid.ActualSpeed=0.0;pid.err=0.0;pid.err_last=0.0;pid.err_next=0.0;pid.Kp=0.15;pid.Ki=0.20;pid.Kd=0.25;
}
float PID_realize(float speed)
{pid.SetSpeed=speed;pid.err=pid.SetSpeed-pid.ActualSpeed;float incrementSpeed=pid.Kp*(pid.err-pid.err_next)+pid.Ki*pid.err+pid.Kd*(pid.err-2*pid.err_next+pid.err_last);pid.ActualSpeed+=incrementSpeed;pid.err_last=pid.err_next;pid.err_next=pid.err;return pid.ActualSpeed;
}
int main()
{PID_init();int count=0;while(count<1000){float speed=PID_realize(100.0);printf("%f\n",speed);count++;}return 0;
}