1. 程式人生 > >模糊控制演算法-轉載

模糊控制演算法-轉載

之前寫過一篇關於使用樣本資料獲取模糊規則的博文,原文 的地址是: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);      //顯示隸屬度函式的資訊
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
然後給出類方法的定義:

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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
此模糊控制的類,允許使用者使用不同的模糊隸屬度函式,如三角型,正態分佈型和梯形。但是需要相應的給出適當的函式引數。使用者可以修改模糊控制規則表,以提高模糊控制器的效能。但是使用者需要首先明確誤差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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
執行結果: 
 
這裡設定的目標值為600,可見,控制器在執行到9次時就穩定在了600,控制效果比較好。 
程式碼已上傳至我的CSDN,有興趣的可以下載看看: 
https://download.csdn.net/download/shuoyueqishilove/10433961
--------------------- 
作者:shuoyueqishilove 
來源:CSDN 
原文:https://blog.csdn.net/shuoyueqishilove/article/details/74029745 
版權宣告:本文為博主原創文章,轉載請附上博文連結!