PID算法原理


 

 

 

 

 

上面給出的是PID控制算法的整個框圖,以及根據框圖所給出的公式。下面是結合蒸汽刷的實例子進行說明PID控制。

   首先需要說明的是PID是一個閉環控制,也就是說一定要有個反饋通路在那,還有就是對於系統存在滯后性、穩定誤差,PID可以達到較好效果,具體原因還要從PID三個參數說起,為了貼近項目。這里先將框圖中具體參數具體意義和蒸汽刷實物相對。

   蒸汽刷項目中,r(t)為當前設定的溫度,c(t)為當前輸出溫度,e(t)為當前設定溫度與當前輸出溫度的差值,u(t)為溫度的控制量,也就是加熱的脈沖數,執行機構為可控硅,對象就是蒸汽刷了。好了,有了實際的意義,可以討論PID三個參數了。

   P(Proportion)比列系數:P系數實際就是公式中的那個Kp,純P作用就是u(t)=Kp*e(t),單純的就P作用就很好理解了,看設定溫度與當前溫度差值e(t),不夠就加控制量,夠了就減小,具體加多大或者減多少,那就要看Kp了,溫差e(t)一定時,Kp大了給的控制量就大,試想一下,當Kp無窮大時,給的控制量就無窮大,顯然系統是很難穩定的,當Kp無窮小時,系統控制量也無窮小,系統也就沒什么變化,升溫幾乎不可能,這也側面反應了Kp顯然不是越大或越小越好。這里假設我們Kp已經取的合適,這里暫就假設為5,設定溫度r(t)為150,為防止控制量過大,這里限定一下上限值為50,剛開始時,e(t1) = (150-0)=150,

u(t1) = 150*50>50  u(t1)控制量就為50,繼續加熱t2……tn,當溫差為13左右時候,控制量就開始逐漸小於50了,這個時候也還很大,為48,…..當溫差為1度時候,控制量就一直在5范圍內波動了,這就了不得了,溫度假設現在是149,誤差為+5那下個階段就要5的控制量,這個時候溫度就有可能達到155, 在155時候又發現溫度高了,誤差為-5那就降下來控制量為0,降到149時候,控制量又為5,溫度又會上升到155,如此反復。你會發現溫度始終都不能穩定下來,始終在一個范圍內波動。要是在考慮這個系統的滯后性,也就是說這個控制量給到了發熱體,發熱體發熱是需要時間的,可能要下兩個時刻溫度才會升,那可能就會出現,那邊溫度還沒升完,我這邊又給控制量,這樣一來溫度一定過沖更加嚴重。當然了,看到這里,肯定會想到,前面這個Kp或許太大了,那我減小一點不就行了,是的,減小確實會有效果,至少溫度到后面穩定的波動不會太大,但Kp小了,也就意味着控制量小了,對吧,這時候升溫時間可就長了,Kp越小,升溫時間就越久,可總不能這么一直等下去呀,人們等待時間總是有限的。進一步的,就會發現,那我就剛開始讓它控制量大些,等到快穩定時候再讓它控制量小下來,不錯,這就會引申出我們下面講到的D參數。

  D(Differential)微分系數:微分系數是公式中的那個Kd,微分作用部分也就是Kd(de(t)/dt) ,由於上面講的那個P一個人不能解決問題,我們就找了一個叫D的人過來幫忙了,兩人聯手,公式這時也變為了u(t)= Kp*e(t)+ Kd(de(t)/dt),既然D過來幫忙了,那我們先介紹一下D的絕招,D擅長將過去與現在聯系一起,預料到后面事態的發展,可以說是半個預言家吧。也就是說它主要是輔助P來解決問題,P負責沖鋒,D負責輔助。清楚了各個職責后,讓我們接着上面講的蒸汽刷控溫的繼續講下去。這時候我們需要把眼光放的長遠一些,e(t)也就是溫差,我們上面看的時候都是單個時刻去看的,這時候我們假設把e(t)的變化都繪制出來,也就是將所有時刻都連線連起來看的話,就會發現,e(t)是一個隨着時間遞減的曲線,后面在0范圍內上下波動,剛開始時候e(t1)=150,緊接着e(t2)=130……e(tn) = 50.這個時候一定會想到這個曲線究竟是怎樣的,目前看來我們只能靠猜測,但有一點可以肯定的是就是這個曲線一定是一個斜率小於0的,而且斜率有可能在不斷變化,看,我們想到了什么,斜率,斜率就是變化,那我們是否可以用它來告訴我們控制量什么時候大些,什么時候小些呢。由於我們在實際過程中,整個溫度變化不可能是瞬間產生的,一定是緩慢的,這時候只要采集溫度時間足夠短的話,那完全可以通過現階段的斜率預想到下個時刻的發生。D開始出場了,這個時候Kd我們假設取8,剛開始,Kd不起作用因為沒法預測都沒兩個點產生也沒有所謂的斜率,u(t1)=5*(150-0),第一個時刻當前溫度為0度,u(t1)為50,第二個時刻:Kd開始作用,當前溫度為20度, de(t)/dt =(130-150)/(t2-t1),這里我們每1S檢測一次,所以de(t)/dt=20  u(t2)=5*(150-20) +0.8*(130-150)>50  = 50, 溫度不斷上升,當溫差當前為10時,前一個時刻為13,也就是當前溫度為140度時,u(t2)=5*(150-140) +0.8*(10-13)=50-2.4= 47,本來沒有微分作用時候這時候應該為50,現在為47,再下個時刻,溫差為5,則u(t2)=5*(150-145)+0.8*(5-10)=21,再下個時刻,當溫差為正1時候, u(t2)=5*(150-149)+0.8*(1-5)<0=0,不給控制量,當溫差為負1時候,u(t2)=5*(150-151)+0.8*(-1-5)<0=0,不給控制量,可以看出溫度有明顯的改善,穩定度大大的提高。但也不要過於開心,仔細觀察會發現,我們現在的整個升溫是理想化的,也就是說並沒有考慮任何散熱啊,什么的。拿出我們前面升溫一個狀態看一下,這個時刻我們貼近實際,假設這時候散熱是變化的,具體散熱的量我們對應到控制量上,當溫差當前為10時,前一個時刻為13,也就是當前溫度為140度時,u(t2)=5*(150-140) +0.8*(10-13)=50-2.4= 47,這時候散熱為15,則實際相當於32的控制量用於升溫,下個時刻溫度為145,溫差為5,則u(t2)=5*(150-145)+0.8*(5-10)=21,這時候散熱為16,再下個時刻溫度為146,溫差為4,則u(t2)=5*(150-146)+0.8*(4-5)=19.2, 這時候散熱為19,溫度為146,溫差為4,那會出現什么情況,很明顯溫度不會往上升了,這時候給的控制量都用於了散熱。這對於溫度要求精度不高的話,好像是可以了,但是如果一個應用,比方說開水啥的,就是要達到100度,少1度都不行,那P和D就不夠用了,這時候要是再來一個量,在什么時候溫度提不上的時候,也就是誤差始終不為0,能夠再增加一下控制量就好辦了。在理一下思路,誤差不為0,上面那個加熱的誤差差不多一直在5左右,究竟什么時候增加一下控制量,那肯定是誤差加到什么時候,注意這個加,累加就是積分,那就是積分到多少的問題,這就引申到我們下面最后要講的積分了。

I(integral)積分系數:積分系數是公式中的那個Ki,積分作用部分為Ki* ,這個公式中是從0到t開始積分的,現在我們將這個三個兄弟集結在一起,公式就變成了這樣:

u(t)= Kp*e(t)+ Kd(de(t)/dt)+ Ki*  ,這個時候還是接着我們上面的例子開始講起來,Kp和Kd都不變,Kp為5,Kd為0.8,Ki為2.0,剛開始時候,u(t)=5*(150-0)+0+2*(150-0)>50=50,

下一個時刻溫度上升到20度,u(t)=5*(150-0)+0.8(130-150)+2*(150-0+130-0)>50=50,這樣溫度不斷上升,假設當溫差當前為10時,前一個時刻為13,也就是當前溫度為140度時,u(t2)=5*(150-140) +0.8*(10-13) +2*(150-0+130-0 +….)=50-2.4+ …>50,這時候控制量還是保持50,容易導致超溫,而且隨着時間拉長,積分量可能只會越來越大,這就容易導致一種稱為積分飽和的現象,因此一般在使用積分時候,都會給積分加限制條件,比如最大值,或最小值,這樣即使超溫,還是能夠靠微分給拉回平衡。另外一點也容易想到,就是剛開始溫差大,本來P作用就很大了,這時又加了I進來,可能會導致溫升過於劇烈,所以一般情況下是在最好快接近目標溫度時候,選擇加入積分作用,也就是,積分時機很關鍵,這里我把積分I比作刺客,P是戰士,D是輔助,D輔助戰士發動進攻,等到敵人與戰士僵持不下時候,刺客這時出手,爭取一擊必殺。

  理清了PID系數后,接下來就開始實際操作了,第一步就是對函數進行離散化處理,計算機只能處理數字量,所以為便於計算,下面將整個函數離散化表示如下:

 

 

 

上面的離散表達式中為tn時刻的控制量,在ts時刻加入積分控制。

 

 

軟件代碼:

第一步:定義PID變量結構體

struct  _pid{

float  Err;               //------定義偏差值

float  ErrLast;            //------定義上一個偏差值

float  Kp,Ki,Kd;           //------定義比列、積分、微分值

unsigned  char  ControlDuty;        //------定義控制量  

float  Proportion;         //------定義PID比列部分     

float  Interal;             //-------定義PID積分部分

float  Differential;         //-------定義PID微分部分

}Pid;

#define  Integral_max     15  //-----定義積分上限值

#define  Integral_min     -15  //-----定義積分下限值

#define  Integral_time    100  //-----定義積分加入時機

#define  ControlDuty_Max  50  //-----定義控制量最大值不超過50

extern  float  SetTemperature;    //------設定溫度值

extern  float  ActualTemperature;  //------實際測得溫度值

 

第二步:初始化PID參數

void  PID_Init(void)

{

   Pid.Err  =  0;

   Pid.ErrLast  =  0;

   Pid.Kp  =  10;

   Pid.Ki  =  2;

   Pid.Kd  =  0.8;

   Pid. ControlDuty  =  0;

   Pid. Proportion  =  0;

   Pid. Differential  =  0;

   Pid. Interal  =  0;

}

 

 

 

 

第三步:編寫控制算法

void  PID_Ctrl(void)

{

   Pid.Err  =  SetTemperature  -  ActualTemperature;

   Pid. Proportion  =  Err;

   If(ActualTemperature !=0)

   Pid. Differential  =  (Err - ErrLast);

   If(ActualTemperature  >=  Integral_time)

      Pid .Interal  =  Pid .Interal + Err;

   If(Pid .Interal >15)

      Pid .Interal  =  Integral_max;

   If(Pid .Interal <-15)

      Pid .Interal  =  Integral_min;

 

Pid.ErrLast  =  Pid.Err;

ControlDuty  = (unsigned char)( Pid.Kp * Pid. Proportion + Pid.Ki * Pid .Interal + Pid.Kd* Pid. Differential);

  If(ControlDuty  >  ControlDuty_Max)

   ControlDuty  =  50;

}


免責聲明!

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



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