增量式pidc語言
1. 求一下增量式和位置式PID的C語言程序
增量式PID:
typedefstruct{
floatscope;//輸出限幅量
floataim;//目標輸出量
floatreal_out;//實際輸出量
floatKp;
floatKi;
floatKd;
floate0;//當前誤差
floate1;//上一次誤差
floate2;//上上次誤差
}PID_Type;
#definemin(a,b)(a<b?a:b)
#definemax(a,b)(a>b?a:b)
#definelimiter(x,a,b)(min(max(x,a),b))
#defineexchange(a,b,tmp)(tmp=a,a=b,b=tmp)
#definemyabs(x)((x<0)?-x:x)
floatpid_acc(PID_Type*pid)
{
floatout;
floatep,ei,ed;
pid->e0=pid->aim-pid->real_out;
ep=pid->e0-pid->e1;
ei=pid->e0;
ed=pid->e0-2*pid->e1+pid->e2;
out=pid->Kp*ep+pid->Ki*ei+pid->Kd*ed;
out=limiter(out,-pid->scope,pid->scope);
pid->e2=pid->e1;
pid->e1=pid->e0;
returnout;
}
位置式PID:
typedefstruct{
floatscope;//輸出限幅量
floataim;//目標輸出量
floatreal_out;//反饋輸出量
floatKp;
floatKi;
floatKd;
floatSum;
floate0;//當前誤差
floate1;//上一次誤差
}PID_Type;
#definemax(a,b)(a>b?a:b)
#definemin(a,b)(a<b?a:b)
#definelimiter(x,a,b)(min(max(x,a),b))
floatpid_pos(PID_Type*p)
{
floatpe,ie,de;
floatout=0;
p->e0=p->aim-p->real_out;//計算當前誤差
p->Sum+=p->e0;//誤差積分
de=p->e0-p->e1;//誤差微分
pe=p->e0;
ie=p->Sum;
p->e1=p->e0;
out=pe*(p->Kp)+ie*(p->Ki)+de*(p->Kd);
out=limiter(out,-p->scope,p->scope);//輸出限幅
returnout;
}
親手移植到我的stm32小車上 調試3個參數後正常使用。
2. PID演算法的C語言實現
基本流程
積分環節:主要是用來消除 靜差 (系統穩定後輸出值和設定值之間的差值,積分環節實際上就是偏差累積的過程,把累積的誤差加到原來系統上以抵消系統造成的靜差)
微分環節:反映了偏差信號的變化規律,根據偏差信號的變化規律來進行超前調節,從而增加系統的快速性
對上述公式進行離散化(采樣):兩個公式
增量型PID:
通過增量型PID公式可以看出,最終表達結果和最近三次的偏差有關,最終輸出結果應該為:
首先定義結構變數體:
然後初始化變數
最後編寫控制演算法
基本演算法,沒有考慮死區問題,沒有設定上下限
在啟動、結束或大幅度增減設定時,短時間內系統輸出有很大的偏差,會造成PID運算的積分積累,導致控制量超過執行機構可能允許的最大動作范圍對應的極限控制量,從而引起較大的超調,甚至是振盪。
為了克服這個問題,引入積分分離的概念,即當被控量和設定值偏差較大時,取消積分作用;當被控量接近設定值時,引入積分控制,以消除靜差,提高精度。
abs :絕對值
令index=0使積分環節失效
積分飽和現象:如果系統存在一個方向的偏差,PID控制器的輸出由於積分作用的不斷累加而加大,從而導致執行機構達到極限位置。此時計算器輸出量超出正常運行范圍而進入飽和區,一旦系統出現反向偏差,輸出量將逐漸從飽和區退出,進入飽和區越深則退出飽和區時間越長,在這段時間里,執行機構仍然停留在極限位置而不隨偏差反向而立即做出相應改變,造成性能惡化。
採用梯形積分能夠減小余差,提高精度
改變積分系數,若偏差大,積分作用減弱,系數減小;若偏差小,積分作用增強,系數增大。
變積分PID的基本思想是設法改變積分項的累加速度,使其與偏差大小對應。
使整個系統的穩定速度非常快
比例系數Kp的作用是加快系統的響應速度提高系統的調節精度
積分系數Ki的作用是消除系統的穩態誤差
微分系數Kd的作用是改善系統的動態特性
反應系統性能的兩個參數是系統誤差和誤差變化律
3. c璇璦 紼嬪簭 鍊掔珛鎽 奼傚姪 pid搴旂敤
#include "stc12.h"
#include <intrins.h>
#include"pid.h"
typedef unsigned char uint8;
typedef unsigned int uint16;
typedef unsigned long int uint32;
/*********************************鍑芥暟澹版槑******************
緇撴瀯浣撹懼畾
***********************************************************/
typedef struct PIDValue
{
uint32 Ek_Uint32[3]; //宸鍊間繚瀛橈紝緇欏畾鍜屽弽棣堢殑宸鍊
uint8 EkFlag_Uint8[3]; //宸鍊兼爣蹇椾綅絎﹀彿錛1鍒欏瑰簲鐨勪負璐熸暟錛0涓哄瑰簲鐨勪負姝f暟
uint8 KP_Uint8; //姣斾緥緋繪暟
uint8 KI_Uint8; //縐鍒嗙郴鏁
uint8 KD_Uint8; //寰鍒嗘樉紺
uint16 Uk_Uint16; //涓婁竴鏃跺埢鐨勬帶鍒剁數鍘
uint16 RK_Uint16; //璁懼畾鍊
uint16 CK_Uint16; //瀹為檯鍊
uint8 Vaule_Flag; //杈撳嚭鐨勫兼h礋鏍囧織浣嶏紝0涓烘o紝1涓鴻礋
}PIDValueStr;
PIDValueStr PID; //瀹氫箟涓涓緇揚鏋勪綋
uint16 out ; // 鍔犵儹杈撳嚭(PID榪愮畻鍚庣殑杈撳嚭鍊)
/***********************************************************************************
澧為噺鍨婸ID綆楀紡:PID 錛歎k=KP*[E(k)-E(k-1)]+KI*E(k)+KD*[E(k)-2E(k-1)+E(k-2)]
鍑芥暟鍏ュ彛: RK(璁懼畾鍊),CK(瀹為檯鍊),KP,KI,KD PID姣斾緥鍙傛暟
鍑芥暟鍑哄彛: U(K)
PID榪愮畻鍑芥暟
**************************************************************************************/
uint16 PID_Calc(uint16 PIDinput)
{
uint32 Temp[3]; //涓闂翠復鏃跺彉閲
uint32 PostSum; //姝f暟鍜
uint32 NegSum; //璐熸暟鍜
Temp[0] = 0; //緇欏偍瀛樹腑闂翠復鏃跺彉閲忚祴鍒濆
Temp[1] = 0;
Temp[2] = 0;
PostSum = 0; //緇欏瓨鍌ㄦ墍鏈夌殑姝f暟鍙橀噺璧嬪垵鍊
NegSum = 0; //緇欏瓨鍌ㄦ墍鏈夌殑璐熷煎彉閲忚祴鍒濆
PID.RK_Uint16=180; //璁懼畾鍊間負180
PID.CK_Uint16=PIDinput; //杈撳叆鍊
if( PID.RK_Uint16 > PID.CK_Uint16 ) //濡傛灉璁懼畾鍊煎ぇ浜庡疄闄呭礆紝灝辨槸褰撳墠鐨勫兼瘮璁懼畾鍊煎皬
{
if( PID.RK_Uint16 - PID.CK_Uint16 >10 ) //璁$畻鍋忓樊鏄鍚﹀ぇ浜 piancha=10 ( 榪欓噷鐨10鐢 piancha 鏉ヨ懼畾澶у皬錛屾牴鎹瀹為檯鎯呭喌璁懼畾)
//if( PID.RK_Uint16 - PID.CK_Uint16 >piancha )
{ //濡傛灉鍋忓樊澶т簬 piancha=10 涓嶅湪璁懼畾鐨凱ID璋冩帶鑼冨洿涔嬪唴灝卞叏閫熷姞鐑
out = 100; //鍋忓樊澶т簬piancha=10涓轟笂闄愬箙鍊艱緭鍑(鍏ㄩ熷姞鐑)
// PID.Uk_Uint16 = full_speed; //鍏ㄩ熸椂鐨勫姞鐑鍊礆紝鏇村叿瀹為檯鎯呭喌鍙鑷鐢辮懼畾 榪欓噷full_speed=100錛
}
else //濡傛灉鍋忓樊灝忎簬 piancha=10 鍐嶈皟鑺傜殑鑼冨洿鍐呭氨璁$畻鍌ㄥ瓨璧鋒潵
{ //涓嬮潰灝辨槸PID綆楁硶
Temp[0] = PID.RK_Uint16 - PID.CK_Uint16; // 璁$畻鍑哄綋鍓嶅嚲宸鍊糆(k)
PID.EkFlag_Uint8[1]=0; //E(k)涓烘f暟 鐨勬爣蹇椾綅 0涓烘o紝1涓鴻礋
//鏁板肩Щ浣
PID.Ek_Uint32[2] = PID.Ek_Uint32[1]; //瀛樺偍E(k-2)
PID.Ek_Uint32[1] = PID.Ek_Uint32[0]; //鍌ㄥ瓨E(k-1)
PID.Ek_Uint32[0] = Temp[0]; //瀛樺偍E(k)
/****************************************************************************************/
if( PID.Ek_Uint32[0] >PID.Ek_Uint32[1] ) //E(k)>E(k-1) 涓烘f暟
{
Temp[0]=PID.Ek_Uint32[0] - PID.Ek_Uint32[1]; //E(k)-E(k-1) 淇濆瓨
PID.EkFlag_Uint8[0]=0; // 璁懼畾鏍囧織浣 0涓烘o紝1涓鴻礋
}
else //E(k)<E(k-1)
{
Temp[0]=PID.Ek_Uint32[1] - PID.Ek_Uint32[0]; //E(k)-E(k-1)涓鴻礋鏁
PID.EkFlag_Uint8[0]=1;
}
/*****************************************************************************************/
Temp[2]=PID.Ek_Uint32[1]*2 ; // 2E(k-1)
if( (PID.Ek_Uint32[0]+ PID.Ek_Uint32[2])>Temp[2] ) //E(k-2)+E(k)>2E(k-1)
{
Temp[2]=(PID.Ek_Uint32[0]+ PID.Ek_Uint32[2])-Temp[2]; //E(k-2)+E(k)-2E(k-1)涓烘f暟
PID.EkFlag_Uint8[2]=0;
}
else //E(k-2)+E(k)-2E(k-1)涓鴻礋鏁
{
Temp[2]=Temp[2]-(PID.Ek_Uint32[0]+ PID.Ek_Uint32[2]); //2E(k-1)-(E(k-2)+E(k))
PID.EkFlag_Uint8[2]=1;
}
/**********************************************************************************************/
Temp[0] = (uint32)PID.KP_Uint8 * Temp[0]; // KP*[E(k)-E(k-1)]
Temp[1] = (uint32)PID.KI_Uint8 * PID.Ek_Uint32[0]; // KI*E(k)
Temp[2] = (uint32)PID.KD_Uint8 * Temp[2]; // KD*[E(k-2)+E(k)-2E(k-1)]
/************************浠ヤ笅閮ㄥ垎浠g爜鏄璁叉墍鏈夌殑姝f暟欏瑰彔鍔狅紝璐熸暟欏瑰彔鍔**************************/
/**************************************KP*[E(k)-E(k-1)]********************************************/
if(PID.EkFlag_Uint8[0]==0)
PostSum += Temp[0]; //姝f暟鍜
else
NegSum += Temp[0]; //璐熸暟鍜
/*************************************** KI*E(k)*************************************************/
if(PID.EkFlag_Uint8[1]==0)
PostSum += Temp[1]; //姝f暟鍜
else
; //絀烘搷浣滐紝E(K)>0
/************************************KD*[E(k-2)+E(k)-2E(k-1)]*************************************/
if(PID.EkFlag_Uint8[2]==0)
PostSum += Temp[2]; //姝f暟鍜
else
NegSum += Temp[2]; //璐熸暟鍜
/**********************************************U(K)*************************************************/
//PostSum += (uint32)PID.Uk_Uint16;
if(PostSum > NegSum ) // 鏄鍚︽帶鍒墮噺涓烘f暟
{
out= PostSum - NegSum;
PID.Vaule_Flag=0; //PID璋冭妭鍊兼槸姝e
}
else //鎺у埗閲忚緭鍑轟負璐熸暟
{
out=NegSum-PostSum;
PID.Vaule_Flag=1; //PID璋冭妭鍊兼槸璐熷
}
}
//return out;
}
else //濡傛灉璁懼畾鍊煎皬浜庡疄闄呭礆紝灝辨槸褰撳墠鐨勫煎ぇ浜庤懼畾鍊,灝變笉榪涜孭ID璁$畻鐩存帴杈撳嚭 0
{
out = 0;
}
return out;
}
4. 誰能幫我用C語言編寫「積分分離式PID控制器」及「微分先行式PID控制器」。
這是C語言的悄世察程序用的的積分分離,增量式演算法你可以看看~在我用的片子是89C52
/*********************************************************/
/* 名稱啟茄: float PIDprocess1 */
/* 功能: PID adjust */
/* 說明: */
/* 調用: */
/* 輸入: float xdata *Yn, float xdata *Rn */
/* 返回返兆值: deltaPn */
/*********************************************************/
float PIDprocess1()
{
int data E_0;
float data deltaPn,deltaPi,deltaPp,deltaPd,PsumCopy;
E_0=SetTemperature1-CurrentTemperature1;
if(abs(E_0)>Emax)
{
deltaPp=(float)Kp*(E_0-E_11);
deltaPd=(float)Kd*(E_0-2*E_11+E_21);
// if(deltaPd>=dPdmax) deltaPd=0;
deltaPn=deltaPp+deltaPd;
}
else
{
if(abs(E_0)>E0)
{
deltaPi=(float)Ki*E_0*(Emax-abs(E_0))/(Emax-E0);
}
else
{ //小誤差時的處理
deltaPi=(float)Ki*E_0;
// if(fabs(deltaPi)<dPimin) deltaPi=0;
}
deltaPp=(float)Kp*(E_0-E_11);
deltaPd=(float)Kd*(E_0-2*E_11+E_21);
// if(deltaPd>=dPdmax) deltaPd=0;
deltaPn=deltaPp+deltaPi+deltaPd;
}
/* if(fabs(deltaPn)>dPmax)
{
if(deltaPn>0) deltaPn=dPmax;
else deltaPn=-dPmax;
} */
Psum1+=deltaPn;
PsumCopy=Psum1;
if(PsumCopy>Pmax) PsumCopy=Pmax;
if(PsumCopy<Pmin) PsumCopy=Pmin;
E_21=E_11;
E_11=E_0;
return(PsumCopy);
}
/*********************************************************/
/* 名稱: float PIDprocess2 */
/* 功能: PID adjust */
/* 說明: */
/* 調用: */
/* 輸入: float xdata Yn, float xdata Rn */
/* 返回值: Psum2 */
/*********************************************************/
float PIDprocess2()
{
int data E_0;
float data deltaPn,deltaPi,PsumCopy;
E_0=SetTemperature2-CurrentTemperature2;
if(abs(E_0)>Emax)
{
deltaPn=(float)Kp*(E_0-E_12)+(float)Kd*(E_0-2*E_12+E_22);
}
else
{
if(abs(E_0)>E0)
{
deltaPi=(float)Ki*E_0*(Emax-abs(E_0))/(Emax-E0);
}
else
{ //小誤差時的處理
deltaPi=(float)Ki*E_0;
}
deltaPn=(float)Kp*(E_0-E_12)+deltaPi+(float)Kd*(E_0-2*E_12+E_22);
}
/* if(fabs(deltaPn)>dPmax)
{
if(deltaPn>0) deltaPn=dPmax;
else deltaPn=-dPmax;
}*/
Psum2+=deltaPn;
PsumCopy=Psum2;
if(PsumCopy>Pmax) PsumCopy=Pmax;
if(PsumCopy<Pmin) PsumCopy=Pmin;
E_22=E_12;
E_12=E_0;
return(PsumCopy);
}
5. 什麼是pid演算法,難學嗎,用C語言,plc怎麼實現
一、什麼是PID:
PID即:Proportional(比例)、Integral(積分)、Differential(微分)的縮寫。顧名思義,PID控制演算法是結合比例、積分和微分三種環節於一體的控制演算法,它是連續系統中技術最為成熟、應用最為廣泛的一種控制演算法,該控制演算法出現於20世紀30至40年代,適用於對被控對象模型了解不清楚的場合。 ---網路
二、PID是否難學:
在工業應用中PID及其衍生演算法是應用最廣泛的演算法之一,是當之無愧的萬能演算法,如果能夠熟練掌握PID演算法的設計與實現過程,對於一般的研發人員來講,應該是足夠應對一般研發問題了,而難能可貴的是,在我所接觸的控制演算法當中,PID控制演算法又是最簡單,最能體現反饋思想的控制演算法,可謂經典中的經典。經典的未必是復雜的,經典的東西常常是簡單的,而且是最簡單的,想想牛頓的力學三大定律吧,想想愛因斯坦的質能方程吧,何等的簡單!簡單的不是原始的,簡單的也不是落後的,簡單到了美的程度。 ---【1】
三、PID演算法的C語言源碼:
PID 控制演算法可以分為位置式 PID和增量式 PID控制演算法
詳細見參考【1】【2】
參考:
【1】PID演算法
【2】簡易PID演算法的快速掃盲(超詳細+過程推導+C語言程序)