在普通的PID控制算法中,由於積分系數Ki是常數,所以在整個控制過程中,積分增量是不變的。然而,系統對於積分項的要求是,系統偏差大時,積分作用應該減弱甚至是全無,而在偏差小時,則應該加強。積分系數取大了會產生超調,甚至積分飽和,取小了又不能短時間內消除靜差。因此,如何根據系統的偏差大小改變積分速度,對提高系統的品質是有必要的。變積分PID算法正好可以滿足這一要求。
1、變積分的基本思想
變積分PID的基本思想是設法改變積分項的累加速度,使其與偏差大小相對應:偏差越大,積分越慢; 偏差越小,積分越快。設定系數為f(err(k)),它是err(k)的函數。當|err(k)|增大時,f減小,反之增大。變積分的PID積分項表達式為:
其中f(err(k))與|err(k)|的函數關系可根據具體情況設定,可以是線性的也可以是非線性的,通常比較簡單的設置如下:
由以上公式可知,f(err(k))的值在[0,1]區間變化,當偏差值|err(k)|大於分離區間A+B時,不對當前偏差err(k)進行累加;當偏差值|err(k)|小於B時,加入當前偏差err(k)進行累加;介於B和A+B的區間時,按一定函數關系隨err(k)變化。於是變積分PID算法可以表示為:
上述的f(err(k))函數只是我們列舉的一種,事實上可以采取任何可行的方式,甚至是非線性函數,只要更符合控制對象的特性。
對於用增量型PID算法的變積分表示如下:
看到這個公式,很多人可能會發覺與前面的積分分離算法的公式很象。特別是在增量型算法中,它們的形式確實是一樣的,但表達的意思確是有一定區別,那么我們來看看有什么不同呢?在后面我們再作總結。
2、算法實現
變積分實際上是通過對偏差的判斷,讓積分以不同的速度累計。這一系數介於0-1之間,可以通過多種方式實現,在這里我們按線性方式實現。變積分的控制流程圖如下:
首先實現一個處理f(e(k))的函數,有前面的函數關系表達式,實現為響應的編碼就很簡單了:
1 /* 變積分系數處理函數,實現一個輸出0和1之間的分段線性函數 */ 2 /* 當偏差的絕對值小於最小值時,輸出為1;當偏差的絕對值大於最大值時,輸出為0 */ 3 /* 當偏差的絕對值介於最大值和最小值之間時,輸出在0和1之間現行變化 */ 4 /* float error,當前輸入的偏差值 */ 5 /* float absmax,偏差絕對值的最大值 */ 6 /* float absmin,偏差絕對值的最小值 */ 7 static float VariableIntegralCoefficient(float error,float absmax,float absmin) 8 { 9 10 float factor=0.0; 11 12 if(abs(error)<=absmin) 13 { 14 15 factor=1.0; 16 17 } 18 else if(abs(error)>absmax) 19 { 20 21 factor=0.0; 22 23 } 24 else 25 26 { 27 28 factor=(absmax-abs(error))/(absmax-absmin); 29 30 } 31 32 return factor; 33 34 }
(1)位置型PID算法實現
變積分基於位置型PID的實現就是更具偏差絕對值的大小獲取變積分的系數。然后再實現PID算法,同樣首先定義PID對象的結構體:
1 /*定義結構體和公用體*/ 2 3 typedef struct 4 5 { 6 7 float setpoint; //設定值 8 9 float proportiongain; //比例系數 10 11 float integralgain; //積分系數 12 13 float derivativegain; //微分系數 14 15 float lasterror; //前一拍偏差 16 17 float result; //輸出值 18 19 float integral;//積分值 20 21 float errorabsmax; //偏差絕對值最大值 22 23 float errorabsmin; //偏差絕對值最小值 24 25 }PID;
接下來實現PID控制器:
1 void PIDRegulation(PID *vPID, float processValue) 2 { 3 4 float thisError; 5 6 float factor; 7 8 thisError=vPID->setpoint-processValue; 9 10 factor= VariableIntegralCoefficient(thisError, vPID->errorabsmax, vPID->errorabsmin); 11 12 13 14 vPID->integral+= factor*thisError; 15 16 vPID->result=vPID->proportiongain*thisError+vPID->integralgain*vPID->integral+vPID->derivativegain*(thisError-vPID->lasterror); 17 18 vPID->lasterror=thisError; 19 20 }
(2)增量型PID算法實現
同樣變積分基於增量型PID的實現也是一樣的。首先定義PID對象的結構體:
1 /*定義結構體和公用體*/ 2 typedef struct 3 { 4 5 float setpoint; //設定值 6 7 float proportiongain; //比例系數 8 9 float integralgain; //積分系數 10 11 float derivativegain; //微分系數 12 13 float lasterror; //前一拍偏差 14 15 float preerror; //前兩拍偏差 16 17 float deadband; //死區 18 19 float result; //輸出值 20 21 float errorabsmax; //偏差絕對值最大值 22 23 float errorabsmin; //偏差絕對值最小值 24 25 }PID;
接下來實現PID控制器:
1 void PIDRegulation(PID *vPID, float processValue) 2 { 3 4 float thisError; 5 6 float increment; 7 8 float pError,dError,iError; 9 10 float factor; 11 12 13 14 thisError=vPID->setpoint-processValue; //得到偏差值 15 16 factor= VariableIntegralCoefficient(thisError, vPID->errorabsmax, vPID->errorabsmin); 17 18 19 20 pError=thisError-vPID->lasterror; 21 22 iError= factor*thisError; 23 24 dError=thisError-2*(vPID->lasterror)+vPID->preerror; 25 26 increment=vPID->proportiongain*pError+vPID->integralgain*iError+vPID->derivativegain*dError; //增量計算 27 28 vPID->preerror=vPID->lasterror; //存放偏差用於下次運算 29 30 vPID->lasterror=thisError; 31 32 vPID->result+=increment; 33 34 }
3、總結
變積分實際上有一定的專家經驗在里面,因為限值的選取以及采用什么樣的函數計算系數,有很大的靈活性。
我們在前面做了積分分離的算法,這次又說了變積分的算法。他們有相通的地方,也有不同的地方,下面對他們進行一些說明。
首先這兩種算法的設計思想是有區別的。積分分離的思想是偏差較大時,取消積分;而偏差較小時引入積分。變積分的實現是想是設法改變積分項的累加速度,偏差大時減弱積分;而偏差小時強化積分。有些所謂改進型的積分分離算法實際已經脫離了積分分離的基本思想,而是動態改變積分系數。就這一點而言,特別是在增量型算法中,已經屬於變積分的思想了。
其次,對於積分分離來說,該操作是針對整個積分項操作,這一點在位置型PID算法中,表現的尤為明顯。而對於變積分來說,是針對當前偏差的積分累計,就是說只影響當前這次的積分部分。再者,具體的實現方式也存在區別,特別是在位置型PID方式下尤為明顯。
我們在這里討論它們的區別原因,佷顯然就是我們沒辦法同時采用這兩種優化方式,只能分別實現,在后面我們將實現基於積分項的優化。
歡迎關注: