📄 fuzzy.c
字号:
#include <hidef.h> /* common defines and macros */
#include "all_head.h"
#include <mc9s12dg128.h> /* derivative information */
#pragma LINK_INFO DERIVATIVE "mc9s12dg128b"
extern uchar FreqSetValue;
extern uchar value;
extern int E;
extern int EC;
extern int E1;
extern uchar U[8];
extern int pulse;
extern char channel;
extern int DisplayValue[8];
extern int SampArray[NUM];
extern int SampNum;
extern char NowChannel;
extern int flag; //看模糊控制输出值时用
extern int fuzzy_value[NUM]; //用于存放模糊控制器输出值
extern int k; //看实际输出值时用 ,实际输出值 = 上一次的值 + 当前控制器输出值 - 128
extern int control_value[NUM]; //用于存放实际给固态继电器的输出值
//extern uchar input_mfs[8][4];
uchar current_ins1; //精确的模糊输入变量1
uchar current_ins2; //精确的模糊输入变量2
const uchar input_mfs[8][4]={ //输入两变量的隶属函数
//E
0, EN2, 0, 13, //no.0 NB
EN1, EN3, 4, 10, //no.1 NS
EN2, EN4, 6, 6, //no.2 ZE
EN3, EN5, 10, 4, //no.3 PS
EN4, 250, 13, 0, //no.4 PB
//EC
0, ECN2, 0, 8, //no.0 NS
ECN1, ECN3, 8, 8, //no.1 Z
ECN2, 250, 8, 0, //no.2 PS
};
/***
----------------E------------
NB NS ZE PS PB
NS NB NS NS ZE PB
EC ZE NB NS ZE PS PB
PS NB ZE PS PS PB
------------------------------
***/
const uchar rule_start[76]={ //模糊推理规则表
(5*0)+0,(5*1)+0,0xfe,(5*0)+0+8,0xfe, //no.1
(5*0)+0,(5*1)+1,0xfe,(5*0)+0+8,0xfe, //2
(5*0)+0,(5*1)+2,0xfe,(5*0)+0+8,0xfe, //3
(5*0)+1,(5*1)+0,0xfe,(5*0)+1+8,0xfe, //4
(5*0)+1,(5*1)+1,0xfe,(5*0)+1+8,0xfe, //5
(5*0)+1,(5*1)+2,0xfe,(5*0)+2+8,0xfe, //6
(5*0)+2,(5*1)+0,0xfe,(5*0)+1+8,0xfe, //7
(5*0)+2,(5*1)+1,0xfe,(5*0)+2+8,0xfe, //8
(5*0)+2,(5*1)+2,0xfe,(5*0)+3+8,0xfe, //9
(5*0)+3,(5*1)+0,0xfe,(5*0)+2+8,0xfe, //10
(5*0)+3,(5*1)+1,0xfe,(5*0)+3+8,0xfe, //11
(5*0)+3,(5*1)+2,0xfe,(5*0)+3+8,0xfe, //12
(5*0)+4,(5*1)+0,0xfe,(5*0)+4+8,0xfe, //13
(5*0)+4,(5*1)+1,0xfe,(5*0)+4+8,0xfe, //14
(5*0)+4,(5*1)+2,0xfe,(5*0)+4+8,0xfe, //15
0xff};
uchar fuz_ins[8]; //用于存放两个模糊输入变量
uchar fuz_outs[5]; //用于存放一个模糊输出变量
uchar output_mfs[5]={32,103,128,154,250}; //输出变量的隶属度函数
/********模糊控制函数*********/
char fuzzy(int e, int ec) /* e表示偏差,ec表示偏差变化率 */
{
uchar cog_out=0;
int m1,m2;
/* 限幅值,128表示0,取值范围0--255 */
m1=e+127;
m2=ec+127;
if(m1<0)
m1=0;
if(m1>250)
m1=250;
if(m2<0)
m2=0;
if(m2>250)
m2=250;
current_ins1=m1-1;
current_ins2=m2-1;
asm{
fuzzyify: ldx #input_mfs
ldy #fuz_ins
ldaa current_ins1
ldab #5
grad_loop: mem
dbne b,grad_loop
ldaa current_ins2
ldab #3
grad_loop1: mem
dbne b,grad_loop1
ldab #5
rule_eval: clr 1,y+
dbne b,rule_eval
ldx #rule_start
ldy #fuz_ins
ldaa #0xff
rev
defuz: ldy #fuz_outs
ldx #output_mfs
ldab #5
wav
ediv
tfr y,d
stab cog_out // cog_out 系统输出
}
return cog_out;
}
/*限幅函数*/
uchar Bounds(uchar data)
{
if(data<1) data = 0;
if(data>250) data = 250;
return data;
}
/*将int型变量限幅到0-250之间*/
int Boundsint(int data) {
if(data<1) data = 0;
if(data>249) data = 249;
return data;
}
/*将输入数据缩小10倍*/
int ReduceBound(int data) { //缩小data的50倍,这个倍数可以根据需要更改,
int quotient; //主要因为采样时间太长
int surplus;
quotient = data/10; //将data缩小10倍
surplus = data%10; //求data除10后的余数
if(surplus>=5) quotient +=1; //判断余数大小,相似于四舍五入
return quotient;
}
/*********主控函数********/
void FreqControl(void) //输出值在0-250之间
{
int feedback_value;
int temp;
char nowchannel;
nowchannel = channel; //保存当前的通道值
channel++;
if(channel>7) channel = 0; //限幅值
pulse = Frequence_sample(); //读取当前通道采样反馈值
ChannelChoose(channel); //设定下一次采样为下一通道采样
feedback_value = ReduceBound(pulse); //限幅0--255
if(SampNum>=NUM) SampNum = 0;
SampArray[SampNum++] = feedback_value; //保存采样数据,以备查看
pulse = 0; //清零变量,
E = FreqSetValue - feedback_value; //求系统偏差
EC = E - E1; //求系统偏差变化
value = fuzzy(E,EC); //执行模糊控制
E1 = E; //当前偏差赋值给前一偏差,用于下次求偏差变化
value = Bounds(value); //限幅
//temp = value - 128; //转换结果,因为模糊控制器输出值是在0-255之间,128代表0
/*
temp = U + temp; //递加
temp = Boundsint(temp); //限幅
U = temp+1; //消除编译警告
//上面三行代码是为实现U =U + value - 128;
*/
temp = U[nowchannel] + value - 128; //递加,输出实际控制值,因为模糊控制器输出值128代表0,故要减去128
temp = Boundsint(temp); //限幅0-249
U[nowchannel] = temp + 1; //将限幅后的值赋给U[nowchannel], +1是为了消除编译警告
U[nowchannel] = Bounds(U[nowchannel]); //限幅0-250,产生控制器输出值
PWM_Generate(nowchannel,U[nowchannel]+128); //产生实际PWM控制量
//这里不能直接将U[nowchannel]作为占空比输出,还应有一个转换过程,
//因为算得的取值范围与实际产生PWM占空比的取值范围一样都是0-250,同样是128代表0,故在此+128
DisplayValue[nowchannel] = feedback_value-1; //保存当前通道的反馈值,-1是为了配合后面消除编译警告
DisplayPicture(NowChannel); //实时显示
//存放控制器输出值,主要为了调试方便
if(flag>NUM) flag = 0;
fuzzy_value[flag++] = value; //fuzzy controller output
if(k>NUM) k = 0;
control_value[k++] = U[nowchannel] + 128; //the actual output pwm
/*
//串口显示当前控制器输出值
if(flag>7) flag = 0;
Sci0Write_string("the output of controller_ch");
Sci0_Sendvalue(flag);
Sci0Write_string(" is ");
Sci0_Sendvalue(value);
Sci0_Sendbyte('\n');
flag++;
//串口显示当前系统输出实际值
if(k>7) k = 0;
Sci0Write_string("the output of system_ch");
Sci0_Sendvalue(k);
Sci0Write_string(" is ");
Sci0_Sendvalue(U[nowchannel] + 128);
Sci0_Sendbyte('\n');
k++;
*/
}
//如果要加入外部按键操作, 可以将nowchannel设为全局变量
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -