改进初学者的PID-初始化

  最近看到了Brett Beauregard发表的有关PID的系列文章,感受对于理解PID算法颇有帮助,因而将系列文章翻译过来!在自我提升的过程当中,也但愿对同道中人有所帮助。做者Brett Beauregard的原文网址:http://brettbeauregard.com/blog/2011/04/improving-the-beginner's-pid-initialization/算法

 

1、问题所在spa

  在前一节中,咱们实现了关闭和打开 PID 的功能。咱们将其关闭,但如今让咱们来看看当咱们从新打开它时会发生什么:翻译

 

  呵!PID跳回到它发送的最后一个输出值,而后从那里开始调整。这将致使咱们不但愿出现的输入颠簸。code

2、解决方案blog

  这个很容易解决。由于咱们如今知道何时打开 (从手动到自动),咱们只需为一个平稳的过渡作一些初始化。这意味着对2个工做变量的存储 (积分项和最后的输入项) 进行处理,以防止输出跳转。get

3、代码it

 1 /*working variables*/
 2 unsigned long lastTime;
 3 double Input,Output,Setpoint;
 4 double ITerm,lastInput;
 5 double kp,ki,kd;
 6 int SampleTime = 1000; //1 sec
 7 double outMin,outMax;
 8 bool inAuto = false;
 9  
10 #define MANUAL 0
11 #define AUTOMATIC 1
12  
13 void Compute()
14 {
15    if(!inAuto) return;
16    unsigned long now = millis();
17    int timeChange = (now - lastTime);
18    if(timeChange>=SampleTime)
19    {
20       /*Compute all the working error variables*/
21       double error = Setpoint - Input;
22       ITerm+= (ki * error);
23       if(ITerm> outMax) ITerm= outMax;
24       else if(ITerm< outMin) ITerm= outMin;
25       double dInput = (Input - lastInput);
26  
27       /*Compute PID Output*/
28       Output = kp * error + ITerm- kd * dInput;
29       if(Output> outMax) Output = outMax;
30       else if(Output < outMin) Output = outMin;
31  
32       /*Remember some variables for next time*/
33       lastInput = Input;
34       lastTime = now;
35    }
36 }
37  
38 void SetTunings(double Kp,double Ki,double Kd)
39 {
40   double SampleTimeInSec = ((double)SampleTime)/1000;
41    kp = Kp;
42    ki = Ki * SampleTimeInSec;
43    kd = Kd / SampleTimeInSec;
44 }
45  
46 void SetSampleTime(int NewSampleTime)
47 {
48    if (NewSampleTime > 0)
49    {
50       double ratio  = (double)NewSampleTime
51                       / (double)SampleTime;
52       ki *= ratio;
53       kd /= ratio;
54       SampleTime = (unsigned long)NewSampleTime;
55    }
56 }
57  
58 void SetOutputLimits(double Min,double Max)
59 {
60    if(Min > Max) return;
61    outMin = Min;
62    outMax = Max;
63    
64    if(Output > outMax) Output = outMax;
65    else if(Output < outMin) Output = outMin;
66  
67    if(ITerm> outMax) ITerm= outMax;
68    else if(ITerm< outMin) ITerm= outMin;
69 }
70  
71 void SetMode(int Mode)
72 {
73     bool newAuto = (Mode == AUTOMATIC);
74     if(newAuto && !inAuto)
75     {  /*we just went from manual to auto*/
76         Initialize();
77     }
78     inAuto = newAuto;
79 }
80  
81 void Initialize()
82 {
83    lastInput = Input;
84    ITerm = Output;
85    if(ITerm> outMax) ITerm= outMax;
86    else if(ITerm< outMin) ITerm= outMin;
87 }

  咱们修改了 SetMode (...) 以检测从手动到自动的转换,并添加了初始化功能。它经过设置“积分项=输出”来处理积分项,“最后输入=输入”以防止微分激增。比例项不依赖于过去的任何信息,所以不须要任何初始化。io

4、最终结果ast

 

  咱们从上面的图表中看到,正确的初始化会致使从手动到自动的无扰动切换,这正是咱们所追求的。class

5、更新:为何不 ITerm=0

  我最近收到了不少问题,问为何我没有把 ITerm=0 设置为初始化。做为答案,我请您考虑如下方案:PID是手动的,用户已将输出设置为50。一段时间后,该过程稳定到75.2 的输入。用户将设置点75.2 打开 PID。会发生什么事?

  我认为,切换到自动后,输出值应该保持在50。因为 P 和 D 项将为零,所以发生这种状况的惟一方法是将 ITerm项初始化为“输出”值。

  若是您处于须要输出初始化为零的状况,则无需更改上面的代码。在将 PID 从“手动”转换为“自动”以前,只需在调用例程中设置Output=0。

 欢迎关注:

相关文章
相关标签/搜索