两输入单输出模糊控制代码C51

基于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


















你可能感兴趣的:(两输入单输出模糊控制代码C51)