欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136
標題:
好用的模糊PID溫度控制算法 C語言源代碼
[打印本頁]
作者:
君墨竹
時間:
2023-4-7 10:16
標題:
好用的模糊PID溫度控制算法 C語言源代碼
#include <string.h>
#include <stdio.h>
#include <math.h>
#include "pid_fuzzy.h"
//注1:自適應模糊pid最重要的就是論域的選擇,要和你應該控制的對象相切合
//注2:以下各閥值、限幅值、輸出值均需要根據具體的使用情況進行更改
//注3:因為我的控制對象慣性比較大,所以以下各部分取值較小
//論域e:[-5,5] ec:[-0.5,0.5]
//誤差的閥值,小于這個數值的時候,不做PID調整,避免誤差較小時頻繁調節引起震蕩
#define Emin 0.0
#define Emid 0.08
#define Emax 0.6
//調整值限幅,防止積分飽和
#define Umax 5
#define Umin -5
//輸出值限幅
#define Pmax 7200
#define Pmin 0
#define NB 0
#define NM 1
#define NS 2
#define ZO 3
#define PS 4
#define PM 5
#define PB 6
int kp[7][7]= { {PB,PB,PM,PM,PS,ZO,ZO},
{PB,PB,PM,PS,PS,ZO,ZO},
{PM,PM,PM,PS,ZO,NS,NS},
{PM,PM,PS,ZO,NS,NM,NM},
{PS,PS,ZO,NS,NS,NM,NM},
{PS,ZO,NS,NM,NM,NM,NB},
{ZO,ZO,NM,NM,NM,NB,NB}
};
int kd[7][7]= { {PS,NS,NB,NB,NB,NM,PS},
{PS,NS,NB,NM,NM,NS,ZO},
{ZO,NS,NM,NM,NS,NS,ZO},
{ZO,NS,NS,NS,NS,NS,ZO},
{ZO,ZO,ZO,ZO,ZO,ZO,ZO},
{PB,NS,PS,PS,PS,PS,PB},
{PB,PM,PM,PM,PS,PS,PB}
};
int ki[7][7]= { {NB,NB,NM,NM,NS,ZO,ZO},
{NB,NB,NM,NS,NS,ZO,ZO},
{NB,NM,NS,NS,ZO,PS,PS},
{NM,NM,NS,ZO,PS,PM,PM},
{NM,NS,ZO,PS,PS,PM,PB},
{ZO,ZO,PS,PS,PM,PB,PB},
{ZO,ZO,PS,PM,PM,PB,PB}
};
/**************求隸屬度(三角形)***************/
float FTri(float x,float a,float b,float c)//FuzzyTriangle
{
if(x<=a)
return 0;
else if((a<x)&&(x<=b))
return (x-a)/(b-a);
else if((b<x)&&(x<=c))
return (c-x)/(c-b);
else if(x>c)
return 0;
else
return 0;
}
/*****************求隸屬度(梯形左)*******************/
float FTraL(float x,float a,float b)//FuzzyTrapezoidLeft
{
if(x<=a)
return 1;
else if((a<x)&&(x<=b))
return (b-x)/(b-a);
else if(x>b)
return 0;
else
return 0;
}
/*****************求隸屬度(梯形右)*******************/
float FTraR(float x,float a,float b)//FuzzyTrapezoidRight
{
if(x<=a)
return 0;
if((a<x)&&(x<b))
return (x-a)/(b-a);
if(x>=b)
return 1;
else
return 1;
}
/****************三角形反模糊化處理**********************/
float uFTri(float x,float a,float b,float c)
{
float y,z;
z=(b-a)*x+a;
y=c-(c-b)*x;
return (y+z)/2;
}
/*******************梯形(左)反模糊化***********************/
float uFTraL(float x,float a,float b)
{
return b-(b-a)*x;
}
/*******************梯形(右)反模糊化***********************/
float uFTraR(float x,float a,float b)
{
return (b-a)*x +a;
}
/**************************求交集****************************/
float fand(float a,float b)
{
return (a<b)?a:b;
}
/**************************求并集****************************/
float forr(float a,float b)
{
return (a<b)?b:a;
}
float ec;
/*========== PID計算部分 ======================*/
int PID_realize(PID *structpid,uint16_t s,uint16_t in)
{
float pwm_var;//pwm調整量
float iError;//當前誤差
float set,input;
//計算隸屬度表
float es[7],ecs[7],e;
float form[7][7];
int i=0,j=0;
int MaxX=0,MaxY=0;
//記錄隸屬度最大項及相應推理表的p、i、d值
float lsd;
int temp_p,temp_d,temp_i;
float detkp,detkd,detki;//推理后的結果
//輸入格式的轉化及偏差計算
set=(float)s/100.0;
input=(float)in/100.0;
iError = set - input; // 偏差
e=iError;
ec=iError-structpid->LastError;
//當溫度差的絕對值小于Emax時,對pid的參數進行調整
if(fabs(iError)<=Emax)
{
//計算iError在es與ecs中各項的隸屬度
es[NB]=FTraL(e*5,-3,-1); //e
es[NM]=FTri(e*5,-3,-2,0);
es[NS]=FTri(e*5,-3,-1,1);
es[ZO]=FTri(e*5,-2,0,2);
es[PS]=FTri(e*5,-1,1,3);
es[PM]=FTri(e*5,0,2,3);
es[PB]=FTraR(e*5,1,3);
ecs[NB]=FTraL(ec*30,-3,-1);//ec
ecs[NM]=FTri(ec*30,-3,-2,0);
ecs[NS]=FTri(ec*30,-3,-1,1);
ecs[ZO]=FTri(ec*30,-2,0,2);
ecs[PS]=FTri(ec*30,-1,1,3);
ecs[PM]=FTri(ec*30,0,2,3);
ecs[PB]=FTraR(ec*30,1,3);
//計算隸屬度表,確定e和ec相關聯后表格各項隸屬度的值
for(i=0; i<7; i++)
{
for(j=0; j<7; j++)
{
form[i][j]=fand(es[i],ecs[j]);
}
}
//取出具有最大隸屬度的那一項
for(i=0; i<7; i++)
{
for(j=0; j<7; j++)
{
if(form[MaxX][MaxY]<form[i][j])
{
MaxX=i;
MaxY=j;
}
}
}
//進行模糊推理,并去模糊
lsd=form[MaxX][MaxY];
temp_p=kp[MaxX][MaxY];
temp_d=kd[MaxX][MaxY];
temp_i=ki[MaxX][MaxY];
if(temp_p==NB)
detkp=uFTraL(lsd,-0.3,-0.1);
else if(temp_p==NM)
detkp=uFTri(lsd,-0.3,-0.2,0);
else if(temp_p==NS)
detkp=uFTri(lsd,-0.3,-0.1,0.1);
else if(temp_p==ZO)
detkp=uFTri(lsd,-0.2,0,0.2);
else if(temp_p==PS)
detkp=uFTri(lsd,-0.1,0.1,0.3);
else if(temp_p==PM)
detkp=uFTri(lsd,0,0.2,0.3);
else if(temp_p==PB)
detkp=uFTraR(lsd,0.1,0.3);
if(temp_d==NB)
detkd=uFTraL(lsd,-3,-1);
else if(temp_d==NM)
detkd=uFTri(lsd,-3,-2,0);
else if(temp_d==NS)
detkd=uFTri(lsd,-3,1,1);
else if(temp_d==ZO)
detkd=uFTri(lsd,-2,0,2);
else if(temp_d==PS)
detkd=uFTri(lsd,-1,1,3);
else if(temp_d==PM)
detkd=uFTri(lsd,0,2,3);
else if(temp_d==PB)
detkd=uFTraR(lsd,1,3);
if(temp_i==NB)
detki=uFTraL(lsd,-0.06,-0.02);
else if(temp_i==NM)
detki=uFTri(lsd,-0.06,-0.04,0);
else if(temp_i==NS)
detki=uFTri(lsd,-0.06,-0.02,0.02);
else if(temp_i==ZO)
detki=uFTri(lsd,-0.04,0,0.04);
else if(temp_i==PS)
detki=uFTri(lsd,-0.02,0.02,0.06);
else if(temp_i==PM)
detki=uFTri(lsd,0,0.04,0.06);
else if (temp_i==PB)
detki=uFTraR(lsd,0.02,0.06);
//pid三項系數的修改
structpid->Kp+=detkp;
structpid->Ki+=detki;
//structpid->Kd+=detkd;
structpid->Kd=0;//取消微分作用
//對Kp,Ki進行限幅
if(structpid->Kp<0)
{
structpid->Kp=0;
}
if(structpid->Ki<0)
{
structpid->Ki=0;
}
//計算新的K1,K2,K3
structpid->K1=structpid->Kp+structpid->Ki+structpid->Kd;
structpid->K2=-(structpid->Kp+2*structpid->Kd);
structpid->K3=structpid->Kd;
}
if(iError>Emax)
{
structpid->pwm_out=7200;
pwm_var = 0;
structpid->flag=1;//設定標志位,如果誤差超過了門限值,則認為當控制量第一次到達給定值時,應該采取下面的 抑制超調 的措施
}
else if(iError<-Emax)
{
structpid->pwm_out=0;
pwm_var = 0;
}
else if( fabs(iError) < Emin ) //誤差的閥值(死區控制??)
{
pwm_var = 0;
}
else
{
if( iError<Emid && structpid->flag==1 )//第一次超過(設定值-Emid(-0.08)攝氏度),是輸出為零,防止超調,也可以輸出其他值,不至于太小而引起震蕩
{
structpid->pwm_out=0;
structpid->flag=0;
}
else if( -iError>Emid)//超過(設定+Emid(+0.08)攝氏度)
{
pwm_var=-1;
}
else
{
//增量計算
pwm_var=(structpid->K1 * iError //e[k]
+ structpid->K2 * structpid->LastError //e[k-1]
+ structpid->K3 * structpid->PrevError); //e[k-2]
}
if(pwm_var >= Umax)pwm_var = Umax; //調整值限幅,防止積分飽和
if(pwm_var <= Umin)pwm_var = Umin; //調整值限幅,防止積分飽和
}
structpid->PrevError=structpid->LastError;
structpid->LastError=iError;
structpid->pwm_out += 360*pwm_var; //調整PWM輸出
if(structpid->pwm_out > Pmax)structpid->pwm_out = Pmax; //輸出值限幅
if(structpid->pwm_out < Pmin)structpid->pwm_out = Pmin; //輸出值限幅
return (int)(structpid->pwm_out); // 微分項
}
void PID_Set(PID *structpid,float Kp,float Ki,float Kd,float T)
{
(*structpid).Kp=Kp;//Kp*(1+(Td/T));
(*structpid).Ki=Ki;
(*structpid).Kd=Kd;
(*structpid).T=T;
structpid->K1=structpid->Kp*(1+structpid->Ki+structpid->Kd);
structpid->K2=-(structpid->Kp+2*structpid->Kp*structpid->Kd);
structpid->K3=structpid->Kp*structpid->Kd;
}
void PID_Init(PID *structpid)
{
PID_Set(structpid,8.3,1.2,0,1);
structpid->flag=0;
structpid->pwm_out=0;
}
復制代碼
pid_fuzzy.h
#ifndef PID_H_
#define PID_H_
#include "stm32f10x.h"
typedef struct PID
{
float Kp; // 增量式積分系數
float Ki;
float Kd;
float T;
float K1; // 增量式積分系數
float K2;
float K3;
float LastError; //Error[-1]
float PrevError; // Error[-2]
float pwm_out;
uint16_t flag;//溫度狀態標志位
}PID;
//void PID_init(PID *structpid);
void PID_Set(PID *structpid,float Kp,float Ki,float Kd,float T);
int PID_realize(PID *structpid,uint16_t s,uint16_t in);
void PID_Init(PID *structpid);
#endif /* PID_H_ */
復制代碼
作者:
lovejk8
時間:
2023-4-11 09:56
代碼簡潔,學習一下看看
歡迎光臨 (http://www.raoushi.com/bbs/)
Powered by Discuz! X3.1