作者:Silent Knight?
PID時間系數(shù)對PID本身的影響
積分時間過小積分作用增強。
微分時間過大,微分控制作用過強,容易產(chǎn)生振蕩。
在這里的時間系統(tǒng),一般指的是采樣的時間,也就是PID控制的周期。在無人機當中一般采用10ms控制一次。
一般來說采樣周期越小,數(shù)字模擬越精確,控制效果越接近連續(xù)控制。
對大多數(shù)算法,縮短采樣周期可使控制回路性能改善,但采樣周期縮短時,頻繁的采樣必然會占用較多的計算工作時間,同時也會增加計算機的計算負擔(dān)。
對于變化迅速的,采樣周期應(yīng)適當減小。多回路控制,采樣周期應(yīng)該適當延長,使得有足夠的時間控制。
位置式PID
離散化后的公式:
優(yōu)點:靜態(tài)誤差小,溢出的影響小。
缺點:計算量很大,累積誤差相對大,在系統(tǒng)出現(xiàn)錯誤的情況下,容易使系統(tǒng)失控,積分飽和。
使用:一般需要結(jié)合輸出限幅和積分限幅使用。積分限幅是避免積分失控的一種手段,也是為了加快調(diào)節(jié)時間,減少積分飽和的影響,輸出限幅是為了使系統(tǒng)輸出不過度,也能夠減少系統(tǒng)的調(diào)節(jié)時間,減少超調(diào)量。
位置式PID適用于執(zhí)行沒有積分部件的對象。
增量式PID
離散化后的公式:
優(yōu)點:溢出的影響小,在系統(tǒng)出現(xiàn)錯誤的情況下,影響相對較?。ㄒ驗橹慌c過去的三次誤差有關(guān)),運算量也相對較小。
缺點:有靜態(tài)誤差(因為沒有累積誤差)。
使用:位置式PID適用于執(zhí)行有積分部件的對象。
位置式PID和增量式PID
C語言實現(xiàn):
?
?
//積分限幅 #define INERGRAL_MAX 200 #define INERGRAL_MAX -200 //輸出限幅 #define OUT_MIN ? ?-1000 #define OUT_MAX ? ?1000 // 濾波系數(shù)a(0-1) ? #define PARAMETER ? 0.01 ? ? ? ? ? ? ? ? //PID結(jié)構(gòu)體 typedef struct { ? volatile float ? ?Proportion; ? ? ? ? ? ? // 比例常數(shù) Proportional Const ? volatile float ? ?Integral; ? ? ? ? ? ? ? // 積分常數(shù) Integral Const ? volatile float ? ?Derivative; ? ? ? ? ? ? // 微分常數(shù) Derivative Const ? volatile int ? ? ?Error1; ? ? ? ? ? ? ? ? // Error[n-1] ? volatile int ? ? ?Error2; ? ? ? ? ? ? ? ? // Error[n-2] ? volatile int ? ? ?iError; ? ? ? ? ? ? ? ? // Error[n] ? volatile ?int ? ? Error_sum; } PID /****************************************************************************************/ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// ? ? ? ? ? ? ? ?位置式PID // ? ? ? ? ? ? ? ? ? ?//pwm=Kp*e(k)+Ki*∑e(k)+Kd[e(k)-e(k-1)] ? /****************************************************************************************/ float PID_Postion (int iError,PID* sptr) { ?float ?iIncpid=0; ?sptr->iError=iError; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// 計算當前誤差 ? ? ? //sptr->iError=filter(sptr->iError,sptr->Error1); 一階濾波器 ?sptr->Error_sum+=sptr->iError;//積分項 ? ? ?///當輸出限幅的時候,積分累加部分也應(yīng)同時進行限幅,以防輸出不變而積分項繼續(xù)累加,也即所謂的積分飽和過深。 ?//積分量限幅 ?if(sptr->Error_sum >INERGRAL_MAX) ?{ ? ?sptr->Error_sum = PID_InitStruct->INERGRAL_MAX ; ?} ?if(sptr->Error_sum < INERGRAL_MIN) ?{ ? ?sptr->Error_sum = PID_InitStruct->INERGRAL_MIN ; ?} ? ? ?iIncpid=sptr->Proportion * sptr->iError ? ? ? ? ? ? ? ? ?// P ? ? ? ? +sptr->Integral * sptr->Error_sum ? ? ? ? ? ? ? ?// I ? ? ? ? +sptr->Derivative * (sptr->iError-sptr->Error1); // D ?sptr->Error1=sptr->iError; ? ? ? ? ?// 存儲誤差,用于下次計算 ? ? ?iIncpid=PID_OutputLimit(sptr,iIncpid);//PID輸出限幅 ? ? ? ? ?return(iIncpid); ? ? ? ? ?// 返回計算值 ? } /****************************************************************************************/ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//增量式PID ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // ? ? ? ?pwm+=Kp[e(k)-e(k-1)]+Ki*e(k)+Kd[e(k)-2e(k-1)+e(k-2)] ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// /****************************************************************************************/ float PID_increase(int iError,PID* sptr) { ? ?float ?iIncpid=0; ?sptr->iError=iError;//直接檢測當前偏差 ?iIncpid=sptr->Proportion * (sptr->iError-sptr->Error1) ? ? ? ? ? ? ? ? ?// P ? ? ? ? +sptr->Integral * sptr->iError ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // I ? ? ? ? +sptr->Derivative * (sptr->iError-2*sptr->Error1+sptr->Error2); ?// D ? ? ? ? ? ? ?sptr->Error2=sptr->Error1; ? ? ? ? ? ? ? ? ? ? ? ? ?// 存儲誤差,用于下次計算 ?sptr->Error1=sptr->iError; ?iIncpid=PID_OutputLimit(sptr,iIncpid);//輸出限幅處理 ? ? ? ?return(iIncpid); ? // 返回增量值 ? } //PID初始化 void PID_Init(PID *sptr) { ? ?sptr->Derivative=0;//Kd ? ?sptr->Proportion=0;//Kp ? ?sptr->Integral=0;//Ki ? ?sptr->Error2=0;//第二次誤差 ? ?sptr->Error1=0; ? ?sptr->iError=0; ? ?sptr->Error_sum=0;//第一次誤差 } //PID輸出限制,根據(jù)PWM的輸出值進行增量式PID輸出限制 float PID_OutputLimit(PID *this, double output) ? { ? ? ? ?if ((int)output < OUT_MIN) ? ?{ ? ? ? ?output = OUT_MIN; ? ?} ? ? ? ?else if ((int)output > OUT_MAX) ? ? ? ?{ ? ? ? ?output = OUT_MAX; ? ?} ? ?return output; } //一階低通濾波器 //減少毛刺, //濾波系數(shù)。取值范圍為0~1, 值越小越穩(wěn)定,越大越靈敏。使用使需要根據(jù)實際情況調(diào)整濾波系數(shù) //輸入:新的采樣值 //輸出:濾波后的值 float filter(float value,float new_value) ? { ? ? ? ?return (1-PARAMETER)*value +PARAMETER*new_value; ? } ?
?
?
兩種針對積分的PID:
主要目的是為了盡可能利用積分的優(yōu)勢,消除靜態(tài)誤差,也同時減少積分的副作用。
使PID控制器的超調(diào)量減少,調(diào)節(jié)時間減少,系統(tǒng)更加穩(wěn)定。
積分分離式PID
積分分離式PID主要是針對位置式PID的積分,引入判斷誤差大小條件,是否使用積分項。
優(yōu)點:
判定誤差比較大的時候,取消積分項的,使用PD或者P控制,沒有I的控制,這樣,超調(diào)量和調(diào)節(jié)時間都會同時減少。當誤差比較小的時候,引入積分項,消除靜態(tài)誤差。
缺點:?
需要經(jīng)驗來確定判斷誤差的大小,在什么時候使用積分分離比較合適,也就是誤差多大的時候取消積分。
應(yīng)用:
主要用于消除余差,該方法特別適用于生產(chǎn)設(shè)備啟動階段的控制。
C語言實現(xiàn):PID位置式上面有,這里只需要添加一句判斷語句和對積分處理。
無積分分離式的PID:
?
?
sptr->Error_sum+=sptr->iError;//積分累加 iIncpid=sptr->Proportion * sptr->iError ? ? ? ? ? ? ? ? ?// P ? ? ? ? +sptr->Integral * sptr->Error_sum ? ? ? ? ? ? ? ?// I ? ? ? ? +sptr->Derivative * (sptr->iError-sptr->Error1); // D
?
?
積分分離式PID:
?
?
#includeint index=0;//積分分離標志 ? //積分分離處理 ?if(abs(sptr->iError)> 40) sptr->index=0; ?else ?{ ? ?sptr->index=1; ?sptr->Error_sum+=sptr->iError;//積分累加 ?} ?iIncpid=sptr->Proportion * sptr->iError ? ? ? ? ? ? ? ? ?// P ? ? ? ? +sptr->Integral * (sptr->Error_sum * index) ? ? ? ? ? ? ?// I ? ? ? ? +sptr->Derivative * (sptr->iError-sptr->Error1); // D
?
?
變速積分PID
變積分PID我的理解是積分分離式PID的變體,積分分離式PID 積分的的權(quán)重是1或者0,而變積分PID積分的權(quán)重會動態(tài)變化。取決于偏差,偏差越大,積分越慢。
優(yōu)缺點和積分分離式PID差不多,只不過,這個變速積分PID更加科學(xué)。
積分分離式PID:
?
?
#include#define I_MAX 40 #define I_MIN 5 int index=0;//積分分離標志 ? //變積分處理 ?if(abs(sptr->iError)> I_MAX) index=0; ?else if(abs(sptr->iError)< I_MIN) index=1; ?else ? index=(I_MAX - ?abs(sptr->iError) / (I_MAX - ?I_MIN); ?if(index!=0) sptr->Error_sum+=sptr->iError;//積分累加 ?iIncpid=sptr->Proportion * sptr->iError ? ? ? ? ? ? ? ? ?// P ? ? ? ? +sptr->Integral * (sptr->Error_sum * index) ? ? ? ? ? ? ?// I ? ? ? ? +sptr->Derivative * (sptr->iError-sptr->Error1); // D ? ? ? ? //變速積分也可以這樣處理:更加靈活 ?if(fabs(sptr->iError)> I_MAX) index=0; ?else if(fabs(sptr->iError)< I_MIN) index=1; ?else if(fabs(sptr->iError>10&&abs(sptr->iError)<20)) index=0.4; ?else if(fabs(sptr->iError>30&&abs(sptr->iError)<50)) index=0.8; ?else ? index=(I_MAX - ?abs(sptr->iError) / (I_MAX - ?I_MIN);
?
?
兩種針對微分的PID如下:
不完全微分PID
這里針對微分的PID控制算法,是減少微分作用的副作用的一些算法,以便更好地利用微分作用的作用。我們知道,當系統(tǒng)引入微分作用得時候會,引進高頻干擾。為了抑制這種干擾,便引入低通濾波器。
這種濾波器得優(yōu)缺點
優(yōu)點:
對周期性干擾具有良好的抑制作用
適用于波動頻率較高的場合
缺點:
相位滯后,靈敏度低
滯后程度取決于a值大小
不能消除濾波頻率高于采樣頻率的1/2的干擾信號
應(yīng)用:對于諸如階躍信號等信號變化很大信號。采用不完全微分能夠使得微分作用更為持續(xù)平緩。
控制圖:
位置式PID不完全微分:
公式:
增量式PID不完全微分:
公式:
?
?
//PID結(jié)構(gòu)體 typedef struct { ? volatile float ? ?Proportion; ? ? ? ? ? ? // 比例常數(shù) Proportional Const ? volatile float ? ?Integral; ? ? ? ? ? ? ? // 積分常數(shù) Integral Const ? volatile float ? ?Derivative; ? ? ? ? ? ? // 微分常數(shù) Derivative Const ? volatile int ? ? ?Error1; ? ? ? ? ? ? ? ? // Error[n-1] ? volatile int ? ? ?Error2; ? ? ? ? ? ? ? ? // Error[n-2] ? volatile int ? ? ?iError; ? ? ? ? ? ? ? ? // Error[n] ? volatile ?int ? ? Error_sum; ? volatile ?float ? ?thisdev;//前一拍時的微分項值 ? volatile ?float ? ?lastdev ;//前一拍時的微分項值 ? float ? ? ? ?dev_per;//微分系數(shù) ? } PID; //位置式PID不完全微分 float PID_Postion (int iError,PID* sptr) { ?float ?iIncpid=0; ?sptr->iError=iError; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// 計算當前誤差 ?sptr->Error_sum+=sptr->iError;//積分項 ?//不完全微分 ? ?sptr->thisdev=sptr->Derivative*(1-sptr->dev_per)*(sptr->iError-sptr->Error1)+sptr->dev_per*sptr->lastdev; ? ?iIncpid=sptr->Proportion * sptr->iError ? ? ? ? ? ? ? ? ?// P ? ? ? ? +sptr->Integral * sptr->Error_sum ? ? ? ? ? ? ? ?// I ? ? ? ? +sptr->thisdev; // D ? //更新值 ?sptr->Error1=sptr->iError; ? ? ? ? ? ?sptr->lastdev=sptr->thisdev;//更新下次微分值 ? ?return(iIncpid); ? ? ? ? ?// 返回計算值 ? } //增量式PID不完全微分 float PID_increase(int iError,PID* sptr) { ? ?float ?iIncpid=0; ?sptr->iError=iError;//直接檢測當前偏差 ? ?sptr->thisdev=sptr->Derivative*(1-sptr->dev_per)*(sptr->iError-2*sptr->Error1+sptr->Error2)+sptr->dev_per*sptr->lastdev; ? ?iIncpid=sptr->Proportion * (sptr->iError-sptr->Error1) ? ? ? ? ? ? ? ? ?// P ? ? ? ? +sptr->Integral * sptr->iError ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // I ? ? ? ? +sptr->thisdev; ?// D ? ? ? //更新 ? ? ? ? ?sptr->Error2=sptr->Error1; ? ? ? ? ? ? ? ? ? ? ? ? ? ?sptr->Error1=sptr->iError; ?sptr->lastdev=sptr->thisdev;//更新下次微分值 ? ?return(iIncpid); ? // 返回增量值 ? }
?
?
微分先行PID
控制器采用PI控制,將微分作用移動到反饋回路上。微分作用直接對被控量進行微分,對被控量速度進行控制。
優(yōu)點:在給定值頻繁變化的情況下,優(yōu)先采用微分先行的控制方案能夠更迅速的反應(yīng),對變化更為敏感。
缺點:更為敏感也就意味著更加不穩(wěn)定,變化量比較大的情況下,微分作用過分凸顯,容易導(dǎo)致超調(diào),引起系統(tǒng)振蕩加大。
圖示:
對微分部分引入一階慣性濾波器,進行離散化后的公式:
?
?
位置式:
?
?
?
?
?增量式:
?
?
C語言實現(xiàn):
?
?
//PID結(jié)構(gòu)體 //位置式 typedef struct { ? volatile float ? Proportion; ? ? ? ? ? ? // 比例常數(shù) Proportional Const ? volatile float ? Integral; ? ? ? ? ? ? ? // 積分常數(shù) Integral Const ? volatile float ? Derivative; ? ? ? ? ? ? // 微分常數(shù) Derivative Const ? volatile int ? ? Error1; ? ? ? ? ? ? ? ? // Error[n-1] ? volatile int ? ? Error2; ? ? ? ? ? ? ? ? // Error[n-2] ? volatile int ? ? iError; ? ? ? ? ? ? ? ? // Error[n] ? volatile ?int ? ?Error_sum; ? ? volatile ? float ?lastPv; ? ? ? ? ? ? //前一拍的測量值 ? volatile ? float ?gama; ? ? ? ? ? ? ? //微分先行濾波系數(shù) ? volatile ? float ?derivative;//微分項 ? ? } PID; //位置式微分先行PID float PID_Postion (float set_point,float processValue,PID* sptr) { ?float ?iIncpid=0; ?float ?temp=0,c1,c2,c3; ?sptr->iError=set_point-processValue; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// 計算當前誤差 ?sptr->Error_sum+=sptr->iError;//積分項 ?//微分先行 ?temp=sptr-> gama * sptr-> Derivative+ sptr-> Proportion;//γKp+Kd ?c3=sptr-> Derivative/temp;//Kd/γKp+Kd ?c2=(sptr-> Derivative+ sptr-> Proportion)/temp;//Kd+Kp/γKp+Kd ?c1=c3*sptr-> gama;//γ(Kp/γKp+Kd) ? ?sptr-> derivative=c1* sptr-> derivative+c2*processValue-c3* sptr-> lastPv; ?iIncpid=sptr->Proportion * sptr->iError ? ? ? ? ? ? ? ? ?// P ? ? ? ? +sptr->Integral * sptr->Error_sum ? ? ? ? ? ? ? ?// I ? ? ? ? +sptr->derivative; // D ? //更新值 ?sptr->Error1=sptr->iError; ? ? ? ? ? ?sptr->lastPv=sptr->processValue;//更新下次微分值 ? ?return(iIncpid); ? ? ? ? ?// 返回計算值 ? } //***********************************************************// // ? ? ? ? ? ? ?增量式微分先行PID //***********************************************************// //增量式PID結(jié)構(gòu)體 typedef struct { ? volatile float ? Proportion; ? ? ? ? ? ? // 比例常數(shù) Proportional Const ? volatile float ? Integral; ? ? ? ? ? ? ? // 積分常數(shù) Integral Const ? volatile float ? Derivative; ? ? ? ? ? ? // 微分常數(shù) Derivative Const ? volatile int ? ? Error1; ? ? ? ? ? ? ? ? // Error[n-1] ? volatile int ? ? iError; ? ? ? ? ? ? ? ? // Error[n] ? volatile ? float ?lastout; ? //上一次的測量量 ? ? volatile ? float ?lastout_proinc; ? ? ? ? ? ? ? ? //前一拍的過程測量增量 ? volatile ? float ?gama; ? ? ? ? ? ? ? ? ?//微分先行濾波系數(shù) ? volatile ? float ?out_proinc; ? ? ? ? //過程測量增量 ? volatile ? float ?derivative_inc; ? ?//微分項 ? ? } PID; //增量式PID不完全微分PID_increase float PID_increase(float set_point,float processValue,PID* sptr) { ?float ?iIncpid=0; ?float ?temp=0,c1,c2,c3; ?sptr->iError=set_point-processValue; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 計算當前誤差 ?//微分先行 ? ?out_proinc=processValue-lastout;//這次輸出增量 ? ? ?temp=sptr-> gama * sptr-> Derivative+ sptr-> Proportion;//γKp+Kd ?c3=sptr-> Derivative/temp;//Kd/γKp+Kd ?c2=(sptr-> Derivative+ sptr-> Proportion)/temp;//Kd+Kp/γKp+Kd ?c1=c3*sptr-> gama;//γ(Kp/γKp+Kd) ? ?sptr-> derivative_inc=c1* sptr-> derivative_inc+c2*out_proinc-c3* sptr-> lastout_proinc; ?iIncpid=sptr->Proportion * (sptr->iError-sptr-> ? ? ? ? ? ? ? Error1)// P ? ? ? ? +sptr->Integral * sptr->iError// I ? ? ? ? +sptr->derivative_inc; // D ? //更新值 ?sptr->Error1=sptr->iError; ?sptr->lastout_proinc=sptr->out_proinc;//過程增量更新 ? ? ? ? ? ?sptr->lastout=processValue;//上一次的測量量更新 ? ?return(iIncpid); ? ? ? ? ?// 返回增量值 }
?
?
帶死區(qū)的PID
死區(qū)控制簡單理解:
死區(qū),就是到了一個區(qū)域,在這個區(qū)域內(nèi),PID算法不起作用,也就是不做控制。
優(yōu)勢:
可以抑制由于控制器輸出量的量化造成的連續(xù)的較小的振蕩,也就是消除穩(wěn)定點附近的抖動。這是因為,現(xiàn)實中,總存在誤差,一些較小誤差難以消除。
缺點:
會造成一定的滯后。設(shè)定死區(qū)的值也是需要考慮,太小每作用,太大滯后嚴重。在零點附近時,若偏差很小,進入死去后,偏差置0會造成積分消失,如是系統(tǒng)存在靜差將不能消除,所以需要人為處理這一點。
應(yīng)用:
減少機械磨損,延長設(shè)備壽命等。
總結(jié)來說:PID調(diào)節(jié)器中設(shè)置死區(qū),犧牲的是調(diào)節(jié)精度,換來的是穩(wěn)定性。適用于精度不是很高的系統(tǒng)。
死區(qū)的輸出為0時,pid控制器的比例部分和微分部分均為0,積分部分保持不變。雖然誤差值在死區(qū)寬度設(shè)置的范圍內(nèi)變化,控制器的輸出卻保持不變。
C語言實現(xiàn):
?
?
#define DEAD_BAND 50//死區(qū)控制值 ? #define PID_OUT_MAX 200 //PID輸出上限 #define PID_OUT_MAX 200 //PID輸出上限 #include "math.h" ? ? ? ? ? //PID結(jié)構(gòu)體 typedef struct { ? volatile float ? ?Proportion; ? ? ? ? ? ? // 比例常數(shù) Proportional Const ? volatile float ? ?Integral; ? ? ? ? ? ? ? // 積分常數(shù) Integral Const ? volatile float ? ?Derivative; ? ? ? ? ? ? // 微分常數(shù) Derivative Const ? volatile int ? ? ?Error1; ? ? ? ? ? ? ? ? // Error[n-1] ? volatile int ? ? ?Error2; ? ? ? ? ? ? ? ? // Error[n-2] ? volatile int ? ? ?iError; ? ? ? ? ? ? ? ? // Error[n] ? volatile ?int ? ? Error_sum; } PID /****************************************************************************************/ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// ? ? ? ? ? ? ? ?位置式PID // ? ? ? ? ? ? ? ? ? ?//pwm=Kp*e(k)+Ki*∑e(k)+Kd[e(k)-e(k-1)] ? /****************************************************************************************/ float PID_Postion (float set_point,,float now_point,PID* sptr) { ?float ?iIncpid=0; ?sptr->iError=now_point-set_point; // 計算當前誤差 ?//死區(qū)控制算法 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if(fabs(sptr->iError)>DEAD_BAND) ?{ ?sptr->Error_sum+=sptr->iError;//積分項 ? ? ? ?iIncpid=sptr->Proportion * sptr->iError ? ? ? ? ? ? ? ? ?// P ? ? ? ? +sptr->Integral * sptr->Error_sum ? ? ? ? ? ? ? ?// I ? ? ? ? +sptr->Derivative * (sptr->iError-sptr->Error1); // D ?sptr->Error1=sptr->iError ; ? ? ? ? ?// 存儲誤差,用于下次計算 ?} ? ?else ?{ ? ?iIncpid=0; ? ?//sptr->Error_sum+=sptr->iError;//積分項 ? ? ? ?sptr->Error1=sptr->iError; ?// 存儲誤差,用于下次計算 ?} ? ? ? ?return(iIncpid); ? ? ? ? ?// 返回計算值 ? ? ? ? ? ? ? ? ? } /****************************************************************************************/ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//增量式PID ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // ? ? ? ?pwm+=Kp[e(k)-e(k-1)]+Ki*e(k)+Kd[e(k)-2e(k-1)+e(k-2)] ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// /****************************************************************************************/ float PID_increase(int iError,PID* sptr) { ? ?float ?iIncpid=0; ?sptr->iError=iError;//直接檢測當前偏差 ?if(fabs(sptr->iError)>DEAD_BAND) ?{ ?iIncpid=sptr->Proportion * (sptr->iError-sptr->Error1) ? ? ? ? ? ? ? ? ?// P ? ? ? ? +sptr->Integral * sptr->iError ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // I ? ? ? ? +sptr->Derivative * (sptr->iError-2*sptr->Error1+sptr->Error2); ?// D ? ? ? ? ? ? ?sptr->Error2=sptr->Error1; ? ? ? ? ? ? ? ? ? ? ? ? ?// 存儲誤差,用于下次計算 ?sptr->Error1=sptr->iError; } else { ?iIncpid=0;//輸出增量值為0 ?sptr->Error2=sptr->Error1; // 存儲誤差,用于下次計算 ? ? ? ? ? ? ? ? ? ? ? ? ?sptr->Error1=sptr->iError; } ?return(iIncpid); ? // 返回增量值 ? }
?
?
PID梯形積分
積分會有余差,消除不了,為了減少余差,提高運算的精度。便有了PID梯形積分,也能抑制一些隨機干擾。
缺點便是,曲線到達設(shè)定值的時間會延長。
總的來說:也就積分的作用削弱了。帶來的是余差進一步減小。
C語言實現(xiàn):
?
?
typedef struct { ? volatile float ? ?Proportion; ? ? ? ? ? ? // 比例常數(shù) Proportional Const ? volatile float ? ?Integral; ? ? ? ? ? ? ? // 積分常數(shù) Integral Const ? volatile float ? ?Derivative; ? ? ? ? ? ? // 微分常數(shù) Derivative Const ? volatile int ? ? ?Error1; ? ? ? ? ? ? ? ? // Error[n-1] ? volatile int ? ? ?Error2; ? ? ? ? ? ? ? ? // Error[n-2] ? volatile int ? ? ?iError; ? ? ? ? ? ? ? ? // Error[n] ? volatile ?int ? ? Error_sum; } PID /****************************************************************************************/ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// ? ? ? ? ? ? ? ?位置式PID // ? ? ? ? ? ? ? ? ? ?//pwm=Kp*e(k)+Ki*∑e(k)+Kd[e(k)-e(k-1)] ? /****************************************************************************************/ float PID_Postion (float set_point,,float now_point,PID* sptr) { ?float ?iIncpid=0; ?sptr->iError=now_point-set_point; // 計算當前誤差 ?//死區(qū)控制算法 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?sptr->Error_sum+=sptr->iError;//積分項 ? ? ? ?iIncpid=sptr->Proportion * sptr->iError ? ? ? ? ? ? ? ? ?// P ? ? ? ? +sptr->Integral * sptr->Error_sum/2 ? ? ? ? ? ? ? ?// 改變的只是這里,多除了2 ? ? ? ? +sptr->Derivative * (sptr->iError-sptr->Error1); // D ?sptr->Error1=sptr->iError ; ? ? ? ? ?// 存儲誤差,用于下次計算 ? ? ?return(iIncpid); ? ? ? ? ?// 返回計算值 ? ? ? ? ? ? ? ? ? }
?
?
總結(jié)
PID的變體還有很多,除了上文,還有專家PID與模糊PID是本文不能承載,也是我不能輸出,便作罷。
事物都有兩面性,該怎么選擇比較合適,怎么將PID的各種變體組合在一起合適自己的系統(tǒng),這個是需要綜合衡量和測試的,要知其然知其所以然。
編輯:黃飛
評論
查看更多