模糊PID控制算法的C++实现

2023-05-16

很久没有更新博客了,今天就来讲讲模糊PID的C++实现方法。先来看一下整体的框架:
模糊PID的整体框架

解释下上面框图的意思,模糊PID其实是在普通PID的基础之上,通过输入的两个变量:误差和误差的变化率的情况来动态的调整PID控制器的三个重要的参数Kp,Ki,Kd。从而使得控制器的性能达到最优。这里的PID参数的整定,使用的是增量的方式,这样可以避免过大的误差,提高整定的精度。
所使用的模糊控制器的设计方法与普通的模糊控制器设计是一样的,具体为:首先,确定模糊控制器的输入为二维输入,即把误差和误差的变化率作为模糊控制器的输入,实际设计时也可以设计成三维或者是其他的输入形式;模糊控制器的输出为PID参数的增量值,分别为kp’, ki’, kd’;
则PID的参数为:
Kp(n)=Kp(n-1)+kp’;
Ki(n)=Ki(n-1)+Ki’;
Kd(n)=Kd(n-1)+kd’;
然后对模糊控制器的输入变量和输出变量划分模糊区间,这里为了模糊控制器设计的简单起见将它们都映射到[-3,3]区间上,统一划分的区间为{-3,-2,-1,0,1,2,3}即为{NB,NM,NS,ZO,PS,PM,PB};确定隶属度函数的形式,常用的隶属度函数类型有三角形隶属度函数,梯形隶属度函数,钟形隶属度函数,正态分布隶属度函数,根据控制对象的需要选择适当的隶属度函数;这里选择的是三角型隶属度函数,因为它形式简单,计算量小,便于在微控制器上实现。隶属度函数下图所示:
隶属度函数
接下来是设计模糊控制器的关键,确定模糊规则,根据前人的大量研究,模糊PID的模糊控制规则一般采用如下的形式,这也是我看过的论文中普遍选择的方式。可能有的控制对象比较特殊需要做一些调整。模糊规则如下:
这里写图片描述
这里写图片描述
这里写图片描述
有了这些规则就完成了模糊控制器的核心设计,然后就需要确定去模糊的方法,还是使用老的办法,加权平均法计算输出值,公式如下:
这里写图片描述
该公式的解释任意一篇关于模糊控制的论文都可以找到,不在赘述。
由以上的描述可以,模糊PID只是使用模糊控制方法来调整PID的参数,从而实现简单的自适应控制,与普通的模糊控制原理并无不同。
需要注意的是:模糊PID一般需要一个比较接近理想控制效果的PID参数初始值,否则,效果并不理想。
了解了模糊PID的控制原理,然后开始编写C++代码,并不是什么难事。这里采用的是C++面向对象的编程思想,设计一个fuzzy_pid类,需要使用时,只需要实例化这个类即可得到一个fuzzy_pid对象,然后调用它的方法就可以实现模糊PID控制,是不是感觉很酷炫;不多说了,直接看代码:
首先是设计fuzzy_pid类的接口;

class FuzzyPID
{
public:
	const static int N=7;
private:
	float target;  //系统的控制目标
	float actual;  //采样获得的实际值
	float e;       //误差
	float e_pre_1; //上一次的误差
	float e_pre_2; //上上次的误差
	float de;      //误差的变化率
	float emax;    //误差基本论域上限
	float demax;   //误差辩化率基本论域的上限
	float delta_Kp_max;   //delta_kp输出的上限
	float delta_Ki_max;   //delta_ki输出上限
	float delta_Kd_max;   //delta_kd输出上限
	float Ke;      //Ke=n/emax,量化论域为[-3,-2,-1,0,1,2,3]
	float Kde;     //Kde=n/demax,量化论域为[-3,-2,-1,0,1,2,3]
	float Ku_p;    //Ku_p=Kpmax/n,量化论域为[-3,-2,-1,0,1,2,3]
	float Ku_i;    //Ku_i=Kimax/n,量化论域为[-3,-2,-1,0,1,2,3]
	float Ku_d;    //Ku_d=Kdmax/n,量化论域为[-3,-2,-1,0,1,2,3]
	int Kp_rule_matrix[N][N];//Kp模糊规则矩阵
	int Ki_rule_matrix[N][N];//Ki模糊规则矩阵
	int Kd_rule_matrix[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的隶属度函数类型
	float *e_mf_paras; //误差的隶属度函数的参数
	float *de_mf_paras;//误差的偏差隶属度函数的参数
	float *Kp_mf_paras; //kp的隶属度函数的参数
	float *Ki_mf_paras; //ki的隶属度函数的参数
	float *Kd_mf_paras; //kd的隶属度函数的参数
	float Kp;
	float Ki;
	float Kd;
	float A;
	float B;
	float C;
void showMf(const string & type,float *mf_paras);      //显示隶属度函数的信息
void setMf_sub(const string & type,float *paras,int n);//设置模糊隶属度函数的子函数
public:
FuzzyPID(float e_max,float de_max,float kp_max,float ki_max,float kd_max,float Kp0,float Ki0,float Kd0);
FuzzyPID(float *fuzzyLimit,float *pidInitVal);
~FuzzyPID();
float trimf(float x,float a,float b,float c);          //三角隶属度函数
float gaussmf(float x,float ave,float sigma);          //正态隶属度函数
float trapmf(float x,float a,float b,float c,float d); //梯形隶属度函数
void setMf(const string & mf_type_e,float *e_mf,
			   const string & mf_type_de,float *de_mf,
			   const string & mf_type_Kp,float *Kp_mf,
		       const string & mf_type_Ki,float *Ki_mf,
			   const string & mf_type_Kd,float *Kd_mf);	//设置模糊隶属度函数的参数
void setRuleMatrix(int kp_m[N][N],int ki_m[N][N],int kd_m[N][N]);  //设置模糊规则
float realize(float t,float a);  //实现模糊控制
void showInfo();   //显示该模糊控制器的信息
};

然后是fuzzy_pid类的实现方法:


#include"fuzzy_PID.h"


FuzzyPID::FuzzyPID(float e_max,float de_max,float kp_max,float ki_max,float kd_max,float Kp0,float Ki0,float Kd0):
target(0),actual(0),emax(e_max),demax(de_max),delta_Kp_max(kp_max),delta_Ki_max(ki_max),delta_Kd_max(kd_max),e_mf_paras(NULL),de_mf_paras(NULL),
Kp_mf_paras(NULL),Ki_mf_paras(NULL),Kd_mf_paras(NULL)
{
   e=target-actual;
   e_pre_1=0;
   e_pre_2=0;
   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);
   mf_t_e="No type";
   mf_t_de="No type";
   mf_t_Kp="No type";
   mf_t_Ki="No type";
   mf_t_Kd="No type";
   Kp=Kp0;
   Ki=Ki0;
   Kd=Kd0;
   A=Kp+Ki+Kd;
   B=-2*Kd-Kp;
   C=Kd;
}

FuzzyPID::FuzzyPID(float *fuzzyLimit,float *pidInitVal)
{
	target=0;
	actual=0;
	e=0;
	e_pre_1=0;
    e_pre_2=0;
    de=e-e_pre_1;
	emax=fuzzyLimit[0];
	demax=fuzzyLimit[1];
	delta_Kp_max=fuzzyLimit[2];
	delta_Ki_max=fuzzyLimit[3];
	delta_Kd_max=fuzzyLimit[4];
	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);
    mf_t_e="No type";
    mf_t_de="No type";
    mf_t_Kp="No type";
    mf_t_Ki="No type";
    mf_t_Kd="No type";
	e_mf_paras=NULL;
	de_mf_paras=NULL;
	Kp_mf_paras=NULL;
	Ki_mf_paras=NULL;
	Kd_mf_paras=NULL;

    Kp=pidInitVal[0];
    Ki=pidInitVal[1];
    Kd=pidInitVal[2];
    A=Kp+Ki+Kd;
    B=-2*Kd-Kp;
    C=Kd;
}

FuzzyPID::~FuzzyPID()
{
  delete [] e_mf_paras;
  delete [] de_mf_paras;
  delete [] Kp_mf_paras;
  delete [] Ki_mf_paras;
  delete [] Kd_mf_paras;
}
//三角隶属度函数
float FuzzyPID::trimf(float x,float a,float b,float c)
{
   float 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.0;
   return u;

}
//正态隶属度函数
float FuzzyPID::gaussmf(float x,float ave,float sigma) 
{
	float u;
	if(sigma<0)
	{
	   cout<<"In gaussmf, sigma must larger than 0"<<endl;
	}
	u=exp(-pow(((x-ave)/sigma),2));
	return u;
}
//梯形隶属度函数
float FuzzyPID::trapmf(float x,float a,float b,float c,float d)
{
    float 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
void FuzzyPID::setRuleMatrix(int kp_m[N][N],int ki_m[N][N],int kd_m[N][N])
{
	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 FuzzyPID::setMf_sub(const string & type,float *paras,int n)
{
	int N_mf_e,N_mf_de,N_mf_Kp,N_mf_Ki,N_mf_Kd;
  switch(n)
  {
  case 0:
	  if(type=="trimf"||type=="gaussmf"||type=="trapmf")
	    mf_t_e=type;
	  else
		cout<<"Type of membership function must be \"trimf\" or \"gaussmf\" or \"trapmf\""<<endl;
      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=new float [N*N_mf_e];
	  for(int i=0;i<N*N_mf_e;i++)
		e_mf_paras[i]=paras[i];
	  break;

  case 1:
	  if(type=="trimf"||type=="gaussmf"||type=="trapmf")
	    mf_t_de=type;
	  else
		cout<<"Type of membership function must be \"trimf\" or \"gaussmf\" or \"trapmf\""<<endl;
      if(mf_t_de=="trimf")
        N_mf_de=3;
	  else if(mf_t_de=="gaussmf")
		N_mf_de=2;
	  else if(mf_t_de=="trapmf")
		N_mf_de=4;
        de_mf_paras=new float [N*N_mf_de];
	  for(int i=0;i<N*N_mf_de;i++)
		de_mf_paras[i]=paras[i];
	  break;

   case 2:
	  if(type=="trimf"||type=="gaussmf"||type=="trapmf")
	    mf_t_Kp=type;
	  else
		cout<<"Type of membership function must be \"trimf\" or \"gaussmf\" or \"trapmf\""<<endl;
      if(mf_t_Kp=="trimf")
        N_mf_Kp=3;
	  else if(mf_t_Kp=="gaussmf")
		N_mf_Kp=2;
	  else if(mf_t_Kp=="trapmf")
		N_mf_Kp=4;
        Kp_mf_paras=new float [N*N_mf_Kp];
	  for(int i=0;i<N*N_mf_Kp;i++)
		Kp_mf_paras[i]=paras[i];
	  break;

   case 3:
	  if(type=="trimf"||type=="gaussmf"||type=="trapmf")
	    mf_t_Ki=type;
	  else
		cout<<"Type of membership function must be \"trimf\" or \"gaussmf\" or \"trapmf\""<<endl;
      if(mf_t_Ki=="trimf")
        N_mf_Ki=3;
	  else if(mf_t_Ki=="gaussmf")
		N_mf_Ki=2;
	  else if(mf_t_Ki=="trapmf")
		N_mf_Ki=4;
        Ki_mf_paras=new float [N*N_mf_Ki];
	  for(int i=0;i<N*N_mf_Ki;i++)
		Ki_mf_paras[i]=paras[i];
	  break;

   case 4:
	  if(type=="trimf"||type=="gaussmf"||type=="trapmf")
	    mf_t_Kd=type;
	  else
		cout<<"Type of membership function must be \"trimf\" or \"gaussmf\" or \"trapmf\""<<endl;
      if(mf_t_Kd=="trimf")
        N_mf_Kd=3;
	  else if(mf_t_Kd=="gaussmf")
		N_mf_Kd=2;
	  else if(mf_t_Kd=="trapmf")
		N_mf_Kd=4;
        Kd_mf_paras=new float [N*N_mf_Kd];
	  for(int i=0;i<N*N_mf_Kd;i++)
		Kd_mf_paras[i]=paras[i];
	  break;

   default: break;
  }
}
//设置模糊隶属度函数的类型和参数
void FuzzyPID::setMf(const string & mf_type_e,float *e_mf,
			const string & mf_type_de,float *de_mf,
			const string & mf_type_Kp,float *Kp_mf,
		    const string & mf_type_Ki,float *Ki_mf,
			const string & mf_type_Kd,float *Kd_mf)
{
	setMf_sub(mf_type_e,e_mf,0);
	setMf_sub(mf_type_de,de_mf,1);
	setMf_sub(mf_type_Kp,Kp_mf,2);
	setMf_sub(mf_type_Ki,Ki_mf,3);
	setMf_sub(mf_type_Kd,Kd_mf,4);
}
//实现模糊控制
float FuzzyPID::realize(float t,float a)   
{
	float u_e[N],u_de[N],u_u[N];
	int u_e_index[3],u_de_index[3];//假设一个输入最多激活3个模糊子集
	float delta_Kp,delta_Ki,delta_Kd;
	float delta_u;
	target=t;
	actual=a;
    e=target-actual;
	de=e-e_pre_1;
	e=Ke*e;
	de=Kde*de;
  /* 将误差e模糊化*/
	int j=0;
	for(int i=0;i<N;i++)
	{
		if(mf_t_e=="trimf")
		  u_e[i]=trimf(e,e_mf_paras[i*3],e_mf_paras[i*3+1],e_mf_paras[i*3+2]);//e模糊化,计算它的隶属度
		else if(mf_t_e=="gaussmf")
		  u_e[i]=gaussmf(e,e_mf_paras[i*2],e_mf_paras[i*2+1]);//e模糊化,计算它的隶属度
		else if(mf_t_e=="trapmf")
		  u_e[i]=trapmf(e,e_mf_paras[i*4],e_mf_paras[i*4+1],e_mf_paras[i*4+2],e_mf_paras[i*4+3]);//e模糊化,计算它的隶属度

		if(u_e[i]!=0)
            u_e_index[j++]=i;                //存储被激活的模糊子集的下标,可以减小计算量
  	}
	for(;j<3;j++)u_e_index[j]=0;             //富余的空间填0

	/*将误差变化率de模糊化*/
	j=0;
	for(int i=0;i<N;i++)
	{
		if(mf_t_de=="trimf")
		   u_de[i]=trimf(de,de_mf_paras[i*3],de_mf_paras[i*3+1],de_mf_paras[i*3+2]);//de模糊化,计算它的隶属度
		else if(mf_t_de=="gaussmf")
		   u_de[i]=gaussmf(de,de_mf_paras[i*2],de_mf_paras[i*2+1]);//de模糊化,计算它的隶属度
		else if(mf_t_de=="trapmf")
		   u_de[i]=trapmf(de,de_mf_paras[i*4],de_mf_paras[i*4+1],de_mf_paras[i*4+2],de_mf_paras[i*4+3]);//de模糊化,计算它的隶属度

		if(u_de[i]!=0)
			u_de_index[j++]=i;            //存储被激活的模糊子集的下标,可以减小计算量
	}
	for(;j<3;j++)u_de_index[j]=0;          //富余的空间填0

	float den=0,num=0;
	/*计算delta_Kp和Kp*/
	for(int m=0;m<3;m++)
		for(int n=0;n<3;n++)
		{
		   num+=u_e[u_e_index[m]]*u_de[u_de_index[n]]*Kp_rule_matrix[u_e_index[m]][u_de_index[n]];
		   den+=u_e[u_e_index[m]]*u_de[u_de_index[n]];
		}
	delta_Kp=num/den;
	delta_Kp=Ku_p*delta_Kp;
	if(delta_Kp>=delta_Kp_max)   delta_Kp=delta_Kp_max;
	else if(delta_Kp<=-delta_Kp_max) delta_Kp=-delta_Kp_max;
	Kp+=delta_Kp;
	if(Kp<0)Kp=0;
	/*计算delta_Ki和Ki*/
	den=0;num=0;
	for(int m=0;m<3;m++)
		for(int n=0;n<3;n++)
		{
		   num+=u_e[u_e_index[m]]*u_de[u_de_index[n]]*Ki_rule_matrix[u_e_index[m]][u_de_index[n]];
		   den+=u_e[u_e_index[m]]*u_de[u_de_index[n]];
		}

	delta_Ki=num/den;
	delta_Ki=Ku_i*delta_Ki;
	if(delta_Ki>=delta_Ki_max)   delta_Ki=delta_Ki_max;
	else if(delta_Ki<=-delta_Ki_max)  delta_Ki=-delta_Ki_max;
	Ki+=delta_Ki;
	if(Ki<0)Ki=0;
	/*计算delta_Kd和Kd*/
	den=0;num=0;
	for(int m=0;m<3;m++)
		for(int n=0;n<3;n++)
		{
		   num+=u_e[u_e_index[m]]*u_de[u_de_index[n]]*Kd_rule_matrix[u_e_index[m]][u_de_index[n]];
		   den+=u_e[u_e_index[m]]*u_de[u_de_index[n]];
		}
	delta_Kd=num/den;
	delta_Kd=Ku_d*delta_Kd;
	if(delta_Kd>=delta_Kd_max)   delta_Kd=delta_Kd_max;
	else if(delta_Kd<=-delta_Kd_max) delta_Kd=-delta_Kd_max;
	Kd+=delta_Kd;
	if(Kd<0)Kd=0;

	A=Kp+Ki+Kd;
    B=-2*Kd-Kp;
    C=Kd;
	delta_u=A*e+B*e_pre_1+C*e_pre_2;

	delta_u=delta_u/Ke;
  
	if(delta_u>=0.95*target)delta_u=0.95*target;
	else if(delta_u<=-0.95*target)delta_u=-0.95*target;

	e_pre_2=e_pre_1;
    e_pre_1=e;

	return delta_u;
}
void FuzzyPID::showMf(const string & type,float *mf_paras)
{
    int tab;
	if(type=="trimf")
		tab=2;
	else if(type=="gaussmf")
		tab==1;
	else if(type=="trapmf")
		tab=3;
	cout<<"函数类型:"<<mf_t_e<<endl;
	cout<<"函数参数列表:"<<endl;
	float *p=mf_paras;
	for(int i=0;i<N*(tab+1);i++)
	  {
		  cout.width(3);
	      cout<<p[i]<<"  ";
		  if(i%(tab+1)==tab)
			  cout<<endl;
	  }
}
void FuzzyPID::showInfo()
{
   cout<<"Info of this fuzzy controller is as following:"<<endl;
   cout<<"基本论域e:["<<-emax<<","<<emax<<"]"<<endl;
   cout<<"基本论域de:["<<-demax<<","<<demax<<"]"<<endl;
   cout<<"基本论域delta_Kp:["<<-delta_Kp_max<<","<<delta_Kp_max<<"]"<<endl;
   cout<<"基本论域delta_Ki:["<<-delta_Ki_max<<","<<delta_Ki_max<<"]"<<endl;
   cout<<"基本论域delta_Kd:["<<-delta_Kd_max<<","<<delta_Kd_max<<"]"<<endl;
   cout<<"误差e的模糊隶属度函数参数:"<<endl;
   showMf(mf_t_e,e_mf_paras);
   cout<<"误差变化率de的模糊隶属度函数参数:"<<endl;
   showMf(mf_t_de,de_mf_paras);
   cout<<"delta_Kp的模糊隶属度函数参数:"<<endl;
   showMf(mf_t_Kp,Kp_mf_paras);
   cout<<"delta_Ki的模糊隶属度函数参数:"<<endl;
   showMf(mf_t_Ki,Ki_mf_paras);
   cout<<"delta_Kd的模糊隶属度函数参数:"<<endl;
   showMf(mf_t_Kd,Kd_mf_paras);
   cout<<"模糊规则表:"<<endl;
   cout<<"delta_Kp的模糊规则矩阵"<<endl;
   for(int i=0;i<N;i++)
   {
	 for(int j=0;j<N;j++)
	   {
		 cout.width(3);
		 cout<<Kp_rule_matrix[i][j]<<"  ";
	    }
	   cout<<endl;
   }
   cout<<"delta_Ki的模糊规则矩阵"<<endl;
   for(int i=0;i<N;i++)
   {
	 for(int j=0;j<N;j++)
	   {
		 cout.width(3);
		 cout<<Ki_rule_matrix[i][j]<<"  ";
	    }
	   cout<<endl;
   }
   cout<<"delta_Kd的模糊规则矩阵"<<endl;
   for(int i=0;i<N;i++)
   {
	 for(int j=0;j<N;j++)
	   {
		 cout.width(3);
		 cout<<Kd_rule_matrix[i][j]<<"  ";
	    }
	   cout<<endl;
   }
   cout<<endl;
   cout<<"误差的量化比例因子Ke="<<Ke<<endl;
   cout<<"误差变化率的量化比例因子Kde="<<Kde<<endl;
   cout<<"输出的量化比例因子Ku_p="<<Ku_p<<endl;
   cout<<"输出的量化比例因子Ku_i="<<Ku_i<<endl;
   cout<<"输出的量化比例因子Ku_d="<<Ku_d<<endl;
   cout<<"设定目标target="<<target<<endl;
   cout<<"误差e="<<e<<endl;
   cout<<"Kp="<<Kp<<endl;
   cout<<"Ki="<<Ki<<endl;
   cout<<"Kd="<<Kd<<endl;
   cout<<endl;
}

之后是简单的测试:

#include<iostream>
#include"fuzzy_PID.h"

#define NB -3
#define NM -2
#define NS -1
#define ZO 0
#define PS 1
#define PM 2
#define PB 3

int main()
{
	float target=600;
	float actual=0;
	float u=0;
	int deltaKpMatrix[7][7]={{PB,PB,PM,PM,PS,ZO,ZO},
	                         {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 deltaKiMatrix[7][7]={{NB,NB,NM,NM,NS,ZO,ZO},
	                         {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 deltaKdMatrix[7][7]={{PS,NS,NB,NB,NB,NM,PS},
	                         {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}};
	float e_mf_paras[]={-3,-3,-2,-3,-2,-1,-2,-1,0,-1,0,1,0,1,2,1,2,3,2,3,3};
	float de_mf_paras[]={-3,-3,-2,-3,-2,-1,-2,-1,0,-1,0,1,0,1,2,1,2,3,2,3,3};
	float Kp_mf_paras[]={-3,-3,-2,-3,-2,-1,-2,-1,0,-1,0,1,0,1,2,1,2,3,2,3,3};
	float Ki_mf_paras[]={-3,-3,-2,-3,-2,-1,-2,-1,0,-1,0,1,0,1,2,1,2,3,2,3,3};
	float Kd_mf_paras[]={-3,-3,-2,-3,-2,-1,-2,-1,0,-1,0,1,0,1,2,1,2,3,2,3,3};
    FuzzyPID fuzzypid(1500,650,0.3,0.9,0.6,0.01,0.04,0.01);
	fuzzypid.setMf("trimf",e_mf_paras,"trimf",de_mf_paras,"trimf",Kp_mf_paras,"trimf",Ki_mf_paras,"trimf",Kd_mf_paras);
	fuzzypid.setRuleMatrix(deltaKpMatrix,deltaKiMatrix,deltaKdMatrix);
	cout<<"num target    actual"<<endl;
	/*fuzzy.showInfo();*/
	for(int i=0;i<50;i++)
	{
		u=fuzzypid.realize(target,actual);
		actual+=u;
		cout<<i<<"   "<<target<<"    "<<actual<<endl;
	}
	fuzzypid.showInfo();
	system("pause");
	return 0;
}

OK,完工,有不明白的欢迎交流!
代码已经上传至CSDN,需要参考的朋友可以下载看看:
https://download.csdn.net/download/shuoyueqishilove/10433941

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

模糊PID控制算法的C++实现 的相关文章

  • 单相Boost功率因数校正电路(PFC)设计与仿真(Simulink & Saber):第一章 PFC基础知识与电路参数设计

    写在前面 教程是根据Mathworks公司的有源功率因数校正教程 点这里跳转 和那日沙等老师编著的 电力电子 电机控制系统的建模及仿真 改写的 设计思路基本与之一致 嫌看文章麻烦的同学可以直接跳转看视频和查阅相关书籍 Simulink仿真部
  • 电机控制进阶——PID速度控制

    之前的几篇文章 电机控制基础篇 介绍的电机编码器原理 定时器输出PWM 定时器编码器模式测速等 本篇在前几篇的基础上 继续来学习电机控制 通过PID算法 来进行电机的速度控制 并进行实验测试 PID基础 PID即 Proportional
  • 端口被占用怎么办?关闭占用端口的进程

    当你发现某个端口被占用时 但不知道是哪一个进程占用了端口 需要关闭占用该端口的进程 1 启动系统命令行 windows系统 win r 2 输入命令 netstat ano 可查看所有端口的使用情况 netstat aon findstr
  • PID稳压

    思路说明 我们设置一个目标值 这是我们要调节的目标 我们通过AD采样 PC3 采集到当前电压 通过减法运算我们得出当前电压与目标电压的差值 接下来我们只要发现当前电压与目标电压不同 我们就要想办法改变当前单片机的输出电压 PA8 也就是当前
  • 电机调速(PID算法)(程序原理图全套资料)

    要求 设计一个基于改变PWM信号占空比来实现直流电动机转速控制的系统 满足控制指标要求 思维导图如下 最终设计的成果为 测速使用霍尔传感器 然后霍尔传感器感应的是使用高强度的磁铁 淘宝上面有买 电机驱动用现成的L9110模块 显示直接用OL
  • 基于LabVIEW的PID算法解读

    记录一下 方便以后翻阅 下图是基本的PID算法实现方式 以及实现PID控制器所需的假设和转换 为实现PID控制器 LabVIEW要求算法对输入信号进行采样并离散积分和微分操作 一 误差计算 e k SP k PV k 上式中 e k 表示当
  • PID自控理论(频域bode图理论分析)

    PID 迟后超前矫正 临界比例度法整定PID 在低频区 主要是PI控制器起作用 用以提高系统型别消除或减小稳态误差 在中 高频区 主要是PD控制器起作用 用以增大幅值穿越频率和相位裕度 提高系统的响应速度 因此 PID控制器可以全面地提高系
  • PID整定之临界比例度法

    概述 在闭环的控制系统中 激励为阶跃信号 将调节器置于纯比例作用下 从小到大逐渐改变调节器比例度的大小 直到出现等幅振荡的过渡过程 此时的比例度称为临界比例度 r 1 K p 相邻两个波峰间的距离称为临界振荡周期T r 比例增益K Pr 图
  • 深入浅出PID控制算法(二)————PID算法离散化和增量式PID算法原理及Matlab实现

    引言 上篇介绍了连续系统的PID算法 但是计算机控制是一种采样控制 他只能根据采样时刻的偏差来计算控制量 因此计算机控制系统中 必须对公式进行离散化 具体就是用求和代替积分 用向后差分来代替微分 使模拟PID离散化为数字形式的差分方程 准备
  • 什么是死区时间

    死区时间是PWM输出时 为了使H桥或半H桥的上下管不会因为开关的关断延迟问题发生同时导通而设置的一个保护时段 通常也指pwm响应时间 由于IGBT 绝缘栅极型功率管 等功率器件都存在一定的结电容 所以会造成器件导通关断的延迟现象 一般在设计
  • 进程组必须有一个正在运行的领导进程吗?

    在类 Unix 操作系统中 如果一个进程 pid和它的pgid相等 则该进程是进程组的领导者 但是 如果进程领导者已经退出 并且同组中的其他进程仍在运行 那么谁是继任的领导者进程 没有继任领导者 一旦流程组领导者退出 该组就失去了领导权 没
  • docker和主机之间的PID映射

    docker 命名空间与主机命名空间有何不同以及 pid 如何在这两者之间映射 谁能给我一个想法 有助于使用源代码在主机和 docker 之间映射 pid 的简单方法 您可以在中找到映射 proc PID status文件 它包含这样一行
  • 如何在 OSX 10.9 中从 ProcessSerialNum 获取 PID?

    GetProcessPID在 OSX 10 9 中被标记为已弃用 并附有注释 使用适当的 processIdentifier 属性 NSRunningApplication 对象 问题是构造类方法NSRunningApplication没有
  • 子进程和父进程ID

    只是与子进程块中的父 pid 值混淆了 我的程序如下 int main int argc char argv pid t pid pid fork if pid 1 perror fork failure exit EXIT FAILURE
  • Ubuntu Java:查找特定程序的 pid 并终止该程序

    我正在尝试创建一个应用程序来检查此特定应用程序是否正在运行 然后在指定的时间后终止该应用程序 我打算获取应用程序的 pid 如何获取应用程序的 pid Thanks 你可以尝试ps aux grep foobar获取 pid 然后发出kil
  • Bash:是否可以阻止 PID 被重复使用?

    是否可以阻止 PID 被重复使用 例如 如果我运行一份工作myjob在背景中myjob 并使用获取PIDPID 是否可以阻止 linux 系统重新使用该 PID 直到我检查该 PID 不再存在 进程已完成 换句话说 我想做类似的事情 myj
  • fork()返回0,但是子进程getpid()!=0。为什么?

    这是测试 fork 系统调用的 C 代码 include
  • 查看用户最近执行的Android任务

    我想查看我的 Android 手机最近的任务 我尝试了一些来自互联网的代码 但没有一个能正常工作 我只想获取用户最后执行的应用程序的PID和名称 例如 如果我执行计算器应用程序 然后执行我创建的最近任务应用程序 则该应用程序应该能够告诉我类
  • 在 python 中,是否有跨平台的方法来确定哪个进程正在侦听给定端口?

    在linux下 我可以使用lsof i如以下函数所示 def FindProcessUsingPort portnum import os fp os popen lsof i s portnum lines fp readlines fp
  • Process.start() 启动的进程返回错误的进程 ID?

    我正在使用以下代码启动可执行文件 Process proc new Process proc StartInfo FileName executablePath proc Start proc WaitForInputIdle 在这次通话之

随机推荐

  • games系列学习 -- Möller Trumbore 算法

    M ller Trumbore 算法 是三角形与射线 光线 之间判定是否相交的快速算法 利用了重心坐标来表示三角形 首先假设射线的方程 xff1a O为发射点 D为方向向量 再假设三角形平面方程 xff1a b1 b2 1 b1 b2 分别
  • 使用手机摄像头实现视频监控实时播放

    使用手机摄像头实现视频监控实时播放 一 概述 视频监控实时播放的原理与目前较为流行的直播是一致的 xff0c 所以采用直播的架构实现视频监控实时播放 xff0c 流程图如下 xff1a
  • 滑模观测器

    什么是滑模观测器 1 滑模观测器是一类动态系统 2 滑模观测器是指根据系统的外部变量 输入变量和输出变量 的实测值得出状态变量估计值的一类动态系统 xff0c 也称为状态重构器 3 作用 xff1a xff08 1 xff09 滑模观测器不
  • ROS入门_1.18 接下来做什么?

    此时你应该已经对ROS中的一些核心概念有了一定的理解 给你一台运行ROS的机器人 xff0c 你应该能够运用所学知识来列出机器人上发布和订阅的各种话题 xff08 topic xff09 xff0c 查看话题中发布的消息 xff0c 然后编
  • 【git】看懂git diff

    git diff 可以用来比较 xff1a 1 staging area和working area的文件 xff08 无其他参数时 xff09 plain view plain copy print git diff 2 master分支和
  • makefile 自动编译同一个目录下的所有文件

    SOURCE 61 wildcard c OBJS 61 patsubst c o SOURCE CROSS COMPILE 61 arm linux CXX 61 gcc CFLAGS 43 61 static CLFAGS 43 61
  • PX4_Bootloader单步调试配置(STM32F7 配置)

    Bootloader Makefile 编译选项 Os g 43 O0 43 ggdb3 Bootloader libopencm3 lib stm32 f7 Makefile TGT CFLAGS 61 Os g 43 TGT CFLAG
  • 2021北邮自考c++实践题及答案

    北邮c 43 43 实践考期 xff0c 只能在每年的下半年进行报名 xff0c 11月进行考试 由于疫情原因 xff0c 现在均为线上考试 xff0c 每人的考题不同 xff0c 但是大同小异 xff0c 此为2021年的c 43 43
  • 从idea推送代码到github,到jenkins部署,再到从github下载代码完成构建的全部详细操作流程

    目录 1 idea推送代码到github 1 1 github创建 1 2 git下载与安装 xff08 windows xff09 1 3 idea关联github 1 3 1 windows生成公私钥 1 3 2 idea关联githu
  • Jmeter常用场景梳理

    一 在一段时间内持续发送请求 此场景可以用于稳定性测试 xff0c 在稳定性测试中 xff0c 通常需要持续压测几个小时甚至几天时间 xff0c 查看接口是否有报错 xff0c 或者cpu 内存会上涨 xff0c 此时就需要通过控制持续时间
  • vnc viewer连不上,vnc viewer连不上是什么原因?解决方法

    vnc viewer连不上是什么原因 接下来尝试在CentOS上安装一个VNC Server CentOS5 已经自带了VNC xff0c 默认也已经安装了 xff0c 只要配置一下就可以了 如果没有安装 xff0c 可以 yum inst
  • 基于netty框架的JTT808/JTT905/JTT1078协议客户端

    基于netty框架的JTT808 JTT905 JTT1078协议客户端 JTT808客户端网络处理 span class token keyword private span span class token keyword void s
  • The BMJ研究:现有的新冠病毒诊断AI模型,几乎毫无用处

    图片出处 xff1a unsplash 本文作者 xff1a 朱演瑞 新型冠状病毒对全球健康造成了严重的威胁 xff0c 为了减轻医疗保健系统的负担 xff0c 也给患者提供最佳的护理 xff0c 高效的诊断和疾病预后信息问题亟待解决 理论
  • 自动驾驶多传感器融合

    12月28日 xff0c 百度Apollo平台携手国内激光雷达公司禾赛科技扔下一颗名为Pandora的重磅炸弹 xff0c 此举将极大地加快无人驾驶落地的进程 xff0c 却也会让不少自动驾驶初创公司陷入无比尴尬的境地 简单地说 xff0c
  • YMFC-32 小四轴 (一)

    https github com jamesshao8 ymfc mini drone 本博客前几天送出了几个v1 0版本的ymfc小四轴 在这里我要说一下组装教程和使用方法 原材料采购 除了我的板子以外还需要一些零件 1 间距0 254的
  • HackRF 代码讲解 (一)

    本文包括驱动 固件 CPLD代码讲解 xff08 也包括gr osmosdr中的相关部分 xff09 HackRF是比较早期的一款SDR设备 xff0c 凭借其相对低廉的价格加上半双工收发能力 xff0c 在国内的SDR市场中占比很高 这款
  • STM32 GPS悬停飞控 (十)气压计

    上次的飞机有干扰问题 没法解决 可能因为我的元器件有问题 或者走线问题 本来打算按老外的一模一样做一个的 但现在想直接做带GPS的了 因为除GPS 罗盘 气压 数传外基本和上次那个一样的 这些部分即使装上也可以禁用 只剩摇控不一样了 暂时忽
  • 自制嵌入式GUI 【前1-3篇】-基于freeRTOS

    自制GUI第4篇 xff1a https blog csdn net shungry article details 78659613 自制GUI第5篇 xff1a https blog csdn net shungry article d
  • 基于C++的PID控制器

    PID控制器是一种广泛用于各种工业控制场合的控制器 xff0c 它结构简单 xff0c 可以根据工程经验整定参数Kp Ki Kd 虽然现在控制专家提出了很多智能的控制算法 xff0c 比如神经网络 xff0c 模糊控制等 xff0c 但是P
  • 模糊PID控制算法的C++实现

    很久没有更新博客了 xff0c 今天就来讲讲模糊PID的C 43 43 实现方法 先来看一下整体的框架 xff1a 解释下上面框图的意思 xff0c 模糊PID其实是在普通PID的基础之上 xff0c 通过输入的两个变量 xff1a 误差和