前面已經實現了各種的PID算法,然而在某些給定值頻繁且大幅變化的場合,微分項常常會引起系統的振盪。為了適應這種給定值頻繁變化的場合,人們設計了微分先行算法。
1、微分先行算法的思想
微分先行PID控制是只對輸出量進行微分,而對給定指令不起微分作用,因此它適合於給定指令頻繁升降的場合,可以避免指令的改變導致超調過大。微分先行的基本結構圖:
根據上面的結構圖,我們可以推出PID控制器的輸出公式,比例和積分是不變的只是微分部分變為只對對象輸出積分,記為y,我們對微分部分引入一階慣性濾波:,可記微分部分的傳遞函數如下:
於是微分部分可以推導出如下的公式:
前面我們在推導PID的公式時曾規定:Kd=Kp*Td/T,於是我們將其帶入公式可得:
於是我們就可以得到微分先行的離散化公式:
這即是位置型PID的計算公式了,我們也可以使用前面的方法推導增量型的計算公式如下:
從上面的公式我們發現,微分部分只與測量值有關,而且與連續的幾個測量值都有關。而與設定值沒有關系,設定值的階躍變化不會造成高頻的干擾。
2、算法實現
前面我們已經簡單的介紹了微分現行的基本結構,也推導了位置型以及增量型公式,接下來我們根據前面對其基本思想的描述,來實現基於微分先行的PID算法實現,同樣是包括位置型和增量型兩種實現方式。
(1)位置型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 derivative; //微分項 22 23 float lastPv; //前一拍的測量值 24 25 float gama; //微分先行濾波系數 26 27 }PID;
接下來實現PID控制器:
1 void PIDRegulation(PID *vPID, float processValue) 2 3 { 4 5 float thisError; 6 7 float c1,c2,c3,temp; 8 9 thisError=vPID->setpoint-processValue; 10 11 vPID->integral+=thisError; 12 13 14 15 temp= vPID-> gama * vPID-> derivativegain + vPID-> proportiongain; 16 17 c3= vPID-> derivativegain/temp; 18 19 c2=( vPID-> derivativegain+ vPID-> proportiongain)/temp; 20 21 c1= vPID-> gama*c3; 22 23 vPID-> derivative=c1* vPID-> derivative+c2* processValue+c3* vPID-> lastPv; 24 25 26 27 vPID->result=vPID->proportiongain*thisError+vPID->integralgain*vPID->integral+vPID-> derivative; 28 29 vPID->lasterror=thisError; 30 31 vPID-> lastPv= processValue; 32 33 }
對於微分先行的位置型PID控制器來說,本次的微分項不僅與上一拍的微分結果有關,而且與上一拍的測量值有關。
(2)增量型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 preerror; //前兩拍偏差 18 19 float deadband; //死區 20 21 float result; //輸出值 22 23 float deltadiff; /*微分增量*/ 24 25 float integralValue; /*積分累計量*/ 26 27 float gama; /*微分先行濾波系數*/ 28 29 float lastPv; /*上一拍的過程測量值*/ 30 31 float lastDeltaPv; /*上一拍的過程測量值增量*/ 32 33 }PID;
接下來實現PID控制器:
1 void PIDRegulation(PID *vPID, float processValue) 2 3 { 4 5 float thisError; 6 7 float increment; 8 9 float pError,iError; 10 11 float c1,c2,c3,temp; 12 13 float deltaPv; 14 15 16 17 temp= vPID-> gama * vPID-> derivativegain + vPID-> proportiongain; 18 19 c3= vPID-> derivativegain/temp; 20 21 c2=( vPID-> derivativegain+ vPID-> proportiongain)/temp; 22 23 c1= vPID-> gama*c3; 24 25 26 27 deltaPv= processValue- vPID-> lastDeltaPv 28 29 vPID-> deltadiff =c1* vPID-> deltadiff +c2* deltaPv +c3* vPID-> lastDeltaPv; 30 31 32 33 thisError=vPID->setpoint-processValue; //得到偏差值 34 35 pError=thisError-vPID->lasterror; 36 37 iError=thisError; 38 39 increment=vPID->proportiongain*pError+vPID->integralgain*iError+ vPID-> deltadiff; //增量計算 40 41 42 43 vPID->preerror=vPID->lasterror; //存放偏差用於下次運算 44 45 vPID->lastDeltaPv=deltaPv; 46 47 vPID->lastPv= processValue; 48 49 vPID->lasterror=thisError; 50 51 vPID->result+=increment; 52 53 }
這就實現了一個最簡單的微分先行的增量型PID控制器,與一般的PID控制器相比,還需要知道前一拍的測量值、前一拍的測量值增值以及前一拍的微分增量,其余的只需要按公式完成即可。
3、總結
微分先行由於微分部分只對測量值起作用所以可以消除設定值突變的影響,還可以引入低通濾波,甚至在必要時將比例作用也可進行相應的改進。其實用於設定值會頻繁改變的過程對象,防止設定值的頻繁波動造成系統的不穩定。該控制對於改善系統的動態特性是有好處的,但勢必影響響應的速度,需全面考慮。
歡迎關注: