之前寫過一篇關於使用樣本數據獲取模糊規則的博文,原文 的地址是:http://blog.csdn.net/shuoyueqishilove/article/details/71908410,大家可以參考,本篇文章適合對模糊控制算法有一定了解的人閱讀,給大家提供一種如何用C++實現模糊控制的方法,僅供參考。
實現模糊控制器需要以下步驟:
- 確定模糊控制器的輸入和輸出量
- 設計模糊控制器的控制規則
- 確立模糊化和非模糊化的方法
- 選擇模糊控制器的輸入變量和輸出變量的論域並確定模糊控制器的參數(如量化因子,比例因子等)
- 編制模糊控制算法的應用程序
合理選擇模糊控制算法的採樣時間
本模糊控制器採用雙輸入單輸出的形式,輸入變量爲誤差e和誤差的變化率de,輸出爲控制量u;e,de,u的量化論域範圍爲[-3,-2,-1,0,1,2,3],劃分的模糊子集爲:[NB,NM,NS,ZO,PS,PM,PB].基本論域的範圍選取需要根據實際情況來確定上限值emax,demax,umax.
量化因子:Ke=3/emax, Kde=3/demax,
輸出縮放因子:Ku=umax/3
爲了減少計算量,e,de,u的隸屬度函數都選用三角形隸屬度函數。如下圖所示:
模糊控制最重要的是要確定模糊控制規則,它可以通過專家經驗獲得,也可以通過採樣數據獲得,這裏使用的模糊控制規則表如下;
在微處理器中實現模糊控制的一般採用離線查表的方法。首先模糊化輸入到控制器中的e和de,計算他們的在每個模糊子集中的隸屬度值,然後找出激活的模糊子集,存儲起來,最後使用加權平均的方法計算輸出值。具體的公式如下:
Zi爲u的模糊隸屬度函數的尖點所對應的橫座標值。
下面講講怎麼用C++實現模糊控制器。
首先需要建立一個Fuzzy_controller的類:
class Fuzzy_controller
{
public:
const static int N=7;//定義量化論域模糊子集的個數
private:
float target;//系統的控制目標
float actual;//採樣獲得的實際值
float e; //誤差
float e_pre; //上一次的誤差
float de; //誤差的變化率
float emax; //誤差基本論域上限
float demax; //誤差辯化率基本論域的上限
float umax; //輸出的上限
float Ke; //Ke=n/emax,量化論域爲[-3,-2,-1,0,1,2,3]
float Kde; //Ke=n/demax,量化論域爲[-3,-2,-1,0,1,2,3]
float Ku; //Ke=umax/n,量化論域爲[-3,-2,-1,0,1,2,3]
int rule[N][N];//模糊規則表
string mf_t_e; //e的隸屬度函數類型
string mf_t_de; //de的隸屬度函數類型
string mf_t_u; //u的隸屬度函數類型
float *e_mf_paras; //誤差的隸屬度函數的參數
float *de_mf_paras;//誤差的偏差隸屬度函數的參數
float *u_mf_paras; //輸出的隸屬度函數的參數
public:
Fuzzy_controller(float e_max,float de_max,float u_max);
~Fuzzy_controller();
float trimf(float x,float a,float b,float c); //三角隸屬度函數
float gaussmf(float x,float ave,float sigma); //正態隸屬度函數
float trapmf(float x,float a,float b,float c,float d); //梯形隸屬度函數
//設置模糊隸屬度函數的參數
void setMf(const string & mf_type_e,float *e_mf,const string & mf_type_de,float *de_mf,const string & mf_type_u,float *u_mf);
void setRule(int rulelist[N][N]); //設置模糊規則
float realize(float t,float a); //實現模糊控制
void showInfo(); //顯示該模糊控制器的信息
void showMf(const string & type,float *mf_paras); //顯示隸屬度函數的信息
};
然後給出類方法的定義:
Fuzzy_controller::Fuzzy_controller(float e_max,float de_max,float u_max):
target(0),actual(0),emax(e_max),demax(de_max),umax(u_max),e_mf_paras(NULL),de_mf_paras(NULL),u_mf_paras(NULL)
{
e=target-actual;
e_pre=0;
de=e-e_pre;
Ke=(N/2)/emax;
Kde=(N/2)/demax;
Ku=umax/(N/2);
mf_t_e="trimf";
mf_t_de="trimf";
mf_t_u="trimf";
}
Fuzzy_controller::~Fuzzy_controller()
{
delete [] e_mf_paras;
delete [] de_mf_paras;
delete [] u_mf_paras;
}
//三角隸屬度函數
float Fuzzy_controller::trimf(float x,float a,float b,float c)
{
float u;
if(x>=a&&x<=b)
u=(x-a)/(b-a);
else if(x>b&&x<=c)
u=(c-x)/(c-b);
else
u=0.0;
return u;
}
//正態隸屬度函數
float Fuzzy_controller::gaussmf(float x,float ave,float sigma)
{
float u;
if(sigma<0)
{
cout<<"In gaussmf, sigma must larger than 0"<<endl;
}
u=exp(-pow(((x-ave)/sigma),2));
return u;
}
//梯形隸屬度函數
float Fuzzy_controller::trapmf(float x,float a,float b,float c,float d)
{
float u;
if(x>=a&&x<b)
u=(x-a)/(b-a);
else if(x>=b&&x<c)
u=1;
else if(x>=c&&x<=d)
u=(d-x)/(d-c);
else
u=0;
return u;
}
//設置模糊規則
void Fuzzy_controller::setRule(int rulelist[N][N])
{
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
rule[i][j]=rulelist[i][j];
}
//設置模糊隸屬度函數的類型和參數
void Fuzzy_controller::setMf(const string & mf_type_e,float *e_mf,const string & mf_type_de,float *de_mf,const string & mf_type_u,float *u_mf)
{
if(mf_type_e=="trimf"||mf_type_e=="gaussmf"||mf_type_e=="trapmf")
mf_t_e=mf_type_e;
else
cout<<"Type of membership function must be \"trimf\" or \"gaussmf\" or \"trapmf\""<<endl;
if(mf_type_de=="trimf"||mf_type_de=="gaussmf"||mf_type_de=="trapmf")
mf_t_de=mf_type_de;
else
cout<<"Type of membership function must be \"trimf\" or \"gaussmf\" or \"trapmf\""<<endl;
if(mf_type_u=="trimf"||mf_type_u=="gaussmf"||mf_type_u=="trapmf")
mf_t_u=mf_type_u;
else
cout<<"Type of membership function must be \"trimf\" or \"gaussmf\" or \"trapmf\""<<endl;
e_mf_paras=new float [N*3];
de_mf_paras=new float [N*3];
u_mf_paras=new float [N*3];
for(int i=0;i<N*3;i++)
e_mf_paras[i]=e_mf[i];
for(int i=0;i<N*3;i++)
de_mf_paras[i]=de_mf[i];
for(int i=0;i<N*3;i++)
u_mf_paras[i]=u_mf[i];
}
//實現模糊控制
float Fuzzy_controller::realize(float t,float a)
{
float u_e[N],u_de[N],u_u[N];
int u_e_index[3],u_de_index[3];//假設一個輸入最多激活3個模糊子集
float u;
int M;
target=t;
actual=a;
e=target-actual;
de=e-e_pre;
e=Ke*e;
de=Kde*de;
if(mf_t_e=="trimf")
M=3; //三角函數有三個參數
else if(mf_t_e=="gaussmf")
M=2; //正態函數有兩個參數
else if(mf_t_e=="trapmf")
M=4; //梯形函數有四個參數
int j=0;
for(int i=0;i<N;i++)
{
u_e[i]=trimf(e,e_mf_paras[i*M],e_mf_paras[i*M+1],e_mf_paras[i*M+2]);//e模糊化,計算它的隸屬度
if(u_e[i]!=0)
u_e_index[j++]=i; //存儲被激活的模糊子集的下標,可以減小計算量
}
for(;j<3;j++)u_e_index[j]=0;
if(mf_t_e=="trimf")
M=3; //三角函數有三個參數
else if(mf_t_e=="gaussmf")
M=2; //正態函數有兩個參數
else if(mf_t_e=="trapmf")
M=4; //梯形函數有四個參數
j=0;
for(int i=0;i<N;i++)
{
u_de[i]=trimf(de,de_mf_paras[i*M],de_mf_paras[i*M+1],de_mf_paras[i*M+2]);//de模糊化,計算它的隸屬度
if(u_de[i]!=0)
u_de_index[j++]=i; //存儲被激活的模糊子集的下標,可以減小計算量
}
for(;j<3;j++)u_de_index[j]=0;
float den=0,num=0;
for(int m=0;m<3;m++)
for(int n=0;n<3;n++)
{
num+=u_e[u_e_index[m]]*u_de[u_de_index[n]]*rule[u_e_index[m]][u_de_index[n]];
den+=u_e[u_e_index[m]]*u_de[u_de_index[n]];
}
u=num/den;
u=Ku*u;
if(u>=umax) u=umax;
else if(u<=-umax) u=-umax;
e_pre=e;
return u;
}
void Fuzzy_controller::showMf(const string & type,float *mf_paras)
{
int tab;
if(type=="trimf")
tab=2;
else if(type=="gaussmf")
tab==1;
else if(type=="trapmf")
tab=3;
cout<<"函數類型:"<<mf_t_e<<endl;
cout<<"函數參數列表:"<<endl;
float *p=mf_paras;
for(int i=0;i<N*(tab+1);i++)
{
cout.width(3);
cout<<p[i]<<" ";
if(i%3==tab)
cout<<endl;
}
}
void Fuzzy_controller::showInfo()
{
cout<<"Info of this fuzzy controller is as following:"<<endl;
cout<<"基本論域e:["<<-emax<<","<<emax<<"]"<<endl;
cout<<"基本論域de:["<<-demax<<","<<demax<<"]"<<endl;
cout<<"基本論域u:["<<-umax<<","<<umax<<"]"<<endl;
cout<<"誤差e的模糊隸屬度函數參數:"<<endl;
showMf(mf_t_e,e_mf_paras);
cout<<"誤差變化率de的模糊隸屬度函數參數:"<<endl;
showMf(mf_t_de,de_mf_paras);
cout<<"輸出u的模糊隸屬度函數參數:"<<endl;
showMf(mf_t_u,u_mf_paras);
cout<<"模糊規則表:"<<endl;
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
cout.width(3);
cout<<rule[i][j]<<" ";
}
cout<<endl;
}
cout<<endl;
cout<<"誤差的量化比例因子Ke="<<Ke<<endl;
cout<<"誤差變化率的量化比例因子Kde="<<Kde<<endl;
cout<<"輸出的量化比例因子Ku="<<Ku<<endl;
cout<<"設定目標target="<<target<<endl;
cout<<"誤差e="<<e<<endl;
cout<<endl;
}
此模糊控制的類,允許用戶使用不同的模糊隸屬度函數,如三角型,正態分佈型和梯形。但是需要相應的給出適當的函數參數。用戶可以修改模糊控制規則表,以提高模糊控制器的性能。但是用戶需要首先明確誤差e,誤差變化率de和輸出u的最大範圍,因爲這裏需要依據他們來確定量化因子和縮放因子,如果給出的範圍不合適,則很難達到理想的控制效果。
下面是一個測試的例子,僅供參考:
#include<iostream>
#include"fuzzy_controller.h"
#define NB -3
#define NM -2
#define NS -1
#define ZO 0
#define PS 1
#define PM 2
#define PB 3
int main()
{
float target=600;
float actual=0;
float u=0;
int ruleMatrix[7][7]={{NB,NB,NM,NM,NS,ZO,ZO},
{NB,NB,NM,NS,NS,ZO,PS},
{NM,NM,NM,NS,ZO,PS,PS},
{NM,NM,NS,ZO,PS,PM,PM},
{NS,NS,ZO,PS,PS,PM,PM},
{NS,ZO,PS,PM,PM,PM,PB},
{ZO,ZO,PM,PM,PM,PB,PB}};//模糊規則表
float e_mf_paras[21]={-3,-3,-2,-3,-2,-1,-2,-1,0,-1,0,1,0,1,2,1,2,3,2,3,3};//誤差e的隸屬度函數參數,這裏隸屬度函數爲三角型,所以3個數據爲一組
float de_mf_paras[21]={-3,-3,-2,-3,-2,-1,-2,-1,0,-1,0,1,0,1,2,1,2,3,2,3,3};//誤差變化率de的模糊隸屬度函數參數
float u_mf_paras[21]={-3,-3,-2,-3,-2,-1,-2,-1,0,-1,0,1,0,1,2,1,2,3,2,3,3};//輸出量u的隸屬度函數參數
Fuzzy_controller fuzzy(1000,650,500);//控制器初始化,設定誤差,誤差變化率,輸出的最大值
fuzzy.setMf("trimf",e_mf_paras,"trimf",de_mf_paras,"trimf",u_mf_paras);//設定模糊隸屬度函數
fuzzy.setRule(ruleMatrix);//設定模糊規則
cout<<"num target actual"<<endl;
for(int i=0;i<100;i++)
{
u=fuzzy.realize(target,actual);
actual+=u;
cout<<i<<" "<<target<<" "<<actual<<endl;
}
fuzzy.showInfo();
system("pause");
return 0;
}
運行結果:
這裏設定的目標值爲600,可見,控制器在運行到9次時就穩定在了600,控制效果比較好。
代碼已上傳至我的CSDN,有興趣的可以下載看看:
https://download.csdn.net/download/shuoyueqishilove/10433961