PID是比例-積分-微分控制的簡稱,也是一種控制算法,其特點是結構改變靈活、技術成熟、適應性強。
對一個控制系統而言,由于控制對象的精確數學模型難以建立,系統的參數經常發生變化,運用控制理論綜合分析要耗費很大的代價,卻不能得到預期的效果,所以人們往往采用PID調節器,根據經驗在線整定參數,以便得到滿意的控制效果。隨著計算機特別是微機技術的發展,PID控制算法已能用微機簡單實現,由于軟件系統的靈活性,PID算法可以得到修正而更加完善。
PID參數的工程整定方法
數字PID調節器與模擬PID調節器控制思想完全一樣,只是實現的物理過程不同,數字PID調節器參數的整定方法也和模擬PID調節器基本相同,只是增加了自整定功能。
參數整定的方法很多,我們只介紹幾種工程上最常用的方法。最實用的是試湊法。
1、自整法
現在的數字調節器,大多采用了模糊控制技術進行PID調節。
模糊控制基于專家知識或熟練操作者的成熟經驗,并可通過學習不斷更新。因而它具有智能性和自學習性,是一種人工智能調節方式。PID參數的自整功能,模擬專家操作,自動尋優,整定出最佳參數,使之達到理想的控制效果。我們在使用調節器時,應首先啟動自整功能,看一看整定的結果和控制效果,這是一個向專家系統學習的過程。自整定結果,也不一定都是最佳參數,有時還需我們進一步尋優。關于啟動自整功能的方法,請閱讀有關的說明書,非常簡單。
2、逐試法
將PID參數之一增加或減少30~50%,如果控制效果變好,則繼續增加或減少該參數,否則往反方向調整,直到效果滿足要求。
??3、臨界值整定性
? ? ? ?①比例+積分調節器 a、積分時間置于最大; b、置TD=0;
c、從一個比較大的比例帶逐步降低,每降低一次等待一定的時間,觀察記錄表上或記錄紙上被控參量的記錄曲線,直至記錄曲線出現周期性振蕩,然后在這一點上再加大比例帶,直到不出現振蕩;
D、減少積分時間,每減一次同樣等待一定的時間,觀察記錄曲線,當它低于由過程的滯后特性所決定的某個臨界值時,曲線又出現周期性振蕩,然后在這點上緩慢地加大積分時間直至振蕩停止。
②比例+積分+微分調節器
? ? ? ? a、積分時間置于最大;
?
? ? ? ? b、微分時間置于最小;
c、用上方法減小比例帶至周期性振蕩出現;
d、加大微分時間,使周期性振蕩停止,再減小比例帶,使振蕩重新出現,再加大微分時間,使振蕩停止,重復上述過程至加大微分時間后振蕩不再停止。再增大比例帶至周期性振蕩停止。
E、取積分時間為微分時間的2~5倍,如果周期性振蕩出現,加大積分時間至振蕩停止。
4、經驗整定法
根據PID控制原理和系統的特性,結合自己的經驗,直接設置PID參數,然后再根據控制效果做進一步的修改。
當調節器輸出變化很小,而引起測量值(被控參量)變化較大時,應將比例帶置于較大的數值,反之亦然。當調節器輸出變化,很快引起被控參量的變化,則積分和微分時間的整定就應較小,對于快速的流量系統則可以不加入微分運算,反之亦然。熟悉系統的特性是整定PID參數的關鍵。最后分析兩個溫度調節系統,加深對上述內容的理解。
例1:果凍條封口溫控系統,采用佳能電子CNG-5181智能數字調節儀出廠時參數設定為P=20,I=130,d=30,置設定值SV=150℃,PV達到SV時,啟動自整定功能,大約在20分鐘左右,自整結束。P=15,I=236,d=59。進入PID控制后,PV很快穩定在上150℃上,當設定值改為155℃,PV很快又穩定在155℃,動靜態品質均非常理想,實際上采用出廠設定參數值也能獲得滿意的控制效果。
例2,聯苯鍋爐用于化纖紡絲管道伴熱,工藝溫度為290℃~300℃,溫控器選用日本島電公司SR74型PID自整定溫控儀,出廠設定值為P=3,I=120,D=30,在該參數下,溫度波動較大為295℃±3℃。啟動自整定功能,約1小時后,整定出的PID參數為P=0.3,I=1168,D=292,顯示溫度始終為295℃,改變設定值為300℃時。顯示溫度又始終為300℃。
點評:果凍條封口溫控系統屬于小型溫控系統,系統靈敏度高,熱慣性小,滯后時間短,所以比例帶較大,積分、微分時間常數均比較小。或者說比例、微分作用較弱,積分作用較強。例2中的溫控系統屬于大型的調節系統,靈敏度低,熱慣性大,滯后時間長,所以整定出的PID參數和例1相反,比例帶較小,積分和微分時間常數均較大,且TI≈4TD。
1)臨界比例度法
這是目前使用較廣的一種方法,具體作法如下:
先在純比例作用下(把積分時間放到最大,微分時間放到零),在閉合的調節系統中,從大到小地逐漸地改變調節器的比例度,就會得到一個臨界振蕩過程,如圖8所示。這時的比例度叫臨界比例度δk,周期為臨界振蕩周期Tk。記下δk和Tk,然后按表1的經驗公式來確定調節器的各參數值。
表1 臨界比例度法數據表
這種方法在下面兩種情況下不宜采用:
a)臨界比例度過小,因為這時候調節閥很容易處于全開及全關位置,對于工藝生產不利,舉例來說,對于一個用燃料油(或瓦斯)加熱的爐子,如δ很小,接近雙位調節,將一會兒熄火,一會兒煙囪濃煙直沖。
b)工藝上約束條件較嚴格時,因為這時候如達到等幅振蕩,將影響生產的安全運行。
2)衰減曲線法
臨界比例度法是要系統等幅振蕩,還要多次試湊,而用衰減曲線法較簡單,一般又有兩種方法。
(1)4:1衰減曲線法
使系統處于純比例作用下,在達到穩定時,用改變給定值的辦法加入階躍干擾,觀察記錄曲線的衰減比,然后逐漸從大到小改變比例度,使出現4:1的衰減比為止,如下圖所示。記下此時的比例度δs和Ts的值,再按表2的經驗公式來確定PID數值。
表2 4:1衰減曲線法數據表
(2)10:1衰減曲線法
有的過程,4:1衰減仍嫌振蕩過強,可采用10:1衰減曲線法。方法同上,得到10:1衰減曲線,記下此時的比例度δ's和上升時間T's,再按表3的經驗公式來確定PID的數值。衰減曲線如下圖所示。
表3 10:1衰減曲線法數據表
采用衰減曲線法必須注意幾點:
a)加給定干擾不能太大,要根據生產操作要求來定,一般在5%左右,也有例外的情況。
b)必須在工藝參數穩定的情況下才能加給定干擾,否則得不到正確得δs、Ts、或δ's和T's值。
c)對于反應快的系統,如流量、管道壓力和小容量的液位調節等,要在記錄紙上嚴格得到4:1衰減曲線較困難,一般以被調參數來回波動兩次達到穩定,就近似地認為達到4:1衰減過程了。
下面舉一個現場整定的例子。在某塔頂溫度調節系統中,被調參數是塔頂溫度,工藝允許波動為<4℃,調節參數是回流量。在整定過程中,考慮到對象滯后較大,反應較慢的情況,δ的選擇從50%開始湊試起,此時在階躍作用下(給定值降低2%)的過渡過程曲線見下圖(a)。此時調節時間長,不起振蕩,于是將比例度減少,δ=30%、20%、及10%時的曲線見(b)、(c)、(d)。顯然,20%的情況最好,衰減比接近4:1,Ts=10分。
按4:1衰減曲線法數據表定出整定參數:
δ=0.8·δs=16%;
Ti=0.3·Ts=3分;
Td=0.1·Ts=1分。
投運時,先將δ放在較大的數值,把Ti從大減少到3分,把Td從小到大逐步放大到1分,然后把δ拉到15%,(如果在δ=15%的條件下很快地把Td放到1分,調節器的輸出會劇烈變化)。再對系統加2% 的給定值變化時,仍產生4:1衰減過程,見圖(e)所示,調節質量顯著改善,超調量小于1℃,調節時間為6.5分。
3)經驗試湊法
這是在生產實踐中所總結出來的方法,目前應用最為廣泛,其步驟簡述如下:
(1)確定KP
可用“優選法”,詳見下表
表4 優選法確定KP
(2)看曲線,調參數,根據操作經驗,看曲線的形狀,直接在閉合的調節系統中逐步反復試湊,一直得到滿意數據。
在實踐中,把具體整定的方法總結了幾段順口溜:
參數整定找最佳,從大到小順次查,先是比例后積分,最后才把微分加;曲線振蕩很頻繁,比例度值要放大, //比例度放大即比例系數KP要減小。曲線漂浮繞大彎,比例度值應減小;曲線偏離回復慢,積分時間往下降,曲線振蕩周期長,積分時間再加長;曲線振蕩頻率快,先把微分降下來,動差大來波動慢,微分時間應加長;理想曲線兩個波,前高后低四比一,一看二調多分析,調節質量不會低。
第一段講的是整定順序,δ和Ti都是從大到小逐步加上去,微分是最后才考慮的。第二段講的是比例度如何整定。第三段講的是積分時間如何整定。第四段講的是微分時間如何整定。第五段講的是標準。
上面這種方法步驟是先加δ,再加Ti,最后才加Td。應用中較穩妥。
另一種方法是先從表列范圍內取Ti的某個數值,如果需要微分,則取Td=(1/3~1/4)Ti,然后對δ進行試湊,也能較快地達到要求。
常用PID控制參數的經驗值如下圖所示。
PID算法的定義:
P:比例控制項。 I:積分控制項。 D:微分控制項。
設當前輸出量為U,我們的期望值或是設定值為U0,則可得當前時刻誤差:E=U-U0;
PID算法即是對誤差量E及E的歷史進行某種線性組合得到控制量的算法。
一般形式:
Up=P*E;
Ui=i*(E+E_1+E_2+.。。) E_n為之前的第n次誤差.
Ud=i*(E-E_1)
U=Up+Ui+Ud; U為PID控制輸出量.
上式中Ui的計算不太方便,長時間單方向的累加將可能出現溢出,于是將上式改為如下所示的增量形式:
Up=p*(E-E_1) 比例項增量
Ui=i*(E-2*E_1+E_2) 微分項增量
Ud=i*E 積分項增量
U=Uout_1+Up+Ui+Ud U為PID控制輸出量,Uout_1為前次PID輸出值
Uout=U 保存本次值
對于上面的公式或理論,便可得到相應的C語言程序:
//======================定義PID結構=========================
static float MinValue; //最大值限制
static float MaxValue; //最小值限制
static float CurrentValue; //當前采樣值
static struct PID{
float Ki; //定義積分常數
float Kp; //定義比例常數
float Kd; //定義微分常數
float E_2; //存儲前前次誤差
float E_1; //存諸前次誤差
float E; //存儲本次誤差
float OutPut; //本次輸出量
float ValueSet; //設定值或期望值
}Control;
//===========================PID計算函數=====================
void PidWork() {
float Up,Ud,Ui;
Control.E=CurrentValue-Control.ValueSet; //得到本次誤差
Up =Control.Kp*(Control.E-Control.E_1); //得到比例項
Ud=Control.Kd*(Control.E-2*Control.E_1+Control.E_2); //得到微分項
Ui=Control.Ki*Control.E; //得到積分項
Control.E_2=Control.E_1; //歷史存儲
Control.E_1=Control.E;
Control.OutPut+=Up+Ud+Ui; //計算增量和
if(Control.OutPut
else if(Control.OutPut》MaxValue)Control.OutPut=MaxValue;
}
//==========================初始化速度=========================
void PidInit() {
MinValue=0;
MaxValue=1000;
CurrentValue=0;
Control.Kp=-6;
Control.Ki=-1.5;
Control.Kd=-0.5;
Control.E=0;
Control.E_2=0;
Control.E_1=0;
Control.ValueSet=100;
Control.OutPut=0;
}
以上三個函數為PID的主體函數,也是萬用PID函數.代碼量已經相當精簡了。注意上面的PID初始化函數中有Kp,Ki,Kd的符號一定要正確,否則輸出量方向相反,后果不堪設想!!!
附上一段完整代碼:
#include
struct _pid {
int pv; /*integer that contains the process value*/
int sp; /*integer that contains the set point*/
float integral;
float pgain;
float igain;
float dgain;
int deadband;
int last_error;
};
struct _pid warm,*pid;
int process_point, set_point,dead_band;
float p_gain, i_gain, d_gain, integral_val,new_integ;;
/*------------------------------------------------------------------------
pid_init
DESCRIPTION This function initializes the pointers in the _pid structure
to the process variable and the setpoint. *pv and *sp are
integer pointers.
------------------------------------------------------------------------*/
void pid_init(struct _pid *warm, int process_point, int set_point)
{
struct _pid *pid;
pid = warm;
pid-》pv = process_point;
pid-》sp = set_point;
}
/*------------------------------------------------------------------------
pid_tune
DESCRIPTION Sets the proportional gain (p_gain), integral gain (i_gain),
derivitive gain (d_gain), and the dead band (dead_band) of
a pid control structure _pid.
------------------------------------------------------------------------*/
void pid_tune(struct _pid *pid, float p_gain, float i_gain, float d_gain, int dead_band)
{
pid-》pgain = p_gain;
pid-》igain = i_gain;
pid-》dgain = d_gain;
pid-》deadband = dead_band;
pid-》integral= integral_val;
pid-》last_error=0;
}
/*------------------------------------------------------------------------
pid_setinteg
DESCRIPTION Set a new value for the integral term of the pid equation.
This is useful for setting the initial output of the
pid controller at start up.
------------------------------------------------------------------------*/
void pid_setinteg(struct _pid *pid,float new_integ)
{
pid-》integral = new_integ;
pid-》last_error = 0;
}
/*------------------------------------------------------------------------
pid_bumpless
DESCRIPTION Bumpless transfer algorithim. When suddenly changing
setpoints, or when restarting the PID equation after an
extended pause, the derivative of the equation can cause
a bump in the controller output. This function will help
smooth out that bump. The process value in *pv should
be the updated just before this function is used.
------------------------------------------------------------------------*/
void pid_bumpless(struct _pid *pid)
{
pid-》last_error = (pid-》sp)-(pid-》pv);
}
/*------------------------------------------------------------------------
pid_calc
DESCRIPTION Performs PID calculations for the _pid structure *a. This function uses the positional form of the pid equation, and incorporates an integral windup prevention algorithim. Rectangular integration is used, so this function must be repeated on a consistent time basis for accurate control.
RETURN VALUE The new output value for the pid loop.
USAGE #include ‘control.h’*/
float pid_calc(struct _pid *pid)
{
int err;
float pterm, dterm, result, ferror;
err = (pid-》sp) - (pid-》pv);
if (abs(err) 》 pid-》deadband)
{
ferror = (float) err; /*do integer to float conversion only once*/
pterm = pid-》pgain * ferror;
if (pterm 》 100 || pterm 《》
{
pid-》integral = 0.0;
}
else
{
pid-》integral += pid-》igain * ferror;
if (pid-》integral 》 100.0)
{
pid-》integral = 100.0;
}
else if (pid-》integral 《 0.0)=“” pid-=“”》integral = 0.0;
}
dterm = ((float)(err - pid-》last_error)) * pid-》dgain;
result = pterm + pid-》integral + dterm;
}
else result = pid-》integral;
pid-》last_error = err;
return (result);
}
void main(void)
{
float display_value;
int count=0;
pid = &warm;
// printf(‘Enter the values of Process point, Set point, P gain, I gain, D gain \n’);
// scanf(‘%d%d%f%f%f’, &process_point, &set_point, &p_gain, &i_gain, &d_gain);
process_point = 30;
set_point = 40;
p_gain = (float)(5.2);
i_gain = (float)(0.77);
d_gain = (float)(0.18);
dead_band = 2;
integral_val =(float)(0.01);
printf(‘The values of Process point, Set point, P gain, I gain, D gain \n’);
printf(‘ %6d %6d %4f %4f %4f\n’, process_point, set_point, p_gain, i_gain, d_gain);
printf(‘Enter the values of Process point\n’);
while(count《》
{
scanf(‘%d’,&process_point);
pid_init(&warm, process_point, set_point);
pid_tune(&warm, p_gain,i_gain,d_gain,dead_band);
pid_setinteg(&warm,0.0); //pid_setinteg(&warm,30.0);
//Get input value for process point
pid_bumpless(&warm);
// how to display output
display_value = pid_calc(&warm);
printf(‘%f\n’, display_value);
//printf(‘\n%f%f%f%f’,warm.pv,warm.sp,warm.igain,warm.dgain);
count++;
}
}
評論