前言
关于模糊PID网上及相关文献介绍掉了很多,但是我一直存在一个疑问,也是很多博客和文献中没有提到的一个细节,就是如何根据error与Δerror的隶属度求得kp、ki、kd的总隶属度。
这里我将整体描述以下一种模糊PID的算法与伪代码以及如何根据error与Δerror的隶属度求得kp、ki、kd的总隶属度。
采用重心法求总隶属度。
模糊控制框图
模糊控制算法环节处于整个控制器的核心地位,其在对PI参数进行修正的过程中起到承上启下的作用,模糊控制算法的设计过程主要可分为规则库建立和隶属函数选取两部分。
模糊控制器设计步骤
个模糊控制器的完整设计过程主要可分为输入模糊化、确定隶属函数、建立模糊控制规则与解模糊化输出四个步骤,下面分别对每个步骤进行介绍与分析。
一、输入模糊化
由于模糊控制器是根据语言变量来工作的,而一般系统中的误差量均为精确量,因此在这些误差信号进入模糊控制器之前需要进行模糊化处理。系统中误差和误差变化率的实际范围称为基本沦域,属于连续域,通过模糊化处理可将精确量从其基本论域映射到离散的模糊论域。
设误差E的基本论域为(-XE,XE)(XE>0),模糊化后可得其离散模糊论域为{-n,-n+l,…,0…,n-1,n},量化因子kq可由下式确定。在完成输入模糊化环节后,接下来需要将离散论域归类于相对应的模糊子集。
kq= n/XE;
量化函数:
float Quantization(float maximum,float minimum,float x)
{
float qvalues= 6.0 *(x-minimum)/(maximum - minimum)-3;
return qvalues;
}
将误差 error 和Δerror映射到论域中
下面展示一些 内联代码片
。
//输入e与de/dt隶属度计算函数
void Get_grad_membership(float error,float error_c)
{
if (error > e_membership_values[0] && error < e_membership_values[6])
{
for (int i = 0; i < num_area - 2; i++)
{
if (error >= e_membership_values[i] && error <= e_membership_values[i + 1])
{
e_gradmembership[0] = -(error - e_membership_values[i + 1]) / (e_membership_values[i + 1] - e_membership_values[i]);
e_gradmembership[1] = 1+(error - e_membership_values[i + 1]) / (e_membership_values[i + 1] - e_membership_values[i]);
e_grad_index[0] = i;
e_grad_index[1] = i + 1;
break;
}
}
}
else
{
if (error <= e_membership_values[0])
{
e_gradmembership[0] = 1;
e_gradmembership[1] = 0;
e_grad_index[0] = 0;
e_grad_index[1] = -1;
}
else if (error >= e_membership_values[6])
{
e_gradmembership[0] = 1;
e_gradmembership[1] = 0;
e_grad_index[0] = 6;
e_grad_index[1] = -1;
}
}
if (error_c > ec_membership_values[0] && error_c < ec_membership_values[6])
{
for (int i = 0; i < num_area - 2; i++)
{
if (error_c >= ec_membership_values[i] && error_c <= ec_membership_values[i + 1])
{
ec_gradmembership[0] = -(error_c - ec_membership_values[i + 1]) / (ec_membership_values[i + 1] - ec_membership_values[i]);
ec_gradmembership[1] = 1 + (error_c - ec_membership_values[i + 1]) / (ec_membership_values[i + 1] - ec_membership_values[i]);
ec_grad_index[0] = i;
ec_grad_index[1] = i + 1;
break;
}
}
}
else
{
if (error_c <= ec_membership_values[0])
{
ec_gradmembership[0] = 1;
ec_gradmembership[1] = 0;
ec_grad_index[0] = 0;
ec_grad_index[1] = -1;
}
else if (error_c >= ec_membership_values[6])
{
ec_gradmembership[0] = 1;
ec_gradmembership[1] = 0;
ec_grad_index[0] = 6;
ec_grad_index[1] = -1;
}
}
}
二、确定隶属函数
隶属函数按分辨率可划分为宽型隶属函数和窄型隶属函数,宽型隶属函数分辨率较低,控制性能较缓和;窄型隶属函数分辨率较高,控制灵敏度也相应较高。在选取隶属函数时,需要从灵敏度、鲁棒性、运算能力以及指标需求等多方面进行综合考量;这里选取的隶属函数为三角形隶属函数。
三、建立模糊控制规则
四、解模糊化输出
解模糊化也称为反模糊化,经过模糊控制规则推理后的输出值是一个模糊值,但作用于被控对象上的控制量需要是一个精确值,解模糊化过程就是将模糊推理的结果转换成为精确值的过程,该精确值不仅需要能最大程度上地代表转换前的模糊值,而且需要有较好的连续性,这样才可以在整个论域范围内都保持较高的分辨率。这里采用重心法解模糊度输出。
如下图所示:
下面展示一些 内联代码片
。
void GetSumGrad()
{
int Kp_rule_list[7][7] = { {PB,PB,PM,PM,PS,ZO,ZO}, //kp规则表
{PB,PB,PM,PS,PS,ZO,NS},
{PM,PM,PM,PS,ZO,NS,NS},
{PM,PM,PS,ZO,NS,NM,NM},
{PS,PS,ZO,NS,NS,NM,NM},
{PS,ZO,NS,NM,NM,NM,NB},
{ZO,ZO,NM,NM,NM,NB,NB} };
int Ki_rule_list[7][7] = { {NB,NB,NM,NM,NS,ZO,ZO}, //ki规则表
{NB,NB,NM,NS,NS,ZO,ZO},
{NB,NM,NS,NS,ZO,PS,PS},
{NM,NM,NS,ZO,PS,PM,PM},
{NM,NS,ZO,PS,PS,PM,PB},
{ZO,ZO,PS,PS,PM,PB,PB},
{ZO,ZO,PS,PM,PM,PB,PB} };
// 初始化 Kp、Ki、Kd 总的隶属度值为 0
for (int i = 0; i <= num_area - 1; i++)
{
KpgradSums[i] = 0;
KigradSums[i] = 0;
KdgradSums[i] = 0;
}
for (int i = 0; i < 2; i++)
{
if (e_grad_index[i] == -1)
{
continue;
}
for (int j = 0; j < 2; j++)
{
if (ec_grad_index[j] != -1)
{
int indexKp = Kp_rule_list[e_grad_index[i]][ec_grad_index[j]] + 3;
int indexKi = Ki_rule_list[e_grad_index[i]][ec_grad_index[j]] + 3;
KpgradSums[indexKp]= KpgradSums[indexKp] + (e_gradmembership[i] * ec_gradmembership[j]);
KigradSums[indexKi] = KigradSums[indexKi] + (e_gradmembership[i] * ec_gradmembership[j]);
}
else
{
continue;
}
}
}
}
// 计算输出增量kp,kd,ki对应论域值
void GetOUT()
{
for (int i = 0; i < num_area - 1; i++)
{
qdetail_kp += kp_menbership_values[i] * KpgradSums[i];
qdetail_ki += ki_menbership_values[i] * KigradSums[i];
}
}
//反区间映射函数
float Inverse_quantization(float maximum, float minimum, float qvalues)
{
float x = (maximum - minimum) *(qvalues + 3)/6 + minimum;
return x;
}
五、模糊PID控制实现函数
下面展示一些 内联代码片
。
//模糊PID控制实现函数
float FuzzyPIDcontroller(float e_max, float e_min, float ec_max, float ec_min, float kp_max, float kp_min, float error, float error_c,float ki_max,float ki_min,float kd_max,float kd_min,float error_pre,float error_ppre)
{
qerror = Quantization(e_max, e_min, error); //将 误差 error 映射到论域中
qerror_c = Quantization(ec_max, ec_min, error_c); //将误差变化 error_c 映射到论域中
Get_grad_membership(qerror, qerror_c); //计算误差 error 和误差变化 error_c 的隶属度
GetSumGrad(); //计算输出增量 △kp、△ki、△kd 的总隶属度
GetOUT(); // 计算输出增量 △kp、△ki、△kd 对应论域值
detail_kp = Inverse_quantization(kp_max, kp_min, qdetail_kp); //去模糊化得到增量 △kp
detail_ki = Inverse_quantization(ki_max, ki_min, qdetail_ki); //去模糊化得到增量 △ki
detail_kd = Inverse_quantization(kd_max, kd_min, qdetail_kd); //去模糊化得到增量 △kd
qdetail_kd = 0;
qdetail_ki = 0;
qdetail_kp = 0;
kp = kp + detail_kp; //得到最终的 kp 值
ki = ki + detail_ki; //得到最终的 ki 值
kd = kd + detail_kd; //得到最终的 kd 值
if (kp < 0)
kp = 0;
if (ki < 0)
ki = 0;
if (kd < 0)
kd = 0;
detail_kp = 0;
detail_ki = 0;
detail_kd = 0;
float output = kp*(error - error_pre) + ki * error + kd * (error - 2 * error_pre + error_ppre); //计算最终的输出
return output;
}