PID算法

前言

本篇文章仅为个人笔记,不是教程
本文所参考的文章
【基础知识】PID(比例微分积分)控制
改进的PID算法
PID控制器算法系列

PID算法简单分类(改进PID之间可以结合使用)

  1. 基础PID
  • 位置式PID算法
  • 增量式PID算法
  • 带死区的PID算法
  1. 积分改进PID
  • 积分分离PID算法
  • 抗积分饱和PID算法
  • 梯形积分PID算法
  • 变速积分PID算法
  1. 微分改进PID
  • 不完全微分PID算法
  • 微分先行PID算法

连续型PID算法

输入量为rin(t),输出量为rout(t),偏差为err(t)=rin(t)-rout(t)。
U ( t ) = k p ( e r r ( t ) + 1 T I ∫ e r r ( t ) d t + T D d e r r ( t ) d t ) U(t)=k_p\bigl( err(t)+\frac 1{T_I}\int err(t)dt+ T_D\frac {derr(t)}{dt} \bigr) U(t)=kp(err(t)+TI1err(t)dt+TDdtderr(t))
其中Kp为比例带,TI为积分时间,TD为微分时间。

离散型PID算法

输入量为rin(k),输出量为rout(k),偏差为err(k)=rin(k)-rout(k)。

位置式PID算法

基本公式
U ( k ) = K p ( e r r ( k ) + T T I ∑ j = 0 k e r r ( j ) + T D T ( e r r ( k ) − e r r ( k − 1 ) ) ) U(k)=K_p \Bigl (err(k)+\frac T{T_I}\sum_{j=0}^{k} err(j)+\frac {T_ D}T\bigl (err(k)-err(k-1)\bigr ) \Bigr) U(k)=Kp(err(k)+TITj=0kerr(j)+TTD(err(k)err(k1)))
其中T为系统采样周期时间,K表示第K个采样周期。
也可以简写为:
U ( k ) = K p ∗ e r r ( k ) + K i ∑ j = 0 k e r r ( j ) + K d ∗ ( e r r ( k ) − e r r ( k − 1 ) ) U(k)=K_p*err(k)+K_i\sum_{j=0}^{k} err(j)+K_d*\big (err(k)-err(k-1)\big ) U(k)=Kperr(k)+Kij=0kerr(j)+Kd(err(k)err(k1))
简单实现

typedef struct
{
	float setpoint;			//设定值
	float proportiongain;	//比例系数
	float integralgain;		//积分系数
	float derivativegain;	//微分系数
	float lasterror;		//前一拍偏差
	float result;			//输出值
	float integral;			//积分值
}PID;
void PIDRegulation(PID *vPID, float processValue)
{
	float thisError;
	thisError=vPID->setpoint-processValue;
	vPID->integral+=thisError;
	vPID->result=vPID->proportiongain*thisError+
				 vPID->integralgain*vPID->integral+
				 vPID->derivativegain*(thisError-vPID->lasterror);
	vPID->lasterror=thisError;
}

特点

  • 位置型PID控制的输出与整个过去的状态有关,用到了偏差的累加值,容易产生累积偏差。
  • 位置型PID适用于执行机构不带积分部件的对象。
  • 位置型的输出直接对应对象的输出,对系统的影响比较大。

增量式PID算法

基本公式
Δ U ( k ) = U ( k ) − U ( k − 1 ) = K p ( e r r ( k ) − e r r ( k − 1 ) ) + K i ∗ e r r ( k ) + K d ( e r r ( k ) − 2 ∗ e r r ( k − 1 ) + e r r ( k − 2 ) ) \begin{aligned} \Delta U(k) &= U(k)-U(k-1)\\ &=K_p\big (err(k)-err(k-1)\big )\\&+K_i*err(k)\\&+K_d\big (err(k)-2*err(k-1)+err(k-2)\big) \end{aligned} ΔU(k)=U(k)U(k1)=Kp(err(k)err(k1))+Kierr(k)+Kd(err(k)2err(k1)+err(k2))
简单实现

typedef struct
{
	float setpoint;			//设定值
	float proportiongain;	//比例系数
	float integralgain;		//积分系数
	float derivativegain;	//微分系数
	float lasterror;		//前一拍偏差
	float preerror;			//前两拍偏差
	float result;			//输出值
}PID;
void PIDRegulation(PID *vPID, float processValue)
{
	float thisError;
	float increment;
	float pError,dError,iError;
	thisError=vPID->setpoint-processValue;
	pError=thisError-vPID->lasterror;
	iError=thisError;
	dError=thisError-2*(vPID->lasterror)+vPID->preerror;
	increment=vPID->proportiongain*pError+
			  vPID->integralgain*iError+
			  vPID->derivativegain*dError;
	vPID->preerror=vPID->lasterror;
	vPID->lasterror=thisError;
	vPID->result+=increment;
}

特点

  • 增量型PID算法不需要做累加,控制量增量的确定仅与最近几次偏差值有关,计算偏差的影响较小。
  • 增量型PID算法得出的是控制量的增量,对系统的影响相对较小。
  • 采用增量型PID算法易于实现手动到自动的无扰动切换。

积分分离PID算法

位置式PID算法

基本公式
U ( k ) = K p ∗ e r r ( k ) + β K i ∑ j = 0 k e r r ( j ) + K d ∗ ( e r r ( k ) − e r r ( k − 1 ) ) U(k)=K_p*err(k)+\beta K_i\sum_{j=0}^{k} err(j)+K_d*\big (err(k)-err(k-1)\big ) U(k)=Kperr(k)+βKij=0kerr(j)+Kd(err(k)err(k1))
其中β称为积分开关系数,其取值范围为:
β = { 0 ∣ e r r ( k ) ∣ > ξ 1 ∣ e r r ( k ) ∣ ≤ ξ \beta= \begin{cases} 0& \vert err(k) \vert\gt\xi\\1& \vert err(k) \vert\leq\xi\end{cases} β={01err(k)>ξerr(k)ξ
根据实际情况,设定一个阈值 ξ \xi ξ;当偏差大于阈值时,消除积分仅用PD控制;当偏差小于等于阈值时,引入积分采用PID控制。
简单实现

static uint16_t BetaGeneration(float error,float epsilon)
{
	uint16_t beta=0;
	if(abs(error)<= epsilon)
	{
		beta=1;
	}
	return beta;
}
typedef struct
{
	float setpoint;			//设定值
	float proportiongain;	//比例系数
	float integralgain;		//积分系数
	float derivativegain;	//微分系数
	float lasterror;		//前一拍偏差
	float result;			//输出值
	float integral;			//积分值
	float epsilon;			//偏差检测阈值
}PID;
void PIDRegulation(PID *vPID, float processValue)
{
	float thisError;
	thisError=vPID->setpoint-processValue;
	vPID->integral+=thisError;
	uint16_t beta=BetaGeneration(error,vPID->epsilon);
	if(beta>0)
	{
		vPID->result=vPID->proportiongain*thisError+
					 vPID->derivativegain*(thisError-vPID->lasterror);
	}
	else
	{
		vPID->result=vPID->proportiongain*thisError+
					 vPID->integralgain*vPID->integral+
					 vPID->derivativegain*(thisError-vPID->lasterror);
	}
	vPID->lasterror=thisError;
}

增量式PID算法

基本公式
Δ U ( k ) = K p ( e r r ( k ) − e r r ( k − 1 ) ) + β K i ∗ e r r ( k ) + K d ( e r r ( k ) − 2 ∗ e r r ( k − 1 ) + e r r ( k − 2 ) ) \begin{aligned} \Delta U(k) &=K_p\big (err(k)-err(k-1)\big )\\&+\beta K_i*err(k)\\&+K_d\big (err(k)-2*err(k-1)+err(k-2)\big) \end{aligned} ΔU(k)=Kp(err(k)err(k1))+βKierr(k)+Kd(err(k)2err(k1)+err(k2))
其中β称为积分开关系数,其取值范围为:
β = { 0 ∣ e r r ( k ) ∣ > ξ 1 ∣ e r r ( k ) ∣ ≤ ξ \beta= \begin{cases} 0& \vert err(k) \vert\gt\xi\\1& \vert err(k) \vert\leq\xi\end{cases} β={01err(k)>ξerr(k)ξ
简单实现

static uint16_t BetaGeneration(float error,float epsilon)
{
	uint16_t beta=0;
	if(abs(error)<= epsilon)
	{
		beta=1;
	}
	return beta;
}
typedef struct
{
	float setpoint;//设定值
	float proportiongain;//比例系数
	float integralgain;//积分系数
	float derivativegain;//微分系数
	float lasterror;//前一拍偏差
	float preerror;//前两拍偏差
	float result;//输出值
	float epsilon;//偏差检测阈值
}PID;
void PIDRegulation(PID *vPID, float processValue)
{
	float thisError;
	float increment;
	float pError,dError,iError;
	thisError=vPID->setpoint-processValue;
	pError=thisError-vPID->lasterror;
	iError=thisError;
	dError=thisError-2*(vPID->lasterror)+vPID->preerror;
	uint16_t beta=BetaGeneration(error,vPID->epsilon);
	if(beta>0)
	{
		increment=vPID->proportiongain*pError+
				  vPID->derivativegain*dError;
	}
	else
	{
		increment=vPID->proportiongain*pError+
				  vPID->integralgain*iError+
				  vPID->derivativegain*dError;
	}
	vPID->preerror=vPID->lasterror;
	vPID->lasterror=thisError;
	vPID->result+=increment;
}

特点

  • 偏差值较大时,取消积分作用,以免于超调量增大。
  • 偏差值较小时,引入积分作用,以便消除静差,提高控制精度。

抗积分饱和PID算法

原理

积分饱和就是指系统存在一个方向的偏差,PID控制器的输出由于积分作用的不断累加而扩大,从而导致控制器输出不断增大超出正常范围进入饱和区。当系统出现反响的偏差时,需要首先从饱和区退出,而不能对反向的偏差进行快速的响应。
抗积分饱和算法,其思路是在计算U(k)的时候,先判断上一时刻的控制量U(k-1)是否已经超出了限制范围。若U(k-1)>Umax,则只累加负偏差;若U(k-1)<Umin,则只累加正偏差。从而避免控制量长时间停留在饱和区。

位置式PID算法

简单实现

typedef struct
{
	float setpoint;			//设定值
	float proportiongain;	//比例系数
	float integralgain;		//积分系数
	float derivativegain;	//微分系数
	float lasterror;		//前一拍偏差
	float result;			//输出值
	float integral;			//积分值
	float maximum;			//最大值
	float minimum;			//最小值
}PID;
void PIDRegulation(PID *vPID, float processValue)
{
	float thisError;
	thisError=vPID->setpoint-processValue;
	if(vPID->result>vPID->maximum)
	{
		if(thisError<=0)
		{
			vPID->integral+=thisError;
		}
	}
	else if(vPID->result<vPID->minimum)
	{
		if(thisError>=0)
		{
			vPID->integral+=thisError;
		}
	}
	else
	{
		vPID->integral+=thisError;
	}
	vPID->result=vPID->proportiongain*thisError+
				 vPID->integralgain*vPID->integral+
				 vPID->derivativegain*(thisError-vPID->lasterror);
	vPID->lasterror=thisError;
}

增量式PID算法

简单实现

typedef struct
{
	float setpoint;			//设定值
	float proportiongain;	//比例系数
	float integralgain;		//积分系数
	float derivativegain;	//微分系数
	float lasterror;		//前一拍偏差
	float preerror;			//前两拍偏差
	float result;			//输出值
	float maximum;			//最大值
	float minimum;			//最小值
}PID;
void PIDRegulation(PID *vPID, float processValue)
{
	float thisError;
	float increment;
	float pError,dError,iError;
	thisError=vPID->setpoint-processValue;
	pError=thisError-vPID->lasterror;
	iError=0;
	dError=thisError-2*(vPID->lasterror)+vPID->preerror;
	if(vPID->result>vPID->maximum)
	{
		if(thisError<=0)
		{
			iError=thisError;
		}
	}
	else if(vPID->result<vPID->minimum)
	{
		if(thisError>=0)
		{
			iError=thisError;
		}
	}
	else
	{
		iError=thisError;
	}
	increment=vPID->proportiongain*pError+
			  vPID->integralgain*iError+
			  vPID->derivativegain*dError;
	vPID->preerror=vPID->lasterror;
	vPID->lasterror=thisError;
	vPID->result+=increment;
}

特点

  • 解决积分饱和的问题

梯形积分PID算法

原理

在PID控制其中,积分项的作用是消除余差,为了尽量减小余差,应提高积分项的运算精度。在积分项中,默认是按矩形方式来计算积分,将矩形积分改为梯形积分可以提高运算精度。

位置式PID算法

基本公式
U ( k ) = K p ∗ e r r ( k ) + K i ∑ j = 0 k e r r ( j ) + e r r ( j − 1 ) 2 + K d ∗ ( e r r ( k ) − e r r ( k − 1 ) ) U(k)=K_p*err(k)+K_i\sum_{j=0}^{k} \frac {err(j)+err(j-1)}2 +K_d*\big (err(k)-err(k-1)\big ) U(k)=Kperr(k)+Kij=0k2err(j)+err(j1)+Kd(err(k)err(k1))
简单实现

typedef struct
{
	float setpoint;			//设定值
	float proportiongain;	//比例系数
	float integralgain;		//积分系数
	float derivativegain;	//微分系数
	float lasterror;		//前一拍偏差
	float result;			//输出值
	float integral;			//积分值
}PID;
void PIDRegulation(PID *vPID, float processValue)
{
	float thisError;
	thisError=vPID->setpoint-processValue;
	vPID->integral+=(thisError+vPID->lasterror)/2;
	vPID->result=vPID->proportiongain*thisError+
				 vPID->integralgain*vPID->integral+
				 vPID->derivativegain*(thisError-vPID->lasterror);
	vPID->lasterror=thisError;
}

增量式PID算法

基本公式
Δ U ( k ) = U ( k ) − U ( k − 1 ) = K p ( e r r ( k ) − e r r ( k − 1 ) ) + K i ∗ e r r ( k ) + e r r ( k − 1 ) 2 + K d ( e r r ( k ) − 2 ∗ e r r ( k − 1 ) + e r r ( k − 2 ) ) \begin{aligned} \Delta U(k) &= U(k)-U(k-1)\\ &=K_p\big (err(k)-err(k-1)\big )\\&+K_i*\frac {err(k)+err(k-1)}2\\&+K_d\big (err(k)-2*err(k-1)+err(k-2)\big) \end{aligned} ΔU(k)=U(k)U(k1)=Kp(err(k)err(k1))+Ki2err(k)+err(k1)+Kd(err(k)2err(k1)+err(k2))
简单实现

typedef struct
{
	float setpoint;			//设定值
	float proportiongain;	//比例系数
	float integralgain;		//积分系数
	float derivativegain;	//微分系数
	float lasterror;		//前一拍偏差
	float preerror;			//前两拍偏差
	float result;			//输出值
}PID;
void PIDRegulation(PID *vPID, float processValue)
{
	float thisError;
	float increment;
	float pError,dError,iError;
	thisError=vPID->setpoint-processValue;
	pError=thisError-vPID->lasterror;
	iError=(thisError+vPID->lasterror)/2;
	dError=thisError-2*(vPID->lasterror)+vPID->preerror;
	increment=vPID->proportiongain*pError+
			  vPID->integralgain*iError+
			  vPID->derivativegain*dError;
	vPID->preerror=vPID->lasterror;
	vPID->lasterror=thisError;
	vPID->result+=increment;
}

特点

  • 梯形积分相较于矩形积分其精度有比较大的提高,所以对消除余差也就越有效

变速积分PID算法

原理

在普通的PID控制算法中,由于积分系数Ki是常数,所以在整个控制过程中,积分增量是不变的。然而,系统对于积分项的要求是,系统偏差大时,积分作用应该减弱甚至是全无,而在偏差小时,则应该加强。积分系数取大了会产生超调,甚至积分饱和,取小了又不能短时间内消除静差。
变积分PID的基本思想是设法改变积分项的累加速度,使其与偏差大小相对应:偏差越大,积分越慢; 偏差越小,积分越快。
设定系数为f(err(k)),它是err(k)的函数。当|err(k)|增大时,f减小,反之增大。变积分的PID积分项表达式为:
U i ( k ) = K i { f ( e r r ( k ) ) ∗ e r r ( k ) + ∑ j = 0 k − 1 e r r ( j ) } U_i(k)=K_i\Big\{ f\big (err(k)\big )*err(k)+\sum_{j=0}^{k-1}err(j)\Big\} Ui(k)=Ki{f(err(k))err(k)+j=0k1err(j)}
其中f(err(k))与|err(k)|的函数关系可根据具体情况设定,可以是线性的也可以是非线性的,通常比较简单的设置如下:
f ( e r r ( k ) ) = { 1 ∣ e r r ( k ) ∣ > ξ 0 ∣ e r r ( k ) ∣ ≤ ξ f\big(err(k)\big)=\begin{cases} 1& \vert err(k) \vert\gt\xi\\0& \vert err(k) \vert\leq\xi\end{cases} f(err(k))={10err(k)>ξerr(k)ξ
f ( e r r ( k ) ) = { 1 ∣ e r r ( k ) ∣ ≤ B A + B − ∣ e r r t ( k ) ∣ A B < ∣ e r r ( k ) ∣ ≤ A + B 0 ∣ e r r ( k ) ∣ > A + B f\big(err(k)\big)=\begin{cases}1 & \vert err(k)\vert\leq B \\\frac{A+B-\vert errt(k)\vert}{A} & B\lt\vert err(k)\vert\leq A+B\\0 & \vert err(k)\vert\gt A+B\end{cases} f(err(k))= 1AA+Berrt(k)0err(k)BB<err(k)A+Berr(k)>A+B

位置式PID算法

基本公式
U ( k ) = K p ∗ e r r ( k ) + K i { f ( e r r ( k ) ) ∗ e r r ( k ) + ∑ j = 0 k − 1 e r r ( j ) } + K d ∗ ( e r r ( k ) − e r r ( k − 1 ) ) U(k)=K_p*err(k)+K_i\Big\{ f\big (err(k)\big )*err(k)+\sum_{j=0}^{k-1}err(j)\Big\} +K_d*\big (err(k)-err(k-1)\big ) U(k)=Kperr(k)+Ki{f(err(k))err(k)+j=0k1err(j)}+Kd(err(k)err(k1))
简单实现

static float VariableIntegralCoefficient(floaterror,float absmax,float absmin)
{
	float factor=0.0;
	if(abs(error)<=absmin)
	{
		factor=1.0;
	}
	else if(abs(error)>absmax)
	{
		factor=0.0;
	}
	else
	{
		factor=(absmax-abs(error))/(absmax-absmin);
	}
	returnfactor;
}
typedef struct
{
	float setpoint;			//设定值
	float proportiongain;	//比例系数
	float integralgain;		//积分系数
	float derivativegain;	//微分系数
	float lasterror;		//前一拍偏差
	float result;			//输出值
	float integral;			//积分值
	float errorabsmax;		//偏差绝对值最大值
	float errorabsmin;		//偏差绝对值最小值
}PID;
void PIDRegulation(PID *vPID, float processValue)
{
	float thisError;
	float factor;
	thisError=vPID->setpoint-processValue;
	factor=VariableIntegralCoefficient(thisError, vPID->errorabsmax,vPID->errorabsmin);
	vPID->integral+= factor*thisError;
	vPID->result=vPID->proportiongain*thisError+
				 vPID->integralgain*vPID->integral+
				 vPID->derivativegain*(thisError-vPID->lasterror);
	vPID->lasterror=thisError;
}

增量式PID算法

基本公式
Δ U ( k ) = K p ( e r r ( k ) − e r r ( k − 1 ) ) + K i ∗ f ( e r r ( k ) ) ∗ e r r ( k ) + K d ( e r r ( k ) − 2 ∗ e r r ( k − 1 ) + e r r ( k − 2 ) ) \begin{aligned} \Delta U(k) &=K_p\big (err(k)-err(k-1)\big )\\&+K_i*f\big (err(k)\big)*err(k)\\&+K_d\big (err(k)-2*err(k-1)+err(k-2)\big) \end{aligned} ΔU(k)=Kp(err(k)err(k1))+Kif(err(k))err(k)+Kd(err(k)2err(k1)+err(k2))
简单实现

static float VariableIntegralCoefficient(floaterror,float absmax,float absmin)
{
	float factor=0.0;
	if(abs(error)<=absmin)
	{
		factor=1.0;
	}
	else if(abs(error)>absmax)
	{
		factor=0.0;
	}
	else
	{
		factor=(absmax-abs(error))/(absmax-absmin);
	}
	returnfactor;
}
typedef struct
{
	float setpoint;			//设定值
	float proportiongain;	//比例系数
	float integralgain;		//积分系数
	float derivativegain;	//微分系数
	float lasterror;		//前一拍偏差
	float preerror;			//前两拍偏差
	float result;			//输出值
	float errorabsmax;		//偏差绝对值最大值
	float errorabsmin;		//偏差绝对值最小值
}PID;
void PIDRegulation(PID *vPID, float processValue)
{
	float thisError;
	float increment;
	float pError,dError,iError;
	float factor;
	thisError=vPID->setpoint-processValue;
	factor=VariableIntegralCoefficient(thisError, vPID->errorabsmax,vPID->errorabsmin);
	pError=thisError-vPID->lasterror;
	iError=factor*thisError;
	dError=thisError-2*(vPID->lasterror)+vPID->preerror;
	increment=vPID->proportiongain*pError+
			  vPID->integralgain*iError+
			  vPID->derivativegain*dError;
	vPID->preerror=vPID->lasterror;
	vPID->lasterror=thisError;
	vPID->result+=increment;
}

不完全微分PID算法

原理

微分项有引入高频干扰的风险,但若在控制算法中加入低通滤波器,则可使系统性能得到改善。方法之一就是在PID算法中加入一个一阶低通滤波器。这就是所谓的不完全微分。

位置式PID算法

基本公式
U ( k ) = K p ∗ e r r ( k ) + K i ∑ j = 0 k e r r ( j ) + U d ( k ) U(k)=K_p*err(k)+K_i\sum_{j=0}^{k} err(j)+U_d(k) U(k)=Kperr(k)+Kij=0kerr(j)+Ud(k)
U d ( k ) = K d ( 1 − α ) ( e r r ( k ) − e r r ( k − 1 ) ) + α U d ( k − 1 ) U_d(k)=K_d(1-\alpha)\big(err(k)-err(k-1)\big)+\alpha U_d(k-1) Ud(k)=Kd(1α)(err(k)err(k1))+αUd(k1)
简单实现

typedef struct
{
	float setpoint;			//设定值
	float proportiongain;	//比例系数
	float integralgain;		//积分系数
	float derivativegain;	//微分系数
	float lasterror;		//前一拍偏差
	float lastdev;			//前一拍时的微分项值
	float alpha;			//不完全微分系数
	float result;			//输出值
	float integral;			//积分值
}PID;
void PIDRegulation(PID *vPID, float processValue)
{
	float thisError;
	float thisDev;
	thisError=vPID->setpoint-processValue;
	vPID->integral+=thisError;
	thisDev=vPID->derivativegain*(1-vPID->alpha)*(thisError-vPID->lasterror)+
			vPID->alpha*vPID->lastdev;
	vPID->result=vPID->proportiongain*thisError+
				 vPID->integralgain*vPID->integral+
				 thisDev;
	vPID->lasterror=thisError;
	vPID->lastdev=thisDev;
}

增量式PID算法

基本公式
Δ U ( k ) = K p ( e r r ( k ) − e r r ( k − 1 ) ) + K i ∗ e r r ( k ) + Δ U d ( k ) \Delta U(k) =K_p\big (err(k)-err(k-1)\big )+K_i*err(k)+\Delta U_d(k) ΔU(k)=Kp(err(k)err(k1))+Kierr(k)+ΔUd(k)
Δ U d ( k ) = K d ( 1 − α ) ( e r r ( k ) − 2 e r r ( k − 1 ) + e r r ( k − 2 ) ) + α Δ U d ( k − 1 ) \Delta U_d(k)=K_d(1-\alpha)\big(err(k)-2err(k-1)+err(k-2)\big)+\alpha\Delta U_d(k-1) ΔUd(k)=Kd(1α)(err(k)2err(k1)+err(k2))+αΔUd(k1)
简单实现

typedef struct
{
	float setpoint;			//设定值
	float proportiongain;	//比例系数
	float integralgain;		//积分系数
	float derivativegain;	//微分系数
	float lasterror;		//前一拍偏差
	float preerror;			//前两拍偏差
	float lastdeltadev;		//前一拍时的微分项增量
	float alpha;			//不完全微分系数
	float result;			//输出值
}PID;
void PIDRegulation(PID *vPID, float processValue)
{
	float thisError;
	float increment;
	float deltaDev;
	float pError,dError,iError;
	thisError=vPID->setpoint-processValue;
	pError=thisError-vPID->lasterror;
	iError=thisError;
	dError=thisError-2*(vPID->lasterror)+vPID->preerror;
	deltaDev=vPID->derivativegain*(1-vPID->alpha)*dError+
			 vPID->alpha*vPID->lastdeltadev;
	increment=vPID->proportiongain*pError+
			  vPID->integralgain*iError+
			  deltaDev;
	vPID->preerror=vPID->lasterror;
	vPID->lasterror=thisError;
	vPID->lastdeltadev=deltaDev;
	vPID->result+=increment;
}

特点

  • 不完全微分方式在微分环节采用了低通滤波有效地提高了微分项的特性。其中α的取值是一个0~1之间的数。两个极限值,在0时其实就是没有滤波的普通微分环节;而取1时,则没有微分作用。

微分先行PID算法

位置式PID算法

基本公式
U ( k ) = K p ∗ e r r ( k ) + K i ∑ j = 0 k e r r ( j ) + U d ( k ) U(k)=K_p*err(k)+K_i\sum_{j=0}^{k} err(j)+U_d(k) U(k)=Kperr(k)+Kij=0kerr(j)+Ud(k)
U d ( k ) = ( γ K d γ K d + K p ) U d ( k − 1 ) + ( K d + K p γ K d + K p ) y ( k ) + ( K d γ K d + K p ) y ( k − 1 ) U_d(k)=\Big(\frac{\gamma K_d}{\gamma K_d+K_p}\Big)U_d(k-1)+\Big(\frac{K_d+K_p}{\gamma K_d+K_p}\Big)y(k)+\Big(\frac{K_d}{\gamma K_d+K_p}\Big)y(k-1) Ud(k)=(γKd+KpγKd)Ud(k1)+(γKd+KpKd+Kp)y(k)+(γKd+KpKd)y(k1)
简单实现

typedef struct
{
	float setpoint;			//设定值
	float proportiongain;	//比例系数
	float integralgain;		//积分系数
	float derivativegain;	//微分系数
	float lasterror;		//前一拍偏差
	float result;			//输出值
	float integral;			//积分值
	float derivative;		//微分项
	float lastPv;			//前一拍的测量值
	float gama;				//微分先行滤波系数
}PID;
void PIDRegulation(PID *vPID, float processValue)
{
	float thisError;
	float c1,c2,c3,temp;
	
	thisError=vPID->setpoint-processValue;
	vPID->integral+=thisError;
	temp=vPID->gama*vPID->derivativegain+vPID->proportiongain;
	c3=vPID->derivativegain/temp;
	c2=(vPID->derivativegain+vPID->proportiongain)/temp;
	c1=vPID->gama*c3;
	vPID->derivative=c1*vPID->derivative+c2*processValue+c3*vPID->lastPv;
	
	vPID->result=vPID->proportiongain*thisError+
				 vPID->integralgain*vPID->integral+
				 vPID->derivative;
	vPID->lasterror=thisError;
	vPID->lastPv=processValue;
}

增量式PID算法

基本公式
Δ U ( k ) = K p ( e r r ( k ) − e r r ( k − 1 ) ) + K i ∗ e r r ( k ) + Δ U d ( k ) \Delta U(k) =K_p\big (err(k)-err(k-1)\big )+K_i*err(k)+\Delta U_d(k) ΔU(k)=Kp(err(k)err(k1))+Kierr(k)+ΔUd(k)
Δ U d ( k ) = ( γ K d γ K d + K p ) Δ U d ( k − 1 ) + ( K d + K p γ K d + K p ) Δ y ( k ) + ( K d γ K d + K p ) Δ y ( k − 1 ) \Delta U_d(k)=\Big(\frac{\gamma K_d}{\gamma K_d+K_p}\Big)\Delta U_d(k-1)+\Big(\frac{K_d+K_p}{\gamma K_d+K_p}\Big)\Delta y(k)+\Big(\frac{K_d}{\gamma K_d+K_p}\Big)\Delta y(k-1) ΔUd(k)=(γKd+KpγKd)ΔUd(k1)+(γKd+KpKd+Kp)Δy(k)+(γKd+KpKd)Δy(k1)
简单实现

typedef struct
{
	float setpoint;			//设定值
	float proportiongain;	//比例系数
	float integralgain;		//积分系数
	float derivativegain;	//微分系数
	float lasterror;		//前一拍偏差
	float preerror;			//前两拍偏差
	float lastdeltadev;		//前一拍时的微分项增量
	float alpha;			//不完全微分系数
	float result;			//输出值
	float deltadiff;		//微分增量
	float integralValue;	//积分累计量
	float gama;				//微分先行滤波系数
	float lastPv;			//上一拍的过程测量值
	float lastDeltaPv;		//上一拍的过程测量值增量
}PID;
void PIDRegulation(PID *vPID, float processValue)
{
	float thisError;
	float increment;
	float pError,iError;
	float c1,c2,c3,temp;
	float deltaPv;
	
	temp=vPID->gama*vPID->derivativegain+vPID->proportiongain;
	c3=vPID->derivativegain/temp;
	c2=(vPID->derivativegain+vPID->proportiongain)/temp;
	c1=vPID->gama*c3;
	deltaPv=processValue-vPID->lastDeltaPv
	vPID->deltadiff=c1*vPID->deltadiff+c2*deltaPv+c3*vPID->lastDeltaPv;
	thisError=vPID->setpoint-processValue;
	pError=thisError-vPID->lasterror;
	iError=thisError;
	
	increment=vPID->proportiongain*pError+
			  vPID->integralgain*iError+
			  vPID->deltadiff;
	vPID->preerror=vPID->lasterror;
	vPID->lastDeltaPv=deltaPv;
	vPID->lastPv=processValue;
	vPID->lasterror=thisError;
	vPID->result+=increment;
}

特点

  • 微分先行由于微分部分只对测量值起作用所以可以消除设定值突变的影响,还可以引入低通滤波,甚至在必要时将比例作用也可进行相应的改进。

带死区的PID算法

位置式PID算法

基本公式
U ( k ) = K p ∗ e r r ( k ) + K i ∑ j = 0 k e r r ( j ) + K d ∗ ( e r r ( k ) − e r r ( k − 1 ) ) U(k)=K_p*err(k)+K_i\sum_{j=0}^{k} err(j)+K_d*\big (err(k)-err(k-1)\big ) U(k)=Kperr(k)+Kij=0kerr(j)+Kd(err(k)err(k1))
e r r ( k ) = { 0 ∣ e r r ( k ) ∣ ≤ ∣ e r r 0 ∣ e r r ( k ) ∣ e r r ( k ) ∣ > ∣ e r r 0 ∣ err(k)=\begin{cases}0 & \vert err(k)\vert\leq \vert err_0\vert \\err(k) & \vert err(k)\vert\gt \vert err_0\vert\end{cases} err(k)={0err(k)err(k)err0err(k)>err0
简单实现

typedef struct
{
	float setpoint;			//设定值
	float proportiongain;	//比例系数
	float integralgain;		//积分系数
	float derivativegain;	//微分系数
	float lasterror;		//前一拍偏差
	float result;			//输出值
	float integral;			//积分值
	float deadband;			//死区
}PID;
void PIDRegulation(PID *vPID, float processValue)
{
	float thisError;
	thisError=vPID->setpoint-processValue;
	if(fabs(thisError)>vPID->deadband)
	{
		vPID->integral+=thisError;
	}
	else
	{
		thisError=0;
	}
	vPID->result=vPID->proportiongain*thisError+
				 vPID->integralgain*vPID->integral+
				 vPID->derivativegain*(thisError-vPID->lasterror);
	vPID->lasterror=thisError;
}

增量式PID算法

基本公式
Δ U ( k ) = U ( k ) − U ( k − 1 ) = K p ( e r r ( k ) − e r r ( k − 1 ) ) + K i ∗ e r r ( k ) + K d ( e r r ( k ) − 2 ∗ e r r ( k − 1 ) + e r r ( k − 2 ) ) \begin{aligned} \Delta U(k) &= U(k)-U(k-1)\\ &=K_p\big (err(k)-err(k-1)\big )\\&+K_i*err(k)\\&+K_d\big (err(k)-2*err(k-1)+err(k-2)\big) \end{aligned} ΔU(k)=U(k)U(k1)=Kp(err(k)err(k1))+Kierr(k)+Kd(err(k)2err(k1)+err(k2))
e r r ( k ) = { 0 ∣ e r r ( k ) ∣ ≤ ∣ e r r 0 ∣ e r r ( k ) ∣ e r r ( k ) ∣ > ∣ e r r 0 ∣ err(k)=\begin{cases}0 & \vert err(k)\vert\leq \vert err_0\vert \\err(k) & \vert err(k)\vert\gt \vert err_0\vert\end{cases} err(k)={0err(k)err(k)err0err(k)>err0
简单实现

typedef struct
{
	float setpoint;			//设定值
	float proportiongain;	//比例系数
	float integralgain;		//积分系数
	float derivativegain;	//微分系数
	float lasterror;		//前一拍偏差
	float preerror;			//前两拍偏差
	float result;			//输出值
	float deadband;			//死区
}PID;
void PIDRegulation(PID *vPID, float processValue)
{
	float thisError;
	float increment;
	float pError,dError,iError;
	thisError=vPID->setpoint-processValue;
	if(fabs(thisError)>vPID->deadband)
	{
		vPID->integral+=thisError;
	}
	else
	{
		thisError=0;
	}
	pError=thisError-vPID->lasterror;
	iError=thisError;
	dError=thisError-2*(vPID->lasterror)+vPID->preerror;
	increment=vPID->proportiongain*pError+
			  vPID->integralgain*iError+
			  vPID->derivativegain*dError;
	vPID->preerror=vPID->lasterror;
	vPID->lasterror=thisError;
	vPID->result+=increment;
}

特点

  • 消除稳定点附近的波动

基于前馈补偿的PID算法

不太懂,直接给链接
基于前馈补偿的PID算法

  • 11
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值