• PID控制器改进笔记之一:改进PID控制器之参数动态调整


      前面我们发布了一系列PID控制器相关的文章,包括经典PID控制器以及参数自适应的PID控制器。这一系列PID控制器虽说实现了主要功能,也在实际使用中取得了良好效果,但还有很多的细节部分可以改进以提高性能和灵活性。所以在这篇中我们来讨论改进PID控制器以实现动态调整参数的目的。

    1、提出问题

      在我们一开始开发PID控制器时,我们主要是关注于其算法的实现而没有过多的关心其使用过程。但在我们的使用过程中发现有些不够灵活的地方。

      在原有的PID控制器中,设定值是通过在外部给PID对象的参数赋值实现的,虽然说并不影响使用,但我们若想对PID控制器中的参数设定值进行某些处理就不是很方便了。而在原有的PID控制器中,输出值在外部是不可见的,只能通过PID对象查看且不可更改。这些使得对这些参数的操作显得不够灵活。

      而且在原有的PID控制器中3个调节参数也不能在外部随时调整,这显然不符合很多应用的需要,因为PID参数的调整是很常见的工作。所以在这篇中我们来考虑实现这些参数的动态调整。

    2、分析设计

      为了使得PID控制器使用起来更为灵活,我们需要将PID对象作必要的改动。关于PID对象我们考虑将测量值、设定值、输出值作为对象的属性。但我们不是直接将这几个变量作为对象属性,因为这样达不到我们从外部灵活操作的目的,我们将几个指向浮点变量的指针作为对象的属性,而初始化后这几个指针将指向我们的测量值、设定值、输出值变量。

      同样的三个PID参数我们想要在外部修改它,我们也将其在外部定义为变量,而在PID对象中定义为指向这三个变量的浮点数指针。在对对象进行初始化时,我们将变量地址赋值给这几个指针。据此我们定义PID对象类型为:

     1 /*定义结构体和公用体*/
     2 typedef struct CLASSIC
     3 {
     4   float *pPV;                   //测量值指针
     5   float *pSV;                   //设定值指针
     6   float *pMV;                   //输出值指针
     7   float *pKp;                   //比例系数指针
     8   float *pKi;                   //积分系数指针
     9   float *pKd;                   //微分系数指针
    10  
    11   float setpoint;               //设定值
    12   float lasterror;              //前一拍偏差
    13   float preerror;               //前两拍偏差
    14   float deadband;               //死区
    15   float result;                 //PID控制器计算结果
    16   float output;                 //输出值0-100%
    17   float maximum;                //输出值上限
    18   float minimum;                //输出值下限
    19   float errorabsmax;            //偏差绝对值最大值
    20   float errorabsmin;            //偏差绝对值最小值
    21   float alpha;                  //不完全微分系数
    22   float deltadiff;              //微分增量
    23   float integralValue;          //积分累计量
    24   float gama;                   //微分先行滤波系数
    25   float lastPv;                 //上一拍的过程测量值
    26   float lastDeltaPv;            //上一拍的过程测量值增量
    27 }CLASSICPID;

    3、软件实现

      我们计划将PID参数和过程变量改成指向浮点型变量的指针,那么代码上需要做哪些修改呢?需要修改的主要是两个函数:PID调节函数和PID对象初始化函数。

      首先,我们来看一看PID对象的初始化函数。我们知道将这些变量修改为指向浮点变量法的指针后,我们就必须在初始化时指定具体的变量地址,否则指向的将是不可预知的位置。所以我们修改初始化函数如下:

     1 /* PID初始化操作,需在对vPID对象的值进行修改前完成 */
     2 void PIDParaInitialization(CLASSICPID *vPID,    //PID控制器对象
     3                            float *pPV,          //测量值指针
     4                            float *pSV,          //设定值指针
     5                            float *pMV,          //输出值指针
     6                            float *pKp,          //比例系数指针
     7                            float *pKi,          //积分系数指针
     8                            float *pKd,          //微分系数指针
     9                            float vMax,          //控制变量量程
    10                            float vMin,          //控制变量的零点
    11                              )
    12 {
    13   if((vPID==NULL)||(pPV==NULL)||(pSV==NULL)||(pMV==NULL)||(pKp==NULL)||(pKi==NULL)||(pKd==NULL))
    14   {
    15     return;
    16   }
    17   vPID->pPV=pPV;
    18   vPID->pSV=pSV;
    19   vPID->pMV=pMV;
    20   vPID->pKp=pKp;
    21   vPID->pKi=pKi;
    22   vPID->pKd=pKd;
    23  
    24   vPID->maximum=vMax;                /*输出值上限*/
    25   vPID->minimum=vMin;                /*输出值下限*/
    26  
    27   vPID->setpoint=*pPV;               /*设定值*/
    28  
    29   vPID->lasterror=0.0;              /*前一拍偏差*/
    30   vPID->preerror=0.0;               /*前两拍偏差*/
    31   vPID->result=vMin;                /*PID控制器结果*/
    32   vPID->output=0.0;                 /*输出值,百分比*/
    33  
    34   vPID->errorabsmax=(vMax-vMin)*0.8;
    35   vPID->errorabsmin=(vMax-vMin)*0.2;
    36  
    37   vPID->deadband=(vMax-vMin)*0.0005;               /*死区*/
    38   vPID->alpha=0.2;                  /*不完全微分系数*/
    39   vPID->deltadiff=0.0;                /*微分增量*/
    40  
    41   vPID->integralValue=0.0;
    42  
    43   vPID->mode=mode;
    44 }

      其次,我们还需要修改PID调节函数。在原来的PID调节器中过程值是作为函数的参数输入的,而且PID参数是作为变量存在于对象内部的,所以要针对这两个方面做相应的修改:

     1 /* 通用PID控制器,采用增量型算法,具有变积分,梯形积分和抗积分饱和功能,微分项采用不完全微分,一阶滤波,alpha值越大滤波作用越强                    */
     2 void PIDRegulator(CLASSICPID *vPID)
     3 {
     4   float thisError;
     5   float result;
     6   float factor;
     7   float increment;
     8   float pError,dError,iError;
     9  
    10   vPID->setpoint=*vPID->pSV;
    11   thisError=vPID->setpoint-(*vPID->pPV); //得到偏差值
    12   result=vPID->result;
    13   if (fabs(thisError)>vPID->deadband)
    14   {
    15     pError=thisError-vPID->lasterror;
    16     iError=(thisError+vPID->lasterror)/2.0;
    17     dError=thisError-2*(vPID->lasterror)+vPID->preerror;
    18    
    19     //变积分系数获取
    20      factor=VariableIntegralCoefficient(thisError,vPID->errorabsmax,vPID->errorabsmin);
    21    
    22     //计算微分项增量带不完全微分
    23       vPID->deltadiff=(*vPID->pKd)*(1-vPID->alpha)*dError+vPID->alpha*vPID->deltadiff;
    24        
    25       increment=(*vPID->pKp)*pError+(*vPID->pKi)*factor*iError+vPID->deltadiff;   //增量计算
    26     }
    27     else
    28     {
    29       if((fabs(vPID->setpoint-vPID->minimum)<vPID->deadband)&&(fabs((*vPID->pPV)-vPID->minimum)<vPID->deadband))
    30       {
    31         result=vPID->minimum;
    32       }
    33       increment=0.0;
    34     }
    35  
    36       result=result+increment;
    37   
    38     /*对输出限值,避免超调和积分饱和问题*/
    39     if(result>=vPID->maximum)
    40     {
    41       result=vPID->maximum;
    42     }
    43     if(result<=vPID->minimum)
    44     {
    45       result=vPID->minimum;
    46     } 
    47  
    48     vPID->preerror=vPID->lasterror;  //存放偏差用于下次运算
    49     vPID->lasterror=thisError;
    50     vPID->result=result;
    51  
    52     vPID->output=(vPID->result-vPID->minimum)/(vPID->maximum-vPID->minimum)*100.0;
    53  
    54       *vPID->pMV=vPID->output;
    55   }
    56 }

    4、总结

      我们将PID参数和过程变量都改为了对象所包含的指针,这样当我们从上位机或者其他进程修改变量的值时,也同步修改了PID对象中的值。测试的结果比原来的方式操作更为方便。

    欢迎关注:

  • 相关阅读:
    C语言移动一个点
    C语言数据结构无向图
    C语言学生管理系统(C语言课程设计/精简版)
    C语言贪吃蛇
    2017蓝桥杯九宫幻方(C++B组)
    2017蓝桥杯Excel地址(C++C组)
    2017蓝桥杯杨辉三角(C++C组)
    2017蓝桥杯算式900(C++C组)
    2017蓝桥杯兴趣小组(C++C组)
    javascript 的默认对象
  • 原文地址:https://www.cnblogs.com/foxclever/p/12537507.html
Copyright © 2020-2023  润新知