基于8位单片机的模糊控制算法程序,实现2输入1输出模糊控制,输入为偏差e,偏差变化率ec,输出为阀门开度,此程序以中央空调制冷控制为例。
以下为模糊算法源程序:
/********************************************************************************************:
编写说明:模糊控制,双输入,单输出,偏差e,偏差变化率ec
编写时间:2015.8.27
作 者:QQ351150613
程序问题:调试结束,与matlab7.0仿真对比,精度在0.05之间
*********************************************************************************************/
#include //头文件
//-------------------------------------宏定义------------------------------------------------
#define OUTPUT_TOT 7
#define MU_MAX 0xFF
#define RULE_TOT 147
#define IO_NUM 0x07
#define LABEL_NUM 0x70
#define DEFAULT_VALUE 0x0
//---------------------------------------变量定义--------------------------------------------
float fuzzy_in[2]={0.0,0.0}, //偏差e(-10.0,10.0),偏差ec(-4.0,4.0)
fuzzy_r; //实际输出增量-1.0,1.0
unsigned char input[2]; //偏差e,ec量化为0-255的值
unsigned char bdata clause_val; // 保持当前规则
unsigned char outputs[OUTPUT_TOT],fuzzy_out;
sbit operator = clause_val^3; // 表示所使用的模糊操作是AND=0;还是0R=1
sbit clause_type = clause_val^7; // 表示分支是条件分支=0;还是结果分支=1
unsigned char code output_memf[OUTPUT_TOT]={ 9,41,84,127,169,212,245};
// 定义E输入常量
#define E_NB 0x00
#define E_NM 0x10
#define E_NS 0x20
#define E_Z 0x30
#define E_PS 0x40
#define E_PM 0x50
#define E_PB 0x60
// 定义E输入常量
#define EC_NB 0x01
#define EC_NM 0x11
#define EC_NS 0x21
#define EC_Z 0x31
#define EC_PS 0x41
#define EC_PM 0x51
#define EC_PB 0x61
// 定义u输出常量
#define U_CB 0x80
#define U_CM 0x90
#define U_CS 0xA0
#define U_H 0xB0
#define U_OS 0xC0
#define U_OM 0xD0
#define U_OB 0xE0
//定义规则
unsigned char code rules[RULE_TOT]={
//规则表第一行
E_NB, EC_NB,U_OB, // 0 1 2
E_NB, EC_NM,U_OB,
E_NB, EC_NS,U_OM,
E_NB, EC_Z,U_OM,
E_NB, EC_PS,U_OS,
E_NB, EC_PM,U_OS,
E_NB, EC_PB,U_H,
//规则表第二行
E_NM, EC_NB,U_OB, //21 22 23
E_NM, EC_NM,U_OM,
E_NM, EC_NS,U_OM,
E_NM, EC_Z,U_OS,
E_NM, EC_PS,U_OS,
E_NM, EC_PM,U_H,
E_NM, EC_PB,U_CS,
//规则表第三行
E_NS, EC_NB,U_OM, // 42 43 44
E_NS, EC_NM,U_OM,
E_NS, EC_NS,U_OS,
E_NS, EC_Z,U_OS,
E_NS, EC_PS,U_H,
E_NS, EC_PM,U_CS,
E_NS, EC_PB,U_CS,
//规则表第四行 // 63 64 65
E_Z, EC_NB,U_OM,
E_Z, EC_NM,U_OS,
E_Z, EC_NS,U_OS,
E_Z, EC_Z,U_H,
E_Z, EC_PS,U_CS,
E_Z, EC_PM,U_CS,
E_Z, EC_PB,U_CM,
//规则表第五行 // 84 85 86
E_PS, EC_NB,U_OS,
E_PS, EC_NM,U_OS,
E_PS, EC_NS,U_H,
E_PS, EC_Z,U_CS,
E_PS, EC_PS,U_CS,
E_PS, EC_PM,U_CM,
E_PS, EC_PB,U_CM,
//规则表第六行 // 105 106 107
E_PM, EC_NB,U_OS,
E_PM, EC_NM,U_H,
E_PM, EC_NS,U_CS,
E_PM, EC_Z,U_CS,
E_PM, EC_PS,U_CM,
E_PM, EC_PM,U_CM,
E_PM, EC_PB,U_CB,
//规则表第七行 // 126 127 128
E_PB, EC_NB,U_H,
E_PB, EC_NM,U_CS,
E_PB, EC_NS,U_CS,
E_PB, EC_Z,U_CM,
E_PB, EC_PS,U_CM,
E_PB, EC_PM,U_CB,
E_PB, EC_PB,U_CB, // 144 145 146
};
unsigned char code input_memf[2][7][4]={ //功能函数点斜式数据
// E功能函数
{
{ 0x00, 0x00, 0x0E, 0x0B }, // NB 10# [0 0 14 38]
{ 0x12, 0x0D, 0x2F, 0x0D }, // NM 10# [18 38 47 66]
{ 0x3B, 0x0C, 0x59, 0x6D }, // NS 10# [59 80 89 109]
{ 0x64, 0x0B, 0x84, 0x0C }, // Z 10# [100 123 132 154]
{ 0x92, 0x0D, 0xAE, 0x0C }, // PS 10# [146 165 174 196]
{ 0xBB, 0x0C, 0xDB, 0x10 }, // PM 10# [187 208 216 232]
{ 0xE2, 0x11, 0xFF, 0x00 }, // PB 10# [226 241 255 255]
},
// EC功能函数
{
{ 0x00, 0x00, 0x0E, 0x0B }, // NB 10# [0 0 14 38]
{ 0x12, 0x0D, 0x2F, 0x0D }, // NM 10# [18 38 47 66]
{ 0x3B, 0x0C, 0x59, 0x6D }, // NS 10# [59 80 89 109]
{ 0x64, 0x0B, 0x84, 0x0C }, // Z 10# [100 123 132 154]
{ 0x92, 0x0D, 0xAE, 0x0C }, // PS 10# [146 165 174 196]
{ 0xBB, 0x0C, 0xDB, 0x10 }, // PM 10# [187 208 216 232]
{ 0xE2, 0x11, 0xFF, 0x00 }, // PB 10# [226 241 255 255]
}
};
//-----------------------------------子函数申明-------------------------------------------------------
void fuzzy_engine(void);
unsigned char compute_memval(unsigned char inp_num,unsigned char label);
void defuzzify(void);
float normalize(unsigned char in,unsigned char insh,unsigned char insl,float outsh,float outsl);
unsigned char normalize_r_c(float in,float insh,float insl,unsigned char outsh,unsigned char outsl);
void main (void)
{
while (1) //主循环
{
//主循环中添加其他需要一直工作的程序
input[0]=normalize_r_c(fuzzy_in[0],10.0,-10.0,0xff,0x00); //输入e归一化
input[1]=normalize_r_c(fuzzy_in[1],4.0,-4.0,0xff,0x00); //输入ec归一化
fuzzy_engine();
fuzzy_r=normalize(fuzzy_out,0xff,0x00,1.0,-1.0);
}
}
//---------------------归一化函数,将无符号整数,转化为0-1.0的实数---------------------------------
float normalize(unsigned char in,unsigned char insh,unsigned char insl,float outsh,float outsl)
{ // 输入值 输入上限 输入下限 输出上限 输出下限
return outsl+(in-insl)*(outsh-outsl)/(insh-insl);
}
//---------------------归一化函数,将实数,转化为0-0xff的整数--------------------------------------
unsigned char normalize_r_c(float in,float insh,float insl,unsigned char outsh,unsigned char outsl)
{ // 输入值 输入上限 输入下限 输出上限 输出下限
return outsl+(in-insl)*(outsh-outsl)/(insh-insl);
}
//-------------------------------------fuzzy_engine------------------------------------------------
void fuzzy_engine(void)
{
bit then; // 当正在分析结果时置位
unsigned char if_val, // 保存当前规则中条件分支中的值
clause, // 规则基中当前的分支
mu, // 保存当前分支中的值
inp_num, // 当前条件使用的输入
label; // 被条件使用的成员函数
then=0; // 设第一个分支是条件分支
if_val=MU_MAX; //初始化复位
for (clause=0; clause if_val)
{ // 取最大值
if_val=mu;
}
} else
{ // 如果是 AND操作
if (mu < if_val)
{ // 取最小值
if_val=mu;
}
}
} else
{ // 当前分支是结果
then=1; // 置位标志位
// 如果当前规则的mu比参考的值要大,保存这个值作为新的模糊输出
if(outputs[(clause_val & 0x70) / 16] < if_val)
{
outputs[(clause_val & 0x70) / 16]=if_val;
}
}
}
defuzzify(); // 用COG方法计算模糊输出
// 和反模糊输出
}
//--------------------compute_memval---------------------------------------------------
unsigned char compute_memval(unsigned char inp_num,unsigned char label)
{
int data temp;
if (input[inp_num] < input_memf[inp_num][label][0])
{
// 如果输入不在曲线下
// u值为0
return 0;
} else
{
if (input[inp_num] < input_memf[inp_num][label][2])
{
temp=input[inp_num]; // 用点斜式计算mu
temp-=input_memf[inp_num][label][0];
if (!input_memf[inp_num][label][1])
{
temp=MU_MAX;
} else
{
temp*=input_memf[inp_num][label][1];
}
if (temp < 0x100)
{ // 如果结果不超过1
return temp; // 返回计算结果
} else
{
return MU_MAX; // 确保mu值在范围内
}
} else
{ // 输入落在第二条斜线上
temp=input[inp_num]; // 用点斜式方法
// 计算 mu
temp-=input_memf[inp_num][label][2];
temp*=input_memf[inp_num][label][3];
temp=MU_MAX-temp;
if (temp < 0)
{ // 确保结果不小于0
return 0;
} else
{
return temp; // mu为正 - 返回结果
}
}
}
return 0;
}
//---------------------- defuzzify ----------------------------------------
void defuzzify(void)
{
unsigned long numerator, denominator;
unsigned char i;
numerator=0; // 恢复总数值
denominator=0;
for (i=0; i