前面我们发布了一系列PID控制器相关的文章,包括经典PID控制器以及参数自适应的PID控制器。这一系列PID控制器虽说实现了主要功能,也在实际使用中取得了良好效果,但还有很多的细节部分可以改进以提高性能和灵活性。所以在这篇中我们来讨论改进PID控制器以串级调节等复杂控制方式。
1、提出问题
我们前面提到的PID控制器其实都是基于单回路来考虑的。但有些时候同一个被控对象可能会受到2个控制变量的影响,或者说为了实现一个被控对象更精确的控制需要同时引入两个控制变量才能得到更好的效果。这个时候我们可以将对被控对象起主要作用的控制变量定义为主变量,相应的控制器作为主控制器;而将对被控对象起次要作用的控制变量定义为从变量,相应的控制器作为从控制器。于是一个串级调节系统就建立起来了。
由以上的控制方框图我们可以知道,如果将副回路看作一个整体的执行单元的话,主控制回路就是一个单回路的PID控制。同样只考虑副回路的话也只是一个单回路的PID控制。但有所不同的是副回路的设定值并非由我们输入给它的,而是由主控制器的输出施加给它的。所以,我们想解决PID控制器的串联问题,需要考虑的就是处理如何将主控制器输出施加给副控制器作为设定的问题。
2、分析设计
我们已经提出了实现PID控制器串级需要考虑的主要问题。接下里我们需要分析采用什么办法解决这一问题并将其数字化。在此,我们先来考虑一下几个方面的问题。
第一个问题是主控制器的输出方式。一般来说,PID算法输出的是实际物理量值的大小。在我们的PID控制器中我们输出了实际物理量值和百分比。
第二个问题是副控制器的输入方式。对于PID控制器设定值输入肯定是与控制变量的物理量相对应的。很显然以主控制器的物理量值作为副控制器的设定输入肯定是不合适的。所以我们只有以百分比的方式作为副控制器设定值的输入。
第三个问题是主副控制器的结合问题。既然以主控制器百分比输出作为副控制器的设定输入。而副控制器的设定值为物理量,我们需要根据百分比和副控制变量的量程来获得副控制器的真正设定值。
第四个问题是PID算法该如何调整。对PID算法的调整并不复杂,事实上我们只需要根据是否是串级来处理设定值就好了。如果不是串级就正常处理;如果是串级就需要根据输入和量程来计算设定值。我们可以用如下的流程图来说明:
为了保持PID控制器算法的严谨性,我们并不需要将这段处理设定值的操作添加到PID控制算法内部,而只需要独立处理完设定值的计算并赋值就可以了。
3、软件实现
我们已经设计了如何实现PID控制器串级的方式。我们还需要将其算法以软件的方式实现才能真正获得我们想要的结果。
首先,我们在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 if(*vPID->pMA<1) //手动模式
11 {
12 vPID->output=*vPID->pMV;
13 //设置无扰动切换
14 vPID->result=(vPID->maximum-vPID->minimum)*vPID->output/100.0+-vPID->minimum;
15 *vPID->pSV=*vPID->pPV;
16 vPID->setpoint=*vPID->pSV;
17 }
18 else //自动模式
19 {
20 if(vPID->sm==SMOOTH_ENABLE) //设定值平滑变化
21 {
22 SmoothSetpoint(vPID);
23 }
24 else
25 {
26 if(vPID->cas==CASCADE) //串级处理
27 {
28 vPID->setpoint=(vPID->maximum-vPID->minimum)*(*vPID->pSV)/100.0+vPID->minimum;
29 }
30 else
31 {
32 vPID->setpoint=*vPID->pSV;
33 }
34 }
35
36 thisError=vPID->setpoint-(*vPID->pPV); //得到偏差值
37 result=vPID->result;
38 if (fabs(thisError)>vPID->deadband)
39 {
40 pError=thisError-vPID->lasterror;
41 iError=(thisError+vPID->lasterror)/2.0;
42 dError=thisError-2*(vPID->lasterror)+vPID->preerror;
43
44 //变积分系数获取
45 factor=VariableIntegralCoefficient(thisError,vPID->errorabsmax,vPID->errorabsmin);
46
47 //计算微分项增量带不完全微分
48 vPID->deltadiff=(*vPID->pKd)*(1-vPID->alpha)*dError+vPID->alpha*vPID->deltadiff;
49
50 increment=(*vPID->pKp)*pError+(*vPID->pKi)*factor*iError+vPID->deltadiff; //增量计算
51 }
52 else
53 {
54 if((fabs(vPID->setpoint-vPID->minimum)<vPID->deadband)&&(fabs((*vPID->pPV)-vPID->minimum)<vPID->deadband))
55 {
56 result=vPID->minimum;
57 }
58 increment=0.0;
59 }
60
61 //正反作用设定
62 if(vPID->direct==DIRECT)
63 {
64 result=result+increment;
65 }
66 else
67 {
68 result=result-increment;
69 }
70
71 /*对输出限值,避免超调和积分饱和问题*/
72 if(result>=vPID->maximum)
73 {
74 result=vPID->maximum;
75 }
76 if(result<=vPID->minimum)
77 {
78 result=vPID->minimum;
79 }
80
81 vPID->preerror=vPID->lasterror; //存放偏差用于下次运算
82 vPID->lasterror=thisError;
83 vPID->result=result;
84
85 vPID->output=(vPID->result-vPID->minimum)/(vPID->maximum-vPID->minimum)*100.0;
86 *vPID->pMV=vPID->output;
87 }
88 }
4、总结
这里我们对PID控制器添加了串级控制的配置参数。当一个PID控制器作为串级调节的副控制器时,我们将串级配置参数使能,这样将主调节器的输出给副调节器的设定时就可实现串级。而此时主控制器的串级配置参数并不需要使能,其设定值由操作者给予。
严格来讲串级控制并不是一种单独的控制算法,而是一种控制方式。但为了实现串级控制方式,我们需要对PID控制算法做必要的适应性修改。
欢迎关注:
来源:oschina
链接:https://my.oschina.net/u/4277082/blog/4263967