改進初學者的PID-初始化


  最近看到了Brett Beauregard發表的有關PID的系列文章,感覺對於理解PID算法很有幫助,於是將系列文章翻譯過來!在自我提高的過程中,也希望對同道中人有所幫助。作者Brett Beauregard的原文網址:http://brettbeauregard.com/blog/2011/04/improving-the-beginner's-pid-initialization/

 

1、問題所在

  在前一節中,我們實現了關閉和打開 PID 的功能。我們將其關閉,但現在讓我們來看看當我們重新打開它時會發生什么:

 

  呵!PID跳回到它發送的最后一個輸出值,然后從那里開始調整。這將導致我們不希望出現的輸入顛簸。

2、解決方案

  這個很容易解決。因為我們現在知道什么時候打開 (從手動到自動),我們只需為一個平穩的過渡做一些初始化。這意味着對2個工作變量的存儲 (積分項和最后的輸入項) 進行處理,以防止輸出跳轉。

3、代碼

 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 (...) 以檢測從手動到自動的轉換,並添加了初始化功能。它通過設置“積分項=輸出”來處理積分項,“最后輸入=輸入”以防止微分激增。比例項不依賴於過去的任何信息,因此不需要任何初始化。

4、最終結果

 

  我們從上面的圖表中看到,正確的初始化會導致從手動到自動的無擾動切換,這正是我們所追求的。

5、更新:為什么不 ITerm=0

  我最近收到了很多問題,問為什么我沒有把 ITerm=0 設置為初始化。作為答案,我請您考慮以下方案:PID是手動的,用戶已將輸出設置為50。一段時間后,該過程穩定到75.2 的輸入。用戶將設置點75.2 打開 PID。會發生什么事?

  我認為,切換到自動后,輸出值應該保持在50。由於 P 和 D 項將為零,因此發生這種情況的唯一方法是將 ITerm項初始化為“輸出”值。

  如果您處於需要輸出初始化為零的情況,則無需更改上面的代碼。在將 PID 從“手動”轉換為“自動”之前,只需在調用例程中設置Output=0。

 歡迎關注:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM