前面我們發佈了一系列PID控制器相關的文章,包括經典PID控制器以及參數自適應的PID控制器。這一系列PID控制器雖說實現了主要功能,也在實際使用中取得了良好效果,但還有很多的細節部分可以改進以提高性能和靈活性。所以在這篇中我們來討論改進PID控制器以實現降低設定值階躍帶來的擾動。
1、提出問題
我們在使用PID控制器時,如果大幅度修改設定值有可能引入一個大的階躍擾動。特別是對微分作用,這一擾動可能引起很大的振盪,這種情況我們通常稱之爲微分衝擊。
爲了應對因爲微分作用對設定值變化造成的激烈響應,人們引入了微分先行的PID算法,這一算法是將基於偏差的微分修改爲基於輸入的微分。也就是說設定值的變化對微分不會有突變的影響,而只有作用在被控對象後微分才起作用,從而消除了設定值的變化帶來的微分作用衝擊。
然而有些時候,設定值的階躍變化也會通過比例作用反映出來,這種衝擊也會對系統造成振盪。當然我們也可以將其改爲基於輸入的比例,雖然也可以消除設定值的突變影響,但是比例和微分都是面向輸入信號的對設定值的響應將會變得滯後,這也並非我們想要的。
所以我們希望能找到一種辦法,既可響應設定值的變化,又不會造成大的衝擊,這就是我們在此要考慮的問題。
2、分析設計
前面實際我們已經討論了基於輸入的比例和微分,這實際上改變了PID的調節方式,這裏我們希望從另一個角度來考慮對設定值的響應問題。我們曾經討論過步進式PID的控制方式就是一種比較好的處理辦法。
所謂步進式PID算法,實際就是在設定值發生階躍變化時,不直接對階躍信號進行響應,而是在一定的時間內逐步改變設定值,直至使設定值達到目標值。這種逐步改變設定值的辦法使得對象運行平穩。適用於高精度伺服系統的位置跟蹤。
佷顯然,這一方法並未改變PID控制器本身,而是對設定值做了前期處理。所以其結構框圖與控制方程與其他的PID控制算法是一致的。
爲了對設定值做必要處理,以使其不至快速變化,有多種方法。比較常用的是建立線性變化函數的辦法。我們可以規定設定值從0-100%的變化時間爲T,則可以確定設定值變化的斜率絕對值,或者說是步長。知道步長後,我們就可以根據步長來不斷修改設定值,直到目標值。可用公式描述爲:
其中SPt爲設定值目標值,SPs爲設定值的起始值,sl爲步長,k爲步長的變化係數:
我們希望能夠根據我們自己的需要使用步進或者不使用步進,所以我們需要在PID對象中添加一個屬性來配置其是否使用。
/*定義PID對象類型*/
typedef struct CLASSIC
{
float *pPV; //測量值指針
float *pSV; //設定值指針
float *pMV; //輸出值指針
float *pKp; //比例係數指針
float *pKi; //積分系數指針
float *pKd; //微分系數指針
uint16_t *pMA; //手自動操作指針
float setpoint; //設定值
float lasterror; //前一拍偏差
float preerror; //前兩拍偏差
float deadband; //死區
float result; //PID控制器計算結果
float output; //輸出值0-100%
float maximum; //輸出值上限
float minimum; //輸出值下限
float errorabsmax; //偏差絕對值最大值
float errorabsmin; //偏差絕對值最小值
float alpha; //不完全微分系數
float deltadiff; //微分增量
float integralValue; //積分累計量
float gama; //微分先行濾波係數
float lastPv; //上一拍的過程測量值
float lastDeltaPv; //上一拍的過程測量值增量
ClassicPIDDRType direct; //正反作用
ClassicPIDSMType sm; //設定值平滑
}CLASSICPID;
3、軟件實現
我們討論的對設定值的響應方式,其實就是直接給定設定值或者採用步進式給定設定值。所謂步進式其實質是將設定值的突變修改爲平緩的變化,這一處理方式在控制中有大量應用。處理設定值變化過程的流程如下所示:
根據我們前面的描述和上面的流程圖我們可以實現對PID控制器的修改。我們將對設定值處理的的部分單獨置爲函數,這樣除了使用線性方式處理外我們也可以根據需要採取其他方式處理。
/*設定值平滑變化處理函數*/
static void SmoothSetpoint(CLASSICPID *vPID)
{
float stepIn=(vPID->maximum-vPID->minimum)*0.1;
float kFactor=0.0;
if(fabs(vPID->setpoint-*vPID->pSV)<=stepIn)
{
vPID->setpoint=*vPID->pSV;
}
else
{
if(vPID->setpoint-*vPID->pSV>0)
{
kFactor=-1.0;
}
else if(vPID->setpoint-*vPID->pSV<0)
{
kFactor=1.0;
}
else
{
kFactor=0.0;
}
vPID->setpoint=vPID->setpoint+kFactor*stepIn;
}
}
/* 通用PID控制器,採用增量型算法,具有變積分,梯形積分和抗積分飽和功能,微分項採用不完全微分,一階濾波,alpha值越大濾波作用越強 */
void PIDRegulator(CLASSICPID *vPID)
{
float thisError;
float result;
float factor;
float increment;
float pError,dError,iError;
if(*vPID->pMA<1) //手動模式
{
vPID->output=*vPID->pMV;
//設置無擾動切換
vPID->result=(vPID->maximum-vPID->minimum)*vPID->output/100.0+-vPID->minimum;
*vPID->pSV=*vPID->pPV;
vPID->setpoint=*vPID->pSV;
}
else //自動模式
{
if(vPID->sm==SMOOTH_ENABLE)
{
SmoothSetpoint(vPID);
}
else
{
vPID->setpoint=*vPID->pSV;
}
thisError=vPID->setpoint-(*vPID->pPV); //得到偏差值
result=vPID->result;
if (fabs(thisError)>vPID->deadband)
{
pError=thisError-vPID->lasterror;
iError=(thisError+vPID->lasterror)/2.0;
dError=thisError-2*(vPID->lasterror)+vPID->preerror;
//變積分系數獲取
factor=VariableIntegralCoefficient(thisError,vPID->errorabsmax,vPID->errorabsmin);
//計算微分項增量帶不完全微分
vPID->deltadiff=(*vPID->pKd)*(1-vPID->alpha)*dError+vPID->alpha*vPID->deltadiff;
increment=(*vPID->pKp)*pError+(*vPID->pKi)*factor*iError+vPID->deltadiff; //增量計算
}
else
{
if((fabs(vPID->setpoint-vPID->minimum)<vPID->deadband)&&(fabs((*vPID->pPV)-vPID->minimum)<vPID->deadband))
{
result=vPID->minimum;
}
increment=0.0;
}
//正反作用設定
if(vPID->direct==DIRECT)
{
result=result+increment;
}
else
{
result=result-increment;
}
/*對輸出限值,避免超調和積分飽和問題*/
if(result>=vPID->maximum)
{
result=vPID->maximum;
}
if(result<=vPID->minimum)
{
result=vPID->minimum;
}
vPID->preerror=vPID->lasterror; //存放偏差用於下次運算
vPID->lasterror=thisError;
vPID->result=result;
vPID->output=(vPID->result-vPID->minimum)/(vPID->maximum-vPID->minimum)*100.0;
*vPID->pMV=vPID->output;
}
}
4、總結
我們引入了讓設定值不大範圍突變的方式,而不需要改變PID控制器的控制方式。經測試效果能夠滿足我們的要求。在我們這裏步長固定採用量程的十分之一,事實上我們可以將其作爲初始化參數予以修改,甚至我們也可以採用一定條件下變步長的方式來滿足更高的控制要求。