PID算法实现及参数整定图解+代码

电子常识

2612人已加入

描述

  PID是比例-积分-微分控制的简称,也是一种控制算法,其特点是结构改变灵活、技术成熟、适应性强。

  对一个控制系统而言,由于控制对象的精确数学模型难以建立,系统的参数经常发生变化,运用控制理论综合分析要耗费很大的代价,却不能得到预期的效果,所以人们往往采用PID调节器,根据经验在线整定参数,以便得到满意的控制效果。随着计算机特别是微机技术的发展,PID控制算法已能用微机简单实现,由于软件系统的灵活性,PID算法可以得到修正而更加完善。

  PID

  PID参数的工程整定方法

  数字PID调节器与模拟PID调节器控制思想完全一样,只是实现的物理过程不同,数字PID调节器参数的整定方法也和模拟PID调节器基本相同,只是增加了自整定功能。

  参数整定的方法很多,我们只介绍几种工程上最常用的方法。最实用的是试凑法。

  1、自整法

  现在的数字调节器,大多采用了模糊控制技术进行PID调节。

  模糊控制基于专家知识或熟练操作者的成熟经验,并可通过学习不断更新。因而它具有智能性和自学习性,是一种人工智能调节方式。PID参数的自整功能,模拟专家操作,自动寻优,整定出最佳参数,使之达到理想的控制效果。我们在使用调节器时,应首先启动自整功能,看一看整定的结果和控制效果,这是一个向专家系统学习的过程。自整定结果,也不一定都是最佳参数,有时还需我们进一步寻优。关于启动自整功能的方法,请阅读有关的说明书,非常简单。

  2、逐试法

  将PID参数之一增加或减少30~50%,如果控制效果变好,则继续增加或减少该参数,否则往反方向调整,直到效果满足要求。

    3、临界值整定性


       ①比例+积分调节器 a、积分时间置于最大; b、置TD=0;

  c、从一个比较大的比例带逐步降低,每降低一次等待一定的时间,观察记录表上或记录纸上被控参量的记录曲线,直至记录曲线出现周期性振荡,然后在这一点上再加大比例带,直到不出现振荡;

  D、减少积分时间,每减一次同样等待一定的时间,观察记录曲线,当它低于由过程的滞后特性所决定的某个临界值时,曲线又出现周期性振荡,然后在这点上缓慢地加大积分时间直至振荡停止。

  ②比例+积分+微分调节器

        a、积分时间置于最大;
 
        b、微分时间置于最小;

  c、用上方法减小比例带至周期性振荡出现;

  d、加大微分时间,使周期性振荡停止,再减小比例带,使振荡重新出现,再加大微分时间,使振荡停止,重复上述过程至加大微分时间后振荡不再停止。再增大比例带至周期性振荡停止。

  E、取积分时间为微分时间的2~5倍,如果周期性振荡出现,加大积分时间至振荡停止。

  4、经验整定法

  根据PID控制原理和系统的特性,结合自己的经验,直接设置PID参数,然后再根据控制效果做进一步的修改。

  当调节器输出变化很小,而引起测量值(被控参量)变化较大时,应将比例带置于较大的数值,反之亦然。当调节器输出变化,很快引起被控参量的变化,则积分和微分时间的整定就应较小,对于快速的流量系统则可以不加入微分运算,反之亦然。熟悉系统的特性是整定PID参数的关键。最后分析两个温度调节系统,加深对上述内容的理解。

  例1:果冻条封口温控系统,采用佳能电子CNG-5181智能数字调节仪出厂时参数设定为P=20,I=130,d=30,置设定值SV=150℃,PV达到SV时,启动自整定功能,大约在20分钟左右,自整结束。P=15,I=236,d=59。进入PID控制后,PV很快稳定在上150℃上,当设定值改为155℃,PV很快又稳定在155℃,动静态品质均非常理想,实际上采用出厂设定参数值也能获得满意的控制效果。

  例2,联苯锅炉用于化纤纺丝管道伴热,工艺温度为290℃~300℃,温控器选用日本岛电公司SR74型PID自整定温控仪,出厂设定值为P=3,I=120,D=30,在该参数下,温度波动较大为295℃±3℃。启动自整定功能,约1小时后,整定出的PID参数为P=0.3,I=1168,D=292,显示温度始终为295℃,改变设定值为300℃时。显示温度又始终为300℃。

  点评:果冻条封口温控系统属于小型温控系统,系统灵敏度高,热惯性小,滞后时间短,所以比例带较大,积分、微分时间常数均比较小。或者说比例、微分作用较弱,积分作用较强。例2中的温控系统属于大型的调节系统,灵敏度低,热惯性大,滞后时间长,所以整定出的PID参数和例1相反,比例带较小,积分和微分时间常数均较大,且TI≈4TD。

  1)临界比例度法

  这是目前使用较广的一种方法,具体作法如下:

  先在纯比例作用下(把积分时间放到最大,微分时间放到零),在闭合的调节系统中,从大到小地逐渐地改变调节器的比例度,就会得到一个临界振荡过程,如图8所示。这时的比例度叫临界比例度δk,周期为临界振荡周期Tk。记下δk和Tk,然后按表1的经验公式来确定调节器的各参数值。

  PID

  PID

  表1 临界比例度法数据表

  这种方法在下面两种情况下不宜采用:

  a)临界比例度过小,因为这时候调节阀很容易处于全开及全关位置,对于工艺生产不利,举例来说,对于一个用燃料油(或瓦斯)加热的炉子,如δ很小,接近双位调节,将一会儿熄火,一会儿烟囱浓烟直冲。

  b)工艺上约束条件较严格时,因为这时候如达到等幅振荡,将影响生产的安全运行。

  2)衰减曲线法

  临界比例度法是要系统等幅振荡,还要多次试凑,而用衰减曲线法较简单,一般又有两种方法。

  (1)4:1衰减曲线法

  使系统处于纯比例作用下,在达到稳定时,用改变给定值的办法加入阶跃干扰,观察记录曲线的衰减比,然后逐渐从大到小改变比例度,使出现4:1的衰减比为止,如下图所示。记下此时的比例度δs和Ts的值,再按表2的经验公式来确定PID数值。

  PID

  表2 4:1衰减曲线法数据表

  (2)10:1衰减曲线法

  有的过程,4:1衰减仍嫌振荡过强,可采用10:1衰减曲线法。方法同上,得到10:1衰减曲线,记下此时的比例度δ's和上升时间T's,再按表3的经验公式来确定PID的数值。衰减曲线如下图所示。

  PID

  表3 10:1衰减曲线法数据表

  采用衰减曲线法必须注意几点:

  a)加给定干扰不能太大,要根据生产操作要求来定,一般在5%左右,也有例外的情况。

  b)必须在工艺参数稳定的情况下才能加给定干扰,否则得不到正确得δs、Ts、或δ's和T's值。

  c)对于反应快的系统,如流量、管道压力和小容量的液位调节等,要在记录纸上严格得到4:1衰减曲线较困难,一般以被调参数来回波动两次达到稳定,就近似地认为达到4:1衰减过程了。

  下面举一个现场整定的例子。在某塔顶温度调节系统中,被调参数是塔顶温度,工艺允许波动为<4℃,调节参数是回流量。在整定过程中,考虑到对象滞后较大,反应较慢的情况,δ的选择从50%开始凑试起,此时在阶跃作用下(给定值降低2%)的过渡过程曲线见下图(a)。此时调节时间长,不起振荡,于是将比例度减少,δ=30%、20%、及10%时的曲线见(b)、(c)、(d)。显然,20%的情况最好,衰减比接近4:1,Ts=10分。

  按4:1衰减曲线法数据表定出整定参数:

  δ=0.8·δs=16%;

  Ti=0.3·Ts=3分;

  Td=0.1·Ts=1分。

  投运时,先将δ放在较大的数值,把Ti从大减少到3分,把Td从小到大逐步放大到1分,然后把δ拉到15%,(如果在δ=15%的条件下很快地把Td放到1分,调节器的输出会剧烈变化)。再对系统加2% 的给定值变化时,仍产生4:1衰减过程,见图(e)所示,调节质量显著改善,超调量小于1℃,调节时间为6.5分。

  PID

 PID

  3)经验试凑法

  这是在生产实践中所总结出来的方法,目前应用最为广泛,其步骤简述如下:

  (1)确定KP

  可用“优选法”,详见下表

  表4 优选法确定KP

  PID

  (2)看曲线,调参数,根据操作经验,看曲线的形状,直接在闭合的调节系统中逐步反复试凑,一直得到满意数据。

  在实践中,把具体整定的方法总结了几段顺口溜:

  参数整定找最佳,从大到小顺次查,先是比例后积分,最后才把微分加;曲线振荡很频繁,比例度值要放大, //比例度放大即比例系数KP要减小。曲线漂浮绕大弯,比例度值应减小;曲线偏离回复慢,积分时间往下降,曲线振荡周期长,积分时间再加长;曲线振荡频率快,先把微分降下来,动差大来波动慢,微分时间应加长;理想曲线两个波,前高后低四比一,一看二调多分析,调节质量不会低。

  第一段讲的是整定顺序,δ和Ti都是从大到小逐步加上去,微分是最后才考虑的。第二段讲的是比例度如何整定。第三段讲的是积分时间如何整定。第四段讲的是微分时间如何整定。第五段讲的是标准。

  上面这种方法步骤是先加δ,再加Ti,最后才加Td。应用中较稳妥。

  另一种方法是先从表列范围内取Ti的某个数值,如果需要微分,则取Td=(1/3~1/4)Ti,然后对δ进行试凑,也能较快地达到要求。

  常用PID控制参数的经验值如下图所示。

  PID

  PID算法的定义:

  P:比例控制项。 I:积分控制项。 D:微分控制项。

  设当前输出量为U,我们的期望值或是设定值为U0,则可得当前时刻误差:E=U-U0;

  PID算法即是对误差量E及E的历史进行某种线性组合得到控制量的算法。

  一般形式:

  Up=P*E;

  Ui=i*(E+E_1+E_2+.。。) E_n为之前的第n次误差.

  Ud=i*(E-E_1)

  U=Up+Ui+Ud; U为PID控制输出量.

  上式中Ui的计算不太方便,长时间单方向的累加将可能出现溢出,于是将上式改为如下所示的增量形式:

  Up=p*(E-E_1) 比例项增量

  Ui=i*(E-2*E_1+E_2) 微分项增量

  Ud=i*E 积分项增量

  U=Uout_1+Up+Ui+Ud U为PID控制输出量,Uout_1为前次PID输出值

  Uout=U 保存本次值

  对于上面的公式或理论,便可得到相应的C语言程序:

  //======================定义PID结构=========================

  static float MinValue; //最大值限制

  static float MaxValue; //最小值限制

  static float CurrentValue; //当前采样值

  static struct PID{

  float Ki; //定义积分常数

  float Kp; //定义比例常数

  float Kd; //定义微分常数

  float E_2; //存储前前次误差

  float E_1; //存诸前次误差

  float E; //存储本次误差

  float OutPut; //本次输出量

  float ValueSet; //设定值或期望值

  }Control;

  //===========================PID计算函数=====================

  void PidWork() {

  float Up,Ud,Ui;

  Control.E=CurrentValue-Control.ValueSet; //得到本次误差

  Up =Control.Kp*(Control.E-Control.E_1); //得到比例项

  Ud=Control.Kd*(Control.E-2*Control.E_1+Control.E_2); //得到微分项

  Ui=Control.Ki*Control.E; //得到积分项

  Control.E_2=Control.E_1; //历史存储

  Control.E_1=Control.E;

  Control.OutPut+=Up+Ud+Ui; //计算增量和

  if(Control.OutPut

  else if(Control.OutPut》MaxValue)Control.OutPut=MaxValue;

  }

  //==========================初始化速度=========================

  void PidInit() {

  MinValue=0;

  MaxValue=1000;

  CurrentValue=0;

  Control.Kp=-6;

  Control.Ki=-1.5;

  Control.Kd=-0.5;

  Control.E=0;

  Control.E_2=0;

  Control.E_1=0;

  Control.ValueSet=100;

  Control.OutPut=0;

  }

  以上三个函数为PID的主体函数,也是万用PID函数.代码量已经相当精简了。注意上面的PID初始化函数中有Kp,Ki,Kd的符号一定要正确,否则输出量方向相反,后果不堪设想!!!

  附上一段完整代码:

  #include

  struct _pid {

  int pv; /*integer that contains the process value*/

  int sp; /*integer that contains the set point*/

  float integral;

  float pgain;

  float igain;

  float dgain;

  int deadband;

  int last_error;

  };

  struct _pid warm,*pid;

  int process_point, set_point,dead_band;

  float p_gain, i_gain, d_gain, integral_val,new_integ;;

  /*------------------------------------------------------------------------

  pid_init

  DESCRIPTION This function initializes the pointers in the _pid structure

  to the process variable and the setpoint. *pv and *sp are

  integer pointers.

  ------------------------------------------------------------------------*/

  void pid_init(struct _pid *warm, int process_point, int set_point)

  {

  struct _pid *pid;

  pid = warm;

  pid-》pv = process_point;

  pid-》sp = set_point;

  }

  /*------------------------------------------------------------------------

  pid_tune

  DESCRIPTION Sets the proportional gain (p_gain), integral gain (i_gain),

  derivitive gain (d_gain), and the dead band (dead_band) of

  a pid control structure _pid.

  ------------------------------------------------------------------------*/

  void pid_tune(struct _pid *pid, float p_gain, float i_gain, float d_gain, int dead_band)

  {

  pid-》pgain = p_gain;

  pid-》igain = i_gain;

  pid-》dgain = d_gain;

  pid-》deadband = dead_band;

  pid-》integral= integral_val;

  pid-》last_error=0;

  }

  /*------------------------------------------------------------------------

  pid_setinteg

  DESCRIPTION Set a new value for the integral term of the pid equation.

  This is useful for setting the initial output of the

  pid controller at start up.

  ------------------------------------------------------------------------*/

  void pid_setinteg(struct _pid *pid,float new_integ)

  {

  pid-》integral = new_integ;

  pid-》last_error = 0;

  }

  /*------------------------------------------------------------------------

  pid_bumpless

  DESCRIPTION Bumpless transfer algorithim. When suddenly changing

  setpoints, or when restarting the PID equation after an

  extended pause, the derivative of the equation can cause

  a bump in the controller output. This function will help

  smooth out that bump. The process value in *pv should

  be the updated just before this function is used.

  ------------------------------------------------------------------------*/

  void pid_bumpless(struct _pid *pid)

  {

  pid-》last_error = (pid-》sp)-(pid-》pv);

  }

  /*------------------------------------------------------------------------

  pid_calc

  DESCRIPTION Performs PID calculations for the _pid structure *a. This function uses the positional form of the pid equation, and incorporates an integral windup prevention algorithim. Rectangular integration is used, so this function must be repeated on a consistent time basis for accurate control.

  RETURN VALUE The new output value for the pid loop.

  USAGE #include ‘control.h’*/

  float pid_calc(struct _pid *pid)

  {

  int err;

  float pterm, dterm, result, ferror;

  err = (pid-》sp) - (pid-》pv);

  if (abs(err) 》 pid-》deadband)

  {

  ferror = (float) err; /*do integer to float conversion only once*/

  pterm = pid-》pgain * ferror;

  if (pterm 》 100 || pterm 《》

  {

  pid-》integral = 0.0;

  }

  else

  {

  pid-》integral += pid-》igain * ferror;

  if (pid-》integral 》 100.0)

  {

  pid-》integral = 100.0;

  }

  else if (pid-》integral 《 0.0)=“” pid-=“”》integral = 0.0;

  }

  dterm = ((float)(err - pid-》last_error)) * pid-》dgain;

  result = pterm + pid-》integral + dterm;

  }

  else result = pid-》integral;

  pid-》last_error = err;

  return (result);

  }

  void main(void)

  {

  float display_value;

  int count=0;

  pid = &warm;

  // printf(‘Enter the values of Process point, Set point, P gain, I gain, D gain \n’);

  // scanf(‘%d%d%f%f%f’, &process_point, &set_point, &p_gain, &i_gain, &d_gain);

  process_point = 30;

  set_point = 40;

  p_gain = (float)(5.2);

  i_gain = (float)(0.77);

  d_gain = (float)(0.18);

  dead_band = 2;

  integral_val =(float)(0.01);

  printf(‘The values of Process point, Set point, P gain, I gain, D gain \n’);

  printf(‘ %6d %6d %4f %4f %4f\n’, process_point, set_point, p_gain, i_gain, d_gain);

  printf(‘Enter the values of Process point\n’);

  while(count《》

  {

  scanf(‘%d’,&process_point);

  pid_init(&warm, process_point, set_point);

  pid_tune(&warm, p_gain,i_gain,d_gain,dead_band);

  pid_setinteg(&warm,0.0); //pid_setinteg(&warm,30.0);

  //Get input value for process point

  pid_bumpless(&warm);

  // how to display output

  display_value = pid_calc(&warm);

  printf(‘%f\n’, display_value);

  //printf(‘\n%f%f%f%f’,warm.pv,warm.sp,warm.igain,warm.dgain);

  count++;

  }

  }

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
评论(0)
发评论
jf_71285317 2022-01-29
0 回复 举报
好文章 收起回复
cooldog123pp 2019-03-19
0 回复 举报
好文章!!! 收起回复

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分