PID控制算法一勺燴 從模型到實現再到口訣

PID控制算法一勺燴 從模型到實現再到口訣

一、PID的數學模型

在工業應用中PID及其衍生算法是應用最廣泛的算法之一,是當之無愧的萬能算法,如果能夠熟練掌握PID算法的設計與實現過程,對於一般的研發人員來講,應該是足夠應對一般研發問題了,而難能可貴的是,在很多控制算法當中,PID控制算法又是最簡單,最能體現反饋思想的控制算法,可謂經典中的經典。經典的未必是複雜的,經典的東西常常是簡單的,而且是最簡單的。PID算法的一般形式:

PID控制算法一勺燴 從模型到實現再到口訣

PID算法通過誤差信號控制被控量,而控制器本身就是比例、積分、微分三個環節的加和。這裡我們規定(在t時刻):

1.輸入量為

PID控制算法一勺燴 從模型到實現再到口訣

2.輸出量為

PID控制算法一勺燴 從模型到實現再到口訣

3.偏差量為

PID控制算法一勺燴 從模型到實現再到口訣

PID控制算法一勺燴 從模型到實現再到口訣

二、PID算法的數字離散化

假設採樣間隔為T,則在第K個T時刻:

偏差

PID控制算法一勺燴 從模型到實現再到口訣

積分環節用加和的形式表示,即

PID控制算法一勺燴 從模型到實現再到口訣

微分環節用斜率的形式表示,即

PID控制算法一勺燴 從模型到實現再到口訣

PID算法離散化後的式子:

PID控制算法一勺燴 從模型到實現再到口訣

則可表示成為:

PID控制算法一勺燴 從模型到實現再到口訣

其中式中:

比例參數Kp:控制器的輸出與輸入偏差值成比例關係。系統一旦出現偏差,比例調節立即產生調節作用以減少偏差。特點:過程簡單快速、比例作用大,可以加快調節,減小誤差;但是使系統穩定性下降,造成不穩定,有餘差。

積分參數Ki:積分環節主要是用來消除靜差,所謂靜差,就是系統穩定後輸出值和設定值之間的差值,積分環節實際上就是偏差累計的過程,把累計的誤差加到原有系統上以抵消系統造成的靜差。

微分參數Kd:微分信號則反應了偏差信號的變化規律,或者說是變化趨勢,根據偏差信號的變化趨勢來進行超前調節,從而增加了系統的快速性。

PID的基本離散表示形式如上。目前的這種表述形式屬於位置型PID,另外一種表述方式為增量式PID,由上述表達式可以輕易得到:

PID控制算法一勺燴 從模型到實現再到口訣

那麼:

PID控制算法一勺燴 從模型到實現再到口訣

上式就是離散化PID的增量式表示方式,由公式可以看出,增量式的表達結果和最近三次的偏差有關,這樣就大大提高了系統的穩定性。需要注意的是最終的輸出結果應該為:

輸出量 = U(k)+ 增量調節值

三、PID的C語言實現

1.位置式PID的C語言實現

上邊已經抽象出了位置性PID和增量型PID的數學表達式,這裡重點講解C語言代碼的實現過程。

第一步:定義PID變量結構體,代碼如下:

struct t_pid{

float SetSpeed; //定義設定值

float ActualSpeed; //定義實際值

float err; //定義偏差值

float err_last; //定義上一個偏差值

float Kp,Ki,Kd; //定義比例、積分、微分系數

float voltage; //定義電壓值(控制執行器的變量)

float integral; //定義積分值

}pid;

第二部:初始化變量,代碼如下:

void PID_init(){

pid.SetSpeed=0.0;

pid.ActualSpeed=0.0;

pid.err=0.0;

pid.err_last=0.0;

pid.voltage=0.0;

pid.integral=0.0;

pid.Kp=0.2;

pid.Ki=0.015;

pid.Kd=0.2;

}

統一初始化變量,尤其是Kp,Ki,Kd三個參數,調試過程當中,對於要求的控制效果,可以通過調節這三個量直接進行調節。

第三步:編寫控制算法,代碼如下:

float PID_realize(float speed){

pid.SetSpeed=speed;

pid.err=pid.SetSpeed-pid.ActualSpeed;

pid.integral+=pid.err;

pid.voltage=pid.Kp*pid.err+pid.Ki*pid.integral+pid.Kd*(pid.err-pid.err_last);

pid.err_last=pid.err;

pid.ActualSpeed=pid.voltage*1.0;

return pid.ActualSpeed;

}

注意:這裡用了最基本的算法實現形式,沒有考慮死區問題,沒有設定上下限,只是對公式的一種直接的實現,後面的介紹當中還會逐漸的對此改進。

到此為止,PID的基本實現部分就初步完成了。下面是測試代碼:

int main(){

PID_init();

int count=0;

while(count<1000>

{

float speed=PID_realize(200.0);

printf("%f\n",speed);

count++;

}

return 0;

}

2.增量型PID的C語言實現

上一節中介紹了最簡單的位置型PID的實現手段,這一節講解增量式PID的實現方法。

#include

#include

struct t_pid{

float SetSpeed; //定義設定值

float ActualSpeed; //定義實際值

float err; //定義偏差值

float err_next; //定義上一個偏差值

float err_last; //定義最上前的偏差值

float Kp,Ki,Kd; //定義比例、積分、微分系數

}pid;

void PID_init(){

pid.SetSpeed=0.0;

pid.ActualSpeed=0.0;

pid.err=0.0;

pid.err_last=0.0;

pid.err_next=0.0;

pid.Kp=0.2;

pid.Ki=0.015;

pid.Kd=0.2;

}

float PID_realize(float speed){

pid.SetSpeed=speed;

pid.err=pid.SetSpeed-pid.ActualSpeed;

float incrementSpeed=pid.Kp*(pid.err-pid.err_next)+pid.Ki*pid.err+pid.Kd*(pid.err-2*pid.err_next+pid.err_last);

pid.ActualSpeed+=incrementSpeed;

pid.err_last=pid.err_next;

pid.err_next=pid.err;

return pid.ActualSpeed;

}

int main(){

PID_init();

int count=0;

while(count<1000>

{

float speed=PID_realize(200.0);

printf("%f\n",speed);

count++;

}

return 0;

}

3.積分分離的PID控制算法

在普通PID控制中,引入積分環節的目的,主要是為了消除靜差,提高控制精度。但是在啟動、結束或大幅度增減設定時,短時間內系統輸出有很大的偏差,會造成PID運算的積分積累,導致控制量超過執行機構可能允許的最大動作範圍對應極限控制量,從而引起較大的超調,甚至是震盪,這是絕對不允許的。

為了克服這一問題,引入了積分分離的概念,其基本思路是 當被控量與設定值偏差較大時,取消積分作用; 當被控量接近給定值時,引入積分控制,以消除靜差,提高精度。其具體實現代碼如下:

pid.Kp=0.2;

pid.Ki=0.04;

pid.Kd=0.2; //初始化過程

if(abs(pid.err)>200)

{

index=0;

}else{

index=1;

pid.integral+=pid.err;

}

pid.voltage=pid.Kp*pid.err+index*pid.Ki*pid.integral+pid.Kd*(pid.err-pid.err_last); //算法具體實現過程

4.抗積分飽和的PID控制算法C語言實現

所謂的積分飽和現象是指如果系統存在一個方向的偏差,PID控制器的輸出由於積分作用的不斷累加而加大,從而導致執行機構達到極限位置,若控制器輸出U(k)繼續增大,執行器開度不可能再增大,此時計算機輸出控制量超出了正常運行範圍而進入飽和區。一旦系統出現反向偏差,u(k)逐漸從飽和區退出。進入飽和區越深則退出飽和區時間越長。在這段時間裡,執行機構仍然停留在極限位置而不隨偏差反向而立即做出相應的改變,這時系統就像失控一樣,造成控制性能惡化,這種現象稱為積分飽和現象或積分失控現象。

防止積分飽和的方法之一就是抗積分飽和法,該方法的思路是在計算u(k)時,首先判斷上一時刻的控制量u(k-1)是否已經超出了極限範圍: 如果u(k-1)>umax,則只累加負偏差; 如果u(k-1)

struct t_pid{

float SetSpeed; //定義設定值

float ActualSpeed; //定義實際值

float err; //定義偏差值

float err_last; //定義上一個偏差值

float Kp,Ki,Kd; //定義比例、積分、微分系數

float voltage; //定義電壓值(控制執行器的變量)

float integral; //定義積分值

float umax;

float umin;

}pid;

void PID_init(){

pid.SetSpeed=0.0;

pid.ActualSpeed=0.0;

pid.err=0.0;

pid.err_last=0.0;

pid.voltage=0.0;

pid.integral=0.0;

pid.Kp=0.2;

pid.Ki=0.1; //注意,和上幾次相比,這裡加大了積分環節的值

pid.Kd=0.2;

pid.umax=400;

pid.umin=-200;

}

float PID_realize(float speed){

int index;

pid.SetSpeed=speed;

pid.err=pid.SetSpeed-pid.ActualSpeed;

if(pid.ActualSpeed>pid.umax) //灰色底色表示抗積分飽和的實現

{

if(abs(pid.err)>200) //藍色標註為積分分離過程

{

index=0;

}else{

index=1;

if(pid.err<0)

{

pid.integral+=pid.err;

}

}

}else if(pid.ActualSpeed

if(abs(pid.err)>200) //積分分離過程

{

index=0;

}else{

index=1;

if(pid.err>0)

{

pid.integral+=pid.err;

}

}

}else{

if(abs(pid.err)>200) //積分分離過程

{

index=0;

}else{

index=1;

pid.integral+=pid.err;

}

}

pid.voltage=pid.Kp*pid.err+index*pid.Ki*pid.integral+pid.Kd*(pid.err-pid.err_last);

pid.err_last=pid.err;

pid.ActualSpeed=pid.voltage*1.0;

return pid.ActualSpeed;

}

5.梯形積分的PID控制算法

先看一下梯形算法的積分環節公式

PID控制算法一勺燴 從模型到實現再到口訣

作為PID控制律的積分項,其作用是消除餘差,為了儘量減小余差,應提高積分項運算精度,為此可以將矩形積分改為梯形積分,具體實現的語句為:

pid.voltage=pid.Kp*pid.err+index*pid.Ki*pid.integral/2+pid.Kd*(pid.err-pid.err_last); //梯形積分

6.變積分的PID控制算法

變積分PID可以看成是積分分離的PID算法的更一般的形式。在普通的PID控制算法中,由於積分系數是常數,所以在整個控制過程中,積分增量是不變的。但是,系統對於積分項的要求是,系統偏差大時,積分作用應該減弱甚至是全無,而在偏差小時,則應該加強。積分系數取大了會產生超調,甚至積分飽和,取小了又不能短時間內消除靜差。因此,根據系統的偏差大小改變積分速度是有必要的。

變積分PID的基本思想是設法改變積分項的累加速度,使其與偏差大小相對應:偏差越大,積分越慢; 偏差越小,積分越快。

這裡給積分系數前加上一個比例值index:

當abs(err)<180時,index=1;

當180

當abs(err)>200時,index=0;

最終的比例環節的比例係數值為ki*index;

具體PID實現代碼如下:

pid.Kp=0.4;

pid.Ki=0.2; //增加了積分系數

pid.Kd=0.2;

float PID_realize(float speed){

float index;

pid.SetSpeed=speed;

pid.err=pid.SetSpeed-pid.ActualSpeed;

if(abs(pid.err)>200) //變積分過程

{

index=0.0;

}else if(abs(pid.err)<180){

index=1.0;

pid.integral+=pid.err;

}else{

index=(200-abs(pid.err))/20;

pid.integral+=pid.err;

}

pid.voltage=pid.Kp*pid.err+index*pid.Ki*pid.integral+pid.Kd*(pid.err-pid.err_last);

pid.err_last=pid.err;

pid.ActualSpeed=pid.voltage*1.0;

return pid.ActualSpeed;

}

7.專家PID和模糊PID

從前面的講解中不難看出,PID的控制思想非常簡單,其主要問題點和難點在於比例、積分、微分環節上的參數整定過程,對於執行器控制模型確定或者控制模型簡單的系統而言,參數的整定可以通過計算獲得,對於一般精度要求不是很高的執行器系統,可以採用拼湊的方法進行實驗型的整定。

然而,在實際的控制系統中,線性系統畢竟是少數,大部分的系統屬於非線性系統,或者說是系統模型不確定的系統,如果控制精度要求較高的話,那麼對於參數的整定過程是有難度的。專家PID和模糊PID就是為滿足這方面的需求而設計的。專家算法和模糊算法都歸屬於智能算法的範疇,智能算法最大的優點就是在控制模型未知的情況下,可以對模型進行控制。這裡需要注意的是,專家PID也好,模糊PID也罷,絕對不是專家系統或模糊算法與PID控制算法的簡單加和,他是專家系統或者模糊算法在PID控制器參數整定上的應用。也就是說,智能算法是輔助PID進行參數整定的手段。

專家系統、模糊算法,需要參數整定就一定要有整定的依據,也就是說什麼情況下整定什麼值是要有依據的,這個依據是一些邏輯的組合,只要找出其中的邏輯組合關係來,這些依據就再明顯不過了。下面先說一下專家PID的C語言實現。正如前面所說,需要找到一些依據,還得從PID係數本身說起。

(1).比例係數Kp的作用是加快系統的響應速度,提高系統的調節精度。Kp越大,系統的響應速度越快,系統的調節精度越高,但是容易產生超調,甚至會使系統不穩定。Kp取值過小,則會降低調節精度,使響應速度緩慢,從而延長調節時間,是系統靜態、動態特性變差;

(2).積分作用係數Ki的作用是消除系統的穩態誤差。Ki越大,系統的靜態誤差消除的越快,但是

Ki過大,在響應過程的初期會產生積分飽和的現象,從而引起響應過程的較大超調。若Ki過小,將使系統靜態誤差難以消除,影響系統的調節精度;

(3).微分系數Kd的作用是改善系統的動態特性,其作用主要是在響應過程中抑制偏差向任何方向的變化,對偏差變化進行提前預報。但是Kd過大,會使響應過程提前制動,從而延長調節時間,而且會降低系統的抗干擾性。

反應系統性能的兩個參數是系統誤差e和誤差變化律ec,這點還是好理解的:

首先我們規定一個誤差的極限值,假設為Mmax;規定一個誤差的比較大的值,假設為Mmid;規定一個誤差的較小值,假設為Mmin;

當abs(e)>Mmax時,說明誤差的絕對值已經很大了,不論誤差變化趨勢如何,都應該考慮控制器的輸入應按最大(或最小)輸出,以達到迅速調整誤差的效果,使誤差絕對值以最大的速度減小。此時,相當於實施開環控制。

當e*ec>0時,說明誤差在朝向誤差絕對值增大的方向變化,此時,如果abs(e)>Mmid,說明誤差也較大,可考慮由控制器實施較強的控制作用,以達到扭轉誤差絕對值向減小的方向變化,並迅速減小誤差的絕對值。此時如果abs(e)

當e*err<0且e*err(k-1)>0或者e=0時,說明誤差的絕對值向減小的方向變化,或者已經達到平衡狀態,此時保持控制器輸出不變即可。

當e*err<0且e*err(k-1)<0時,說明誤差處於極限狀態。如果此時誤差的絕對值較大,大於Mmin,可以考慮實施較強控制作用。如果此時誤差絕對值較小,可以考慮實施較弱控制作用。

當abs(e)

上面的邏輯判斷過程,實際上就是對於控制系統的一個專家判斷過程。

實際上模糊算法屬於智能算法,智能算法也可以叫非模型算法,智能算法包含了專家系統、模糊算法、遺傳算法、神經網絡算法等。其實這其中的任何一種算法都可以跟PID去做結合,而選擇的關鍵在於,處理的實時性能不能得到滿足。當我們處理器的速度足夠快速時,我們可以選擇更為複雜的、精度更加高的算法。但是,控制器的處理速度限制了我們算法的選擇。當然,成本是限制處理器速度最根本的原因。模糊PID適應一般的控制系統是沒有問題。

模糊算法其實並不模糊。模糊算法其實也是逐次求精的過程。這裡舉個例子說明。我們設計一個倒立擺系統,假如擺針偏差<5°,我們說它的偏差比較“小”;擺針偏差在5°和10°之間,我們說它的偏差處於“中”的狀態;當擺針偏差>10°的時候,我們說它的偏差有點兒“大”了。對於“小”、“中”、“大”這樣的詞彙來講,他們是精確的表述,可問題是如果擺針偏差是3°呢,那麼這是一種什麼樣的狀態呢。我們可以用“很小”來表述它。如果是7°呢,可以說它是“中”偏“小”。那麼如果到了80°呢,它的偏差可以說“非常大”。而我們調節的過程實際上就是讓系統的偏差由非常“大”逐漸向非常“小”過度的過程。當然,我們系統這個調節過程是快速穩定的。通過上面的說明,可以認識到,其實對於每一種狀態都可以劃分到大、中、小三個狀態當中去,只不過他們隸屬的程度不太一樣,比如6°隸屬於小的程度可能是0.3,隸屬於中的程度是0.7,隸屬於大的程度是0。這裡實際上是有一個問題的,就是這個隸屬的程度怎麼確定?這就要求我們去設計一個隸屬函數。詳細內容可以查閱相關的資料,這裡沒有辦法那麼詳細的說明了。那麼,知道了隸屬度的問題,就可以根據目前隸屬的程度來控制電機以多大的速度和方向轉動了,當然,最終的控制量肯定要落實在控制電壓上。這點可以很容易的想想,我們控制的目的就是讓倒立擺從隸屬“大”的程度為1的狀態,調節到隸屬“小”的程度為1的狀態。當隸屬大多一些的時候,我們就加快調節的速度,當隸屬小多一些的時候,我們就減慢調節的速度,進行微調。可問題是,大、中、小的狀態是漢字,怎麼用數字表示,進而用程序代碼表示呢?其實我們可以給大、中、小三個狀態設定三個數字來表示,比如大表示用3表示,中用2表示,小用1表示。那麼我們完全可以用1*0.3+2*0.7+3*0.0=1.7來表示它,當然這個公式也不一定是這樣的,這個公式的設計是系統模糊化和精確化的一個過程,讀者也可參見相關文獻理解。但就1.7這個數字而言,可以說明,目前6°的角度偏差處於小和中之間,但是更偏向於中。我們就可以根據這個數字來調節電機的轉動速度和時間了。當然,這個數字與電機轉速的對應關係,也需要根據實際情況進行設計和調節。

前面一個例子已經基本上說明了模糊算法的基本原理了。可是實際上,一個系統的限制因素常常不是一個。上面的例子中,只有偏差角度成為了系統調節的參考因素。而實際系統中,比如PID系統,我們需要調節的是比例、積分、微分三個環節,那麼這三個環節的作用就需要我們認清,也就是說,我們需要根據超調量、調節時間、震盪情況等信息來考慮對這三個環節調節的比重,輸入量和輸出量都不是單一的,可是其中必然有某種內在的邏輯聯繫。所以這種邏輯聯繫就成為我們設計工作的重點了。

四、PID算法參數整定方法

1.臨界比例度法

(1)將調節器的積分時間

PID控制算法一勺燴 從模型到實現再到口訣

置於最大

PID控制算法一勺燴 從模型到實現再到口訣

,微分時間置零

PID控制算法一勺燴 從模型到實現再到口訣

,比例度δ適當,平衡操作一段時間,把系統投入自動運行。

(2)將比例度δ逐漸減小,得到等幅振盪過程,記下臨界比例度

PID控制算法一勺燴 從模型到實現再到口訣

和臨界振盪週期

PID控制算法一勺燴 從模型到實現再到口訣

值。

(3)根據和值,採用經驗公式,計算出調節器各個參數,即δ的值。

(4)按“先P後I最後D”的操作程序將調節器整定參數調到計算值上。若還不夠滿意,可再作進一步調整。

PID控制算法一勺燴 從模型到實現再到口訣

臨界振盪整定計算公式

2.衰減曲線法

在純比例作用下,由大到小調整比例度以得到具有衰減比(4:1)的過渡過程,記下此時的比例度及振盪週期,根據經驗公式,求出相應的積分時間和微分時間。


PID控制算法一勺燴 從模型到實現再到口訣


衰減曲線法控制器參數計算表

Note:(1).反應較快的控制系統,要認定4:1衰減曲線和讀出Ts比較困難,此時,可用記錄來回擺動兩次就達到穩定作為4:1衰減過程。 (2).在生產過程中,負荷變化會影響過程特性。當負荷變化較大時,必須重新整定調節器參數值。 (3).若認為4:1衰減太慢,宜應用10:1衰減過程。對於10:1衰減曲線法整定調節器參數的步驟與上述完全相同,僅僅採用計算公式有些不同。

3.經驗法

根據經驗先將控制器參數放在某些數值上,直接在閉合的控制系統中通過改變給定值以施加干擾,看輸出曲線的形狀,以δ、、,對控制過程的規律為指導,調整相應的參數進行湊試,直到合適為止。

PID控制算法一勺燴 從模型到實現再到口訣

長期的生產實踐中總結出來的參數表

4.經驗口訣

參數整定找最佳,從小到大順序查。

先是比例後積分,最後再把微分加。

曲線振盪很頻繁,比例度盤要放大。

曲線漂浮繞大灣,比例度盤往小扳。

曲線偏離回覆慢,積分時間往下降。

曲線波動週期長,積分時間再加長。

曲線振盪頻率快,先把微分降下來。

動差大來波動慢。微分時間應加長。

理想曲線兩個波,前高後低4比1。

一看二調多分析,調節質量不會低。


分享到:


相關文章: