一般的控制器只有一套参数,无法实时调整,于是引入模糊控制器,对控制器的参数进行调整

模糊控制一般分为三个部分

  1. 模糊化
  2. 模糊推理
  3. 去模糊化
1
2
3
4
5
6
7
graph LR
subgraph 模糊控制器
输入==e==>模糊化==E==>模糊推理==U==>清晰化==u==>输出
end
输入隶属度函数-.-模糊化
规则库-.-模糊推理
输出隶属度函数-.-清晰化

模糊化

基本概念

  • 模糊量:输入模糊控制器的量,如(偏差)、
  • 论域:模糊子集上下限的区间
  • 隶属度:隶属于某模糊子集的程度
  • 模糊子集:
    • NB (Negetive Big)
    • NM (Negative Medium)
    • NS (Negative Small)
    • ZO (Zero)
    • PS (Positive Small)
    • PM (Positive Medium)
    • PB (Positive Big)

模糊化

根据隶属度函数(模糊函数)求隶属度。一般使用线性隶属度函数(三角隶属度函数)。例如对于一个测量信号,其模糊化的过程如下:

  1. 定义模糊子集,分别对应NB,NM,NS,ZO,PS,PM,PB
  2. 将输入量化。为了将与模糊子集对应,引入量化函数,的范围为为两次作差,范围为的二倍。采取线性量化,函数关系为例如,则
  3. 计算隶属度。对于线性隶属度函数,我们只需计算量化值其与其所属的两个隶属度的差值比例即可。其中,隶属于PS和PM,隶属于NB和NM。隶属于PS的隶属度为:隶属于PM的隶属度为:隶属于NB的隶属度为:隶属于NM的隶属度为:可以看出,对于一个输入,它所属的两个隶属度的和为1

模糊推理

模糊推理:根据模糊规则表求输出值U的隶属度,决策出模糊输出量

对于一般的控制,我们可以制订以下模糊表规则:

U NB NM NS ZO PS PM PB
NB PB PB PB PB PM ZO ZO
NM PB PB PB PM PM ZO ZO
NS PB PM PM PS ZO NS NM
ZO PM PM PS ZO NS NM NM
PS PS PS ZO NM NM NM NB
PM ZO ZO ZO NM NB NB NB
PB ZO NS NB NB NB NB NB

其中,第一列为的取值,第一行为的取值。

根据以上规则,可以求得输出值隶属于各个模糊子集的隶属度为:
隶属于PS的隶属度为:隶属于ZO的隶属度为:

U ==NB== ==NM== NS ZO PS PM PB
NB PB PB PB PB PM ZO ZO
NM PB PB PB PM PM ZO ZO
NS PB PM PM PS ZO NS NM
ZO PM PM PS ZO NS NM NM
==PS== ==PS== ==PS== ZO NM NM NM NB
==PM== ==ZO== ==ZO== ZO NM NB NB NB
PB ZO NS NB NB NB NB NB

去模糊化

对于输出值,我们同样采用给予隶属度的方法。由于采用了相同的论域,模糊变量的隶属度是相同的。基于这一基础,采用重心法计算量化值。其公式如下:对于三角隶属度函数,有:
对于上例,输出值为:
是一个在论域范围内的量化值

要将其转化为实际值,使用以下公式:

代码实现

fuzzy_pid.h

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
/**
* @file fuzzy_pid.h
* @brief 模糊PID控制器
* @version 1.0
* @author SkylerLiang
* @date 2023-10-15
* @note 仅测试使用
*/

#ifndef __FUZZY_PID_H
#define __FUZZY_PID_H

#include "GM6020.h"

// 模糊子集枚举
enum Union
{
NB = -3,
NM = -2,
NS = -1,
ZO = 0,
PS = 1,
PM = 2,
PB = 3
};

// 将对应的PID控制结构体typedef为PIDController
// @note: 有些结构体的上次偏差命名为Err_Last,有些命名为Err_last,注意区分
typedef GM6020_PID PIDController;

// 隶属度结构体
typedef struct
{
enum Union L_Union; /* 左侧隶属子集 */
enum Union R_Union; /* 右侧隶属子集 */
float L_Membership; /* 左侧隶属度 */
float R_Membership; /* 右侧隶属度 */
} Membership;

// 模糊控制器结构体
typedef struct
{
float MAX; /* 实际最大值 */
float MIN; /* 实际最小值 */
float E; /* 偏差(量化后) */
float EC; /* 偏差变化(量化后) */
float Kp_Output; /* Kp增量 */
float Ki_Output; /* Ki增量 */
float Kd_Output; /* Kd增量 */
Membership E_Membership; /* E的隶属结构体 */
Membership EC_Membership; /* EC的隶属结构体 */
} FuzzyController;

void LinearQuantization(FuzzyController *fc, float e, float ec);
void CalcMembership(Membership *ms, float qv);
void FuzzyComputation(FuzzyController *fc, float rule[7][7], float *output);
void FuzzyPID(PIDController *pidController);

#endif

fuzzy_pid.c

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
/**
* @file fuzzy_pid.c
* @brief 模糊PID控制器
* @version 1.0
* @author SkylerLiang
* @date 2023-10-15
* @note 仅测试使用
*/

#include "fuzzy_pid.h"

// 规则库,行为e,列为ec
float ruleKp[7][7] =
{
PB, PB, PM, PM, PS, PS, ZO,
PB, PB, PM, PM, PS, ZO, ZO,
PM, PM, PM, PS, ZO, NS, NM,
PM, PS, PS, ZO, NS, NM, NM,
PS, PS, ZO, NS, NS, NM, NM,
ZO, ZO, NS, NM, NM, NM, NB,
ZO, NS, NS, NM, NM, NB, NB};

float ruleKi[7][7] =
{
NB, NB, NB, NM, NM, ZO, ZO,
NB, NB, NM, NM, NS, ZO, ZO,
NM, NM, NS, NS, ZO, PS, PS,
NM, NS, NS, ZO, PS, PS, PM,
NS, NS, ZO, PS, PS, PM, PM,
ZO, ZO, PS, PM, PM, PB, PB,
ZO, ZO, PS, PM, PB, PB, PB};

float ruleKd[7][7] =
{
PS, PS, ZO, ZO, ZO, PB, PB,
NS, NS, NS, NS, ZO, NS, PM,
NB, NB, NM, NS, ZO, PS, PM,
NB, NM, NM, NS, ZO, PS, PM,
NB, NM, NS, NS, ZO, PS, PS,
NM, NS, NS, NS, ZO, PS, PS,
PS, ZO, ZO, ZO, ZO, PB, PB};

// 模糊控制器输出增益
double increase[3] = {0.1, 0.1, 0.1};

// 实例化模糊控制器,这里取值范围为GM6020电机允许的速度范围
FuzzyController fuzzyController = {
.MAX = 320,
.MIN = -320};

/**
* @brief 将实际的偏差和偏差变化线性量化到论域[-3,3]范围内
* @param fc 要被储存量化结果的模糊控制器
* @param e 要被量化的偏差值
* @param ec 要被量化的偏差变化值
* @note 库内部调用
*/
void LinearQuantization(FuzzyController *fc, float e, float ec)
{
fc->E = 3.0 * e / (fc->MAX - fc->MIN);
fc->EC = 1.5 * ec / (fc->MAX - fc->MIN);
}

/**
* @brief 根据线性隶属度函数计算给定输入值的隶属关系及隶属度
* @param ms Membership,隶属度结构体,用于储存计算结果
* @param qv Quantizated Value,量化后的输入值
* @note 库内部调用
*/
void CalcMembership(Membership *ms, float qv)
{
if (qv < NB)
{
ms->L_Union = NB;
ms->R_Union = NB;
ms->L_Membership = 0;
ms->R_Membership = 1.0;
}
else if ((qv >= NB) && (qv < NM))
{
ms->L_Union = NB;
ms->R_Union = NM;
ms->L_Membership = -qv - 2.0;
ms->R_Membership = qv + 3.0;
}
else if ((qv >= NM) && (qv < NS))
{
ms->L_Union = NM;
ms->R_Union = NS;
ms->L_Membership = -qv - 1.0;
ms->R_Membership = qv + 2.0;
}
else if ((qv >= NS) && (qv < ZO))
{
ms->L_Union = NS;
ms->R_Union = ZO;
ms->L_Membership = -qv;
ms->R_Membership = qv + 1.0;
}
else if ((qv >= ZO) && (qv < PS))
{
ms->L_Union = ZO;
ms->R_Union = PS;
ms->L_Membership = -qv + 1.0;
ms->R_Membership = qv;
}
else if ((qv >= PS) && (qv < PM))
{
ms->L_Union = PS;
ms->R_Union = PM;
ms->L_Membership = -qv + 2.0;
ms->R_Membership = qv - 1.0;
}
else if ((qv >= PM) && (qv <= PB))
{
ms->L_Union = PM;
ms->R_Union = PB;
ms->L_Membership = -qv + 3.0;
ms->R_Membership = qv - 2.0;
}
else if (qv > PB)
{
ms->L_Union = PB;
ms->R_Union = PB;
ms->L_Membership = 1.0;
ms->R_Membership = 0;
}
}

/**
* @brief 根据给定的规则和输入成员计算模糊控制器的输出
* @param fc 包含输入成员信息的FuzzyController结构体
* @param rule 用于模糊推理的7x7规则矩阵
* @param output 指向将要计算的输出变量的指针
* @note 库内部调用
*/
void FuzzyComputation(FuzzyController *fc, float rule[7][7], float *output)
{
// 计算每条规则的输出,储存在临时数组中
float temp[4];
temp[0] = rule[fc->E_Membership.L_Union + 3][fc->EC_Membership.L_Union + 3] * (fc->E_Membership.L_Membership) * (fc->EC_Membership.L_Membership);
temp[1] = rule[fc->E_Membership.L_Union + 3][fc->EC_Membership.R_Union + 3] * (fc->E_Membership.L_Membership) * (fc->EC_Membership.R_Membership);
temp[2] = rule[fc->E_Membership.R_Union + 3][fc->EC_Membership.L_Union + 3] * (fc->E_Membership.R_Membership) * (fc->EC_Membership.L_Membership);
temp[3] = rule[fc->E_Membership.R_Union + 3][fc->EC_Membership.R_Union + 3] * (fc->E_Membership.R_Membership) * (fc->EC_Membership.R_Membership);

// 将计算结果求和,得到最终输出
*output = (temp[0] + temp[1] + temp[2] + temp[3]);
}

/**
* @brief 模糊PID控制器
* @param pidController 指向PIDController结构体的指针,该结构体包含误差值和上次误差值。
* @note 该函数应在PID控制器的计算周期内被调用,如GM6020_Set_Speed()函数中
* @exception 有些结构体的上次偏差命名为Err_last,如报错请自行修改
*/
void FuzzyPID(PIDController *pidController)
{
// 线性量化
LinearQuantization(&fuzzyController, pidController->Err, pidController->Err - pidController->Err_Last);

// 计算隶属度
CalcMembership(&fuzzyController.E_Membership, fuzzyController.E);
CalcMembership(&fuzzyController.EC_Membership, fuzzyController.EC);

// Kp模糊推理
FuzzyComputation(&fuzzyController, ruleKp, &fuzzyController.Kp_Output);
pidController->Kp += fuzzyController.Kp_Output * increase[0];
if (pidController->Kp < 0)
pidController->Kp = 0;

// Ki模糊推理
FuzzyComputation(&fuzzyController, ruleKi, &fuzzyController.Ki_Output);
pidController->Ki += fuzzyController.Ki_Output * increase[1];
if (pidController->Ki < 0)
pidController->Ki = 0;

// Kd模糊推理
FuzzyComputation(&fuzzyController, ruleKd, &fuzzyController.Kd_Output);
pidController->Kd += fuzzyController.Kd_Output * increase[2];
if (pidController->Kd < 0)
pidController->Kd = 0;
}