ファジィPID制御
この文書は主に 3 つの部分で構成されています: ファジィ PID コントローラーの原理、C++ でのファジー PID コントローラーの実装とテスト。
1. ファジィPID原理
ファジィ PID 制御の処理は下図のようになります.目標値Xtargetと出力値Xoutの誤差eとeの変化率de/dtをファジィ制御器の入力として用います. ファジィ制御器はまずファジィ演算を行います.入力に対する処理を行った後、ファジィ推論を実行し、最後にファジィ推論の結果を非ファジィ化して、PID コントローラの 3 つのパラメータkp、ki、kd を出力し、PID コントローラ パラメータの適応調整の効果を実現します。
上記の説明によれば、ファジー コントローラーは主に、非ファジー化、ファジー推論、非ファジー化の 3 つの部分で構成されます。3 つの部分については、以下で詳しく説明します。
1.1 ファジー化
ファジー化を実現するには、まずファジー化を初期化する必要があります。これには、談話領域の決定とメンバーシップ関数の決定が含まれます。
1.1.1 论域
談話領域は人為的に定められた範囲と言えますが、入力 e, de/dt と出力 kp, ki, kd の範囲が異なるため、統一するには入力を談話領域にマッピングした方がよいと考えられます。処理。言説領域の範囲を決定した後、言説領域をファジィ分類する、すなわち言説領域を分割する必要がある。談話領域を [-3, 3] と仮定し、談話領域を [-3, -2]、[-2, -1]、[-1, 0]、[0] の 5 つの等しい部分に分割します。 、1]、[1、2]、[2、3]。次に、各エンドポイントを次の順序でグレードに分割します: -3—>NB (負性大)、-2—>NM (負性中)、-1—>NS (負性小)、0—>ZO(ゼロ)、1 ---->PS(正小)、2--->PM(正中)、3--->PB(正大)。入力 e の範囲が [-10, 10]、この時点の e の値が 8、マッピング後の値が 2.4 で、2.4 が区間 [2, 3] 内にあるとすると、点は の間にあります。真ん中と右。概略図は次のとおりです。
1.1.2 メンバーシップ関数の決定。
一般的なメンバーシップ関数には、三角メンバーシップ関数、台形メンバーシップ関数、放物線メンバーシップ関数などがあります。最も単純な三角形メンバーシップ関数を例として、その形状を次の図に示します。
上の図からわかるように、メンバーシップ関数の値の範囲は [0, 1] です。マッピング後の入力 e の値が 2.4 の場合、下図の赤線と緑線に相当する値はそれぞれ 0.6 と 0.4 となり、この 2 つは帰属度であり、 PM に属する入力は 0.6、PB に属する確率は 0.4 です。したがって、メンバーシップの度合いも確率です。
上記の談話領域とメンバーシップ関数の説明から、ファジー化のプロセスは区間マッピングに要約でき、メンバーシップ度はメンバーシップ関数に従って計算されます。
1.2 ファジー推論
ファジー推論。つまり、e および de/dt のメンバーシップ次数に従ってテーブルを検索し、出力のサイズ (NB、NS など) を取得します。したがって、ファジィ推論の中核となる作業は、推論テーブルを構築することです。ファジー PID で一般的に使用される推論テーブルを次の図に示します。
以下では、例を使用してルール テーブルの使用方法を説明します。
このときの入力 e が 8、de/dt が -12、e の範囲が [-10,10]、de/dt の範囲が [-20,20] であるとします。ファジー化により、e のメンバーシップ度は 0.6 (PM) と 0.4 (PB)、de/dt のメンバーシップ度は 0.8 (NM) と 0.2 (NS) となり、e と de/dt のメンバーシップ度は次のようになります。は 2 つです。この 2 つを組み合わせてテーブル検索を実行すると、次の表の関係が得られます。
次に、各出力 Kp、Ki、Kd の帰属度を計算します。
Kp を例に挙げます。
同様に、Ki と Kd もメンバーシップの度合いを計算します。
最後に、各出力の帰属度を Kp として統合します。上記の計算によれば、Kp の帰属度は 0.8 (ZO)、0.12 (NS)、0.08 (NM) となります。
1.3 ブレの除去
非ファジィ化とは、ファジィ推論によって得られた各出力の帰属度に応じて談話領域における出力の値を計算し、区間写像関係に従って出力を取得することである。
1.3.1 談話領域における出力の価値を計算する
上の例は、計算プロセスを説明するために使用されています。上記より、Kp のメンバーシップ度は 0.8 (ZO)、0.12 (NS)、0.08 (NM) であることがわかります。ユニバースの説明では ZO の値を 0、 NS は -1 に設定され、NM の値は -2 に設定されます。この場合、Kp の期待値は次のようになります。
談話領域における Kp の値として期待値を考慮し、Kp の範囲を決定した後、区間マッピング式に従って Kp の出力値を取得できます。
以上がファジィコントローラの流れとなります。
出力 Kp、Ki、Kd が増分であることは注目に値します。初期化中に、間隔マッピングのために入力と出力の範囲 (間隔) を決定する必要があります。
2.1 ファジー PID コントローラーの C++ 実装
このバージョンのメンバーシップ関数は固定トライアングル メンバーシップ関数であり、談話領域は [-3, 3] に固定されています。
ファジーPID.h
#ifndef FuzzyPID_H
#define FuzzyPID_H
class FuzzyPID
{
public:
FuzzyPID();
~FuzzyPID();
void Get_grad_membership(float erro, float erro_c);
float Quantization(float maximum, float minimum, float x);
float Inverse_quantization(float maximum, float minimum, float qvalues);
void GetSumGrad();
void GetOUT();
float FuzzyPIDcontroller(float e_max, float e_min, float ec_max, float ec_min, float kp_max, float kp_min, float erro, float erro_c, float ki_max, float ki_min,float kd_max, float kd_min,float erro_pre, float errp_ppre);
const int num_area = 8; //划分区域个数
//float e_max; //误差做大值
//float e_min; //误差最小值
//float ec_max; //误差变化最大值
//float ec_min; //误差变化最小值
//float kp_max, kp_min;
float e_membership_values[7] = {
-3,-2,-1,0,1,2,3}; //输入e的隶属值
float ec_membership_values[7] = {
-3,-2,-1,0,1,2,3 };//输入de/dt的隶属值
float kp_menbership_values[7] = {
-3,-2,-1,0,1,2,3 };//输出增量kp的隶属值
float ki_menbership_values[7] = {
-3,-2,-1,0,1,2,3 }; //输出增量ki的隶属值
float kd_menbership_values[7] = {
-3,-2,-1,0,1,2,3 }; //输出增量kd的隶属值
float fuzzyoutput_menbership_values[7] = {
-3,-2,-1,0,1,2,3 };
//int menbership_values[7] = {-3,-};
float kp; //PID参数kp
float ki; //PID参数ki
float kd; //PID参数kd
float qdetail_kp; //增量kp对应论域中的值
float qdetail_ki; //增量ki对应论域中的值
float qdetail_kd; //增量kd对应论域中的值
float qfuzzy_output;
float detail_kp; //输出增量kp
float detail_ki; //输出增量ki
float detail_kd; //输出增量kd
float fuzzy_output;
float qerro; //输入e对应论域中的值
float qerro_c; //输入de/dt对应论域中的值
float errosum;
float e_gradmembership[2]; //输入e的隶属度
float ec_gradmembership[2]; //输入de/dt的隶属度
int e_grad_index[2]; //输入e隶属度在规则表的索引
int ec_grad_index[2]; //输入de/dt隶属度在规则表的索引
float gradSums[7] = {
0,0,0,0,0,0,0};
float KpgradSums[7] = {
0,0,0,0,0,0,0 }; //输出增量kp总的隶属度
float KigradSums[7] = {
0,0,0,0,0,0,0 }; //输出增量ki总的隶属度
float KdgradSums[7] = {
0,0,0,0,0,0,0 }; //输出增量kd总的隶属度
int NB = -3, NM = -2, NS = -1, ZO = 0, PS = 1, PM = 2, PB = 3; //论域隶属值
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} };
int Kd_rule_list[7][7] = {
{
PS,NS,NB,NB,NB,NM,PS}, //kd规则表
{
PS,NS,NB,NM,NM,NS,ZO},
{
ZO,NS,NM,NM,NS,NS,ZO},
{
ZO,NS,NS,NS,NS,NS,ZO},
{
ZO,ZO,ZO,ZO,ZO,ZO,ZO},
{
PB,NS,PS,PS,PS,PS,PB},
{
PB,PM,PM,PM,PS,PS,PB} };
int Fuzzy_rule_list[7][7] = {
{
PB,PB,PB,PB,PM,ZO,ZO},
{
PB,PB,PB,PM,PM,ZO,ZO},
{
PB,PM,PM,PS,ZO,NS,NM},
{
PM,PM,PS,ZO,NS,NM,NM},
{
PS,PS,ZO,NM,NM,NM,NB},
{
ZO,ZO,ZO,NM,NB,NB,NB},
{
ZO,NS,NB,NB,NB,NB,NB}};
//private:
};
#endif
ファジーPID.cpp
#include "FuzzyPID.h"
FuzzyPID::FuzzyPID() //构造函数
{
kp = 0;
ki = 0;
kd = 0;
fuzzy_output = 0;
qdetail_kp = 0;
qdetail_ki = 0;
qdetail_kd = 0;
qfuzzy_output = 0;
errosum = 0;
}
FuzzyPID::~FuzzyPID()//析构函数
{
}
//输入e与de/dt隶属度计算函数///
void FuzzyPID::Get_grad_membership(float erro,float erro_c)
{
if (erro > e_membership_values[0] && erro < e_membership_values[6])
{
for (int i = 0; i < num_area - 2; i++)
{
if (erro >= e_membership_values[i] && erro <= e_membership_values[i + 1])
{
e_gradmembership[0] = -(erro - e_membership_values[i + 1]) / (e_membership_values[i + 1] - e_membership_values[i]);
e_gradmembership[1] = 1+(erro - 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 (erro <= e_membership_values[0])
{
e_gradmembership[0] = 1;
e_gradmembership[1] = 0;
e_grad_index[0] = 0;
e_grad_index[1] = -1;
}
else if (erro >= e_membership_values[6])
{
e_gradmembership[0] = 1;
e_gradmembership[1] = 0;
e_grad_index[0] = 6;
e_grad_index[1] = -1;
}
}
if (erro_c > ec_membership_values[0] && erro_c < ec_membership_values[6])
{
for (int i = 0; i < num_area - 2; i++)
{
if (erro_c >= ec_membership_values[i] && erro_c <= ec_membership_values[i + 1])
{
ec_gradmembership[0] = -(erro_c - ec_membership_values[i + 1]) / (ec_membership_values[i + 1] - ec_membership_values[i]);
ec_gradmembership[1] = 1 + (erro_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 (erro_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 (erro_c >= ec_membership_values[6])
{
ec_gradmembership[0] = 1;
ec_gradmembership[1] = 0;
ec_grad_index[0] = 6;
ec_grad_index[1] = -1;
}
}
}
/获取输出增量kp,ki,kd的总隶属度/
void FuzzyPID::GetSumGrad()
{
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;
int indexKd = Kd_rule_list[e_grad_index[i]][ec_grad_index[j]] + 3;
//gradSums[index] = gradSums[index] + (e_gradmembership[i] * ec_gradmembership[j])* Kp_rule_list[e_grad_index[i]][ec_grad_index[j]];
KpgradSums[indexKp]= KpgradSums[indexKp] + (e_gradmembership[i] * ec_gradmembership[j]);
KigradSums[indexKi] = KigradSums[indexKi] + (e_gradmembership[i] * ec_gradmembership[j]);
KdgradSums[indexKd] = KdgradSums[indexKd] + (e_gradmembership[i] * ec_gradmembership[j]);
}
else
{
continue;
}
}
}
}
计算输出增量kp,kd,ki对应论域值//
void FuzzyPID::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];
qdetail_kd+= kd_menbership_values[i] * KdgradSums[i];
}
}
//模糊PID控制实现函数/
float FuzzyPID::FuzzyPIDcontroller(float e_max, float e_min, float ec_max, float ec_min, float kp_max, float kp_min, float erro, float erro_c,float ki_max,float ki_min,float kd_max,float kd_min,float erro_pre,float errp_ppre)
{
errosum += erro;
//Arear_dipart(e_max, e_min, ec_max, ec_min, kp_max, kp_min,ki_max,ki_min,kd_max,kd_min);
qerro = Quantization(e_max, e_min, erro);
qerro_c = Quantization(ec_max, ec_min, erro_c);
Get_grad_membership(qerro, qerro_c);
GetSumGrad();
GetOUT();
detail_kp = Inverse_quantization(kp_max, kp_min, qdetail_kp);
detail_ki = Inverse_quantization(ki_max, ki_min, qdetail_ki);
detail_kd = Inverse_quantization(kd_max, kd_min, qdetail_kd);
qdetail_kd = 0;
qdetail_ki = 0;
qdetail_kp = 0;
/*if (qdetail_kp >= kp_max)
qdetail_kp = kp_max;
else if (qdetail_kp <= kp_min)
qdetail_kp = kp_min;
if (qdetail_ki >= ki_max)
qdetail_ki = ki_max;
else if (qdetail_ki <= ki_min)
qdetail_ki = ki_min;
if (qdetail_kd >= kd_max)
qdetail_kd = kd_max;
else if (qdetail_kd <= kd_min)
qdetail_kd = kd_min;*/
kp = kp + detail_kp;
ki = ki + detail_ki;
kd = kd + detail_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*(erro - erro_pre) + ki * erro + kd * (erro - 2 * erro_pre + errp_ppre);
return output;
}
///区间映射函数///
float FuzzyPID::Quantization(float maximum,float minimum,float x)
{
float qvalues= 6.0 *(x-minimum)/(maximum - minimum)-3;
//float qvalues=6.0*()
return qvalues;
//qvalues[1] = 3.0 * ecerro / (maximum - minimum);
}
//反区间映射函数
float FuzzyPID::Inverse_quantization(float maximum, float minimum, float qvalues)
{
float x = (maximum - minimum) *(qvalues + 3)/6 + minimum;
return x;
}
ファジー PID コントローラーをテストします。
#include <iostream>
#include "FuzzyPID.h"
int main()
{
FuzzyPID myfuzzypid;
float Target = 600;
float actual = 0;
float e_max =1000;
float e_min = -1000;
float ec_max = 800;
float ec_min = -800;
float kp_max =100;
float kp_min = -100;
float ki_max = 0.1;
float ki_min = -0.1;
float kd_max = 0.01;
float kd_min = -0.01;
float erro;
float erro_c;
float erro_pre = 0;
float erro_ppre = 0;
erro =Target - actual;
erro_c = erro - erro_pre;
for (int i = 0; i < 100; i++)
{
float u;
u = myfuzzypid.FuzzyPIDcontroller(e_max, e_min, ec_max, ec_min, kp_max, kp_min, erro, \
erro_c,ki_max,ki_min,kd_max,kd_min,erro_pre,erro_ppre);
actual +=u;
erro_ppre = erro_pre;
erro_pre = erro;
erro = Target - actual;
erro_c= erro - erro_pre;
std::cout << "i:" << i << "\t" << "Target:" << Target << "\t" << "Actual:" << actual << std::endl;
}
}
実行結果:
この記事は主にファジィ制御原理部分とコードルーチンを再現し、管理と収集の便宜のためにCSDNに公開します。