模糊自适应PID算法及其运用

        模糊自适应PID算法主要是由模糊控制器和PID控制器结合而成,模糊控制器以误差e和误差变化率ec作为输入,利用模糊规则对PID控制器的参数Kp、Ki、和Kd进行自适应整定,使被控对象保持在良好的动、静态稳定状态。相比传统的PID控制,模糊自适应PID更加的灵活稳定,特别是对于时变性和非线性较大的被控对象,其优点更加突出。模糊自适应PID算法及其运用_第1张图片


设计模糊自适应PID控制需要以下步骤:

1. 模糊控制规则的确定。(模糊控制规则主要可以通过专家经验和采样数据两个方面获得)

2.利用模糊规则表对e(误差)和ec(误差变化率)进行模糊化处理得出相应的隶属度。

3.利用所得出的隶属度及相应隶属度的横坐标(eg:PB、NS)带入公式求出 Kp、Ki、Kd。

公式如下:

模糊自适应PID算法及其运用_第2张图片

其中UAi(x)、UBi(y)表示求出的隶属度,Zi表示对应隶属度的横坐标(eg:PB、NS)

4.由Kp = Kp + Kp得出整定后的参数Kp、Ki、Kd,并带入PID控制器中运算。

PID公式如下:


以下为模糊自适应PID算法:

/************************************************************************************
* @author: 镜璍氺月
* @date : 2018/2/15
* @fuction name:FUZZY_PID_CONTROL
* @fuction description: 模糊自适应控制算法,为了方便测试默认e、ec在[-3,3]区间,
* 如需改变e、ec范围,需引入量化因子(Ke、Kec=N/emax)、缩放因子(Ku=umax/N)。以下代码采
*用三角隶属函数求隶属度以及加权平均法解模糊,PID采用位置式PID算法,算法仅供参考,欢迎报错。
*************************************************************************************/
#define IS_Kp 1
#define IS_Ki 2
#define IS_Kd 3

#define NL       -3
#define NM	 -2
#define NS	 -1
#define ZE	 0
#define PS	 1
#define PM	 2
#define PL	 3



static const float fuzzyRuleKp[7][7]={
	PL,	PL,	PM,	PM,	PS,	PS,	ZE,
	PL,	PL,	PM,	PM,	PS,	ZE,	ZE,
	PM,	PM,	PM,	PS,	ZE,	NS,	NM,
	PM,	PS,	PS,	ZE,	NS,	NM,	NM,
	PS,	PS,	ZE,	NS,	NS,	NM,	NM,
	ZE,	ZE,	NS,	NM,	NM,	NM,	NL,
	ZE,	NS,	NS,	NM,	NM,	NL,	NL
};

static const float fuzzyRuleKi[7][7]={
	NL,	NL,	NL,	NM,	NM,	ZE,	ZE,
	NL,	NL,	NM,	NM,	NS,	ZE,	ZE,
	NM,	NM,	NS,	NS,	ZE,	PS,	PS,
	NM,	NS,	NS,	ZE,	PS,	PS,	PM,
	NS,	NS,	ZE,	PS,	PS,	PM,	PM,
	ZE,	ZE,	PS,	PM,	PM,	PL,	PL,
	ZE,	ZE,	PS,	PM,	PL,	PL,	PL
};

static const float fuzzyRuleKd[7][7]={
	PS,	PS,	ZE,	ZE,	ZE,	PL,	PL,
	NS,	NS,	NS,	NS,	ZE,	NS,	PM,
	NL,	NL,	NM,	NS,	ZE,	PS,	PM,
	NL,	NM,	NM,	NS,	ZE,	PS,	PM,
	NL,	NM,	NS,	NS,	ZE,	PS,	PS,
	NM,	NS,	NS,	NS,	ZE,	PS,	PS,
	PS,	ZE,	ZE,	ZE,	ZE,	PL,	PL
};

typedef struct{
	float Kp;
	float Ki;
	float Kd;
}PID;






PID fuzzy(float e,float ec)
{

     float etemp,ectemp;
     float eLefttemp,ecLefttemp;
     float eRighttemp ,ecRighttemp;

     int eLeftIndex,ecLeftIndex;
     int eRightIndex,ecRightIndex;
     PID      fuzzy_PID;
     etemp = e > 3.0 ? 0.0 : (e < - 3.0 ? 0.0 : (e >= 0.0 ? (e >= 2.0 ? 2.5: (e >= 1.0 ? 1.5 : 0.5)) : (e >= -1.0 ? -0.5 : (e >= -2.0 ? -1.5 : (e >= -3.0 ? -2.5 : 0.0) ))));

     eLeftIndex = (int)e;
     eRightIndex = eLeftIndex;
     eLeftIndex = (int)((etemp-0.5) + 3);        //[-3,3] -> [0,6]
     eRightIndex = (int)((etemp+0.5) + 3);

     eLefttemp =etemp == 0.0 ? 0.0:((etemp+0.5)-e);
     eRighttemp=etemp == 0.0 ? 0.0:( e-(etemp-0.5));

     ectemp = ec > 3.0 ? 0.0 : (ec < - 3.0 ? 0.0 : (ec >= 0.0 ? (ec >= 2.0 ? 2.5: (ec >= 1.0 ? 1.5 : 0.5)) : (ec >= -1.0 ? -0.5 : (ec >= -2.0 ? -1.5 : (ec >= -3.0 ? -2.5 : 0.0) ))));

     ecLeftIndex = (int)((ectemp-0.5) + 3);        //[-3,3] -> [0,6]
     ecRightIndex = (int)((ectemp+0.5) + 3);

     ecLefttemp =ectemp == 0.0 ? 0.0:((ectemp+0.5)-ec);
     ecRighttemp=ectemp == 0.0 ? 0.0:( ec-(ectemp-0.5));

/*************************************反模糊*************************************/




	fuzzy_PID.Kp = (eLefttemp * ecLefttemp *  fuzzyRuleKp[ecLeftIndex][eLeftIndex]                    
					+ eLefttemp * ecRighttemp * fuzzyRuleKp[ecRightIndex][eLeftIndex]
					+ eRighttemp * ecLefttemp * fuzzyRuleKp[ecLeftIndex][eRightIndex]
					+ eRighttemp * ecRighttemp * fuzzyRuleKp[ecRightIndex][eRightIndex]);

	fuzzy_PID.Ki =   (eLefttemp * ecLefttemp * fuzzyRuleKi[ecLeftIndex][eLeftIndex]
					+ eLefttemp * ecRighttemp * fuzzyRuleKi[ecRightIndex][eLeftIndex]
					+ eRighttemp * ecLefttemp * fuzzyRuleKi[ecLeftIndex][eRightIndex]
					+ eRighttemp * ecRighttemp * fuzzyRuleKi[ecRightIndex][eRightIndex]);

	fuzzy_PID.Kd = (eLefttemp * ecLefttemp *    fuzzyRuleKd[ecLeftIndex][eLeftIndex]
					+ eLefttemp * ecRighttemp * fuzzyRuleKd[ecRightIndex][eLeftIndex]
					+ eRighttemp * ecLefttemp * fuzzyRuleKd[ecLeftIndex][eRightIndex]
					+ eRighttemp * ecRighttemp * fuzzyRuleKd[ecRightIndex][eRightIndex]);
return fuzzy_PID;

}


float speed_pid()
{
        float tar = 0,cur = 0;                //目标值 , 实际值
	static PID pid= {0, 0, 0};      //赋予初值kp,ki,kd
	static int sumE = 0;                   //累加偏差
	static int lastE = 0;

	PID OUT = {0, 0, 0};
	float e = -1,ec = -2.6;



	e = tar - cur;             //目标值 - 实际值
	ec = e - lastE;            //误差变化率
	sumE += e;
	lastE = e;
	OUT = fuzzy(e, ec);      //模糊控制调整  kp,ki,kd

	return (pid.Kp+OUT.Kp)*e + (pid.Kd+OUT.Kd)*ec + (pid.Ki+OUT.Ki)*sumE;
}
可直接应用于对象,需要传入传感器的值于speed_pid()的cur,并更改tar值,赋值pid初始参数。
static PID pid= {0, 0, 0};    //需要自己赋值


你可能感兴趣的:(控制算法)