刚开始在网上搜了下相关代码,发现全都是这个版本的(3条消息) c# 实现模糊PID控制算法_chinaherolts2008的博客-CSDN博客_c# pid算法
原作者简述中提到“这段算法在实际值低于目标值c#教程是工作正常,超过后会有问题,不知道如何调教”,我以为稳了,1天时间摸着鱼也就完成了,没想到远远没这么简单,以下是详情。
在熟悉代码的过程中发现了有下列3个问题:
1. 将“de = e - e_pre_1;”更正为“de = e - e_pre_1/Ke; //此处的e为外部反馈的e,而e_pre_1为转化论域后的值”;
2. 在“e_pre_2 = e_pre_1;”前增加“u += delta_u;”,并提前声明全局变量u,此处应用的是增量式PID,详情可以百度搜索“离散化PID公式”或“位置式PID与增量式PID”;
3. e和de模糊化过程中,富余空间直接填0的代码不严谨,有u_e[0]!=0或u_de[0]!=0的情况存在,需要添加两个变量更改,但影响也不是特别大。
再运行时发现e为负数时还是震荡特别厉害,然后我怀疑了三个点:
1.模糊规则有问题;2.基本论域上限有问题;3.在realize方法中不该限定Ki、Kp、Kd的值为非负数。
对于1和2问题我开始去知网查论文,结果发现没有人讲过模糊规则和基本论域如何选择,他们好像都直接得到了,而且对比大家的模糊规则,基本都是吻合的;对于3,我尝试了放开限定或更改限定范围,好像都没有结果。
附上我当前的代码,再调不出来我就没时间了啊啊啊
算法类 .cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace Test_FuzzPID
{
internal class FuzzyPID
{
public const int N = 7;
double target; //系统的控制目标
double actual; //采样获得的实际值
double e; //误差
double e_pre_1; //上一次的误差
double e_pre_2; //上上次的误差
double de; //误差的变化率
double emax; //误差基本论域上限
double demax; //误差变化率基本论域的上限
double delta_Kp_max; //delta_kp输出的上限
double delta_Ki_max; //delta_ki输出上限
double delta_Kd_max; //delta_kd输出上限
double Ke; //Ke=n/emax, 量化论域为[-3,-2,-1,0,1,2,3]
double Kde; //Kde=n/demax, 量化论域为[-3,-2,-1,0,1,2,3]
double Ku_p; //Ku_p=Kpmax/n,量化论域为[-3,-2,-1,0,1,2,3]
double Ku_i; //Ku_i=Kimax/n,量化论域为[-3,-2,-1,0,1,2,3]
double Ku_d; //Ku_d=Kdmax/n,量化论域为[-3,-2,-1,0,1,2,3]
int[,] Kp_rule_matrix = new int[N, N];//Kp模糊规则矩阵
int[,] Ki_rule_matrix = new int[N, N];//Ki模糊规则矩阵
int[,] Kd_rule_matrix = new int[N, N];//Kd模糊规则矩阵
string mf_t_e; //e的隶属度函数类型
string mf_t_de; //de的隶属度函数类型
string mf_t_Kp; //kp的隶属度函数类型
string mf_t_Ki; //ki的隶属度函数类型
string mf_t_Kd; //kd的隶属度函数类型
double[] e_mf_paras; //误差的隶属度函数的参数
double[] de_mf_paras;//误差的偏差隶属度函数的参数
double[] Kp_mf_paras; //kp的隶属度函数的参数
double[] Ki_mf_paras; //ki的隶属度函数的参数
double[] Kd_mf_paras; //kd的隶属度函数的参数
double Kp;
double Ki;
double Kd;
double A;
double B;
double C;
double u = 0;
public FuzzyPID(double e_max, double de_max, double kp_max, double ki_max, double kd_max, double Kp0, double Ki0, double Kd0)
{
emax = e_max;
demax = de_max;
delta_Kp_max = kp_max;
delta_Ki_max = ki_max;
delta_Kd_max = kd_max;
e = target - actual;
de = e - e_pre_1;
Ke = (N / 2) / emax;
Kde = (N / 2) / demax;
Ku_p = delta_Kp_max / (N / 2);
Ku_i = delta_Ki_max / (N / 2);
Ku_d = delta_Kd_max / (N / 2);
Kp = Kp0;
Ki = Ki0;
Kd = Kd0;
A = Kp + Ki + Kd;
B = -2 * Kd - Kp;
C = Kd;
}
//三角隶属度函数
double trimf(double x, double a, double b, double c)
{
double u;
if (x >= a && x <= b)
u = (x - a) / (b - a);
else if (x > b && x <= c)
u = (c - x) / (c - b);
else
u = 0;
return u;
}
//正态隶属度函数
double gaussmf(double x, double ave, double sigma)
{
double u;
if (sigma < 0)
{
throw new Exception("In gaussmf, sigma must larger than 0");
}
u = Math.Exp(-Math.Pow(((x - ave) / sigma), 2));
return u;
}
//梯形隶属度函数
double trapmf(double x, double a, double b, double c, double d)
{
double u;
if (x >= a && x < b)
u = (x - a) / (b - a);
else if (x >= b && x < c)
u = 1;
else if (x >= c && x <= d)
u = (d - x) / (d - c);
else
u = 0;
return u;
}
//设置模糊规则Matrix
public void setRuleMatrix(int[,] kp_m, int[,] ki_m, int[,] kd_m)
{
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
{
Kp_rule_matrix[i, j] = kp_m[i, j];
Ki_rule_matrix[i, j] = ki_m[i, j];
Kd_rule_matrix[i, j] = kd_m[i, j];
}
}
//设置模糊隶属度函数的子函数
void setMf_sub(string type, double[] paras, int n)
{
int N_mf_e = 0, N_mf_de = 0, N_mf_Kp = 0, N_mf_Ki = 0, N_mf_Kd = 0;
switch (n)
{
case 0:
if (type == "trimf" || type == "gaussmf" || type == "trapmf")
mf_t_e = type;
else
throw new Exception("Type of membership function must be \"trimf\" or \"gaussmf\" or \"trapmf\"");
if (mf_t_e == "trimf")
N_mf_e = 3;
else if (mf_t_e == "gaussmf")
N_mf_e = 2;
else if (mf_t_e == "trapmf")
N_mf_e = 4;
e_mf_paras =