PID Anti-Windup method: Back-calculation

最近在编矢量控制的程序,其中电机的定子电流、转子速度要通过PID进行调节。在学习TI的ACI_Motor例程的时候,发现例程中的pid_reg3模块的框图和平时用到的PID的框图不同,增加了anti-windup环节。其在积分部分中又引入了反馈以抗积分饱和,这片笔记记录一下大致原理。

当误差的正负方向在比较长的一段时间内都处于一个方向时,积分环节的输出容易过大,导致整个PID的输出在这个方向上在较长的时间内维持一个比较大的值。

而后方的执行机构由于存在限制,即使执行机构接收到了PID的输出,也由于饱和无法进一步改变输出。从外部来看,执行机构的输出并不随着PID的输出而改变,即闭环结构在这种情况下变成了开环结构。

所以在设计PID的时候要考虑这种情况的出现,增加Anti-Windup环节。

Back-calculation PID的结构如图所示:

anti-windup pid

其中除去1/Tt这条路上的反馈之后其实就是个普通的PID。所做的改动只有加入了这条反馈。其控制顺序大致如下:

1.如果PID的积分部分过大,则PID的输出会很大。然而由于执行装置具有限值,执行装置的输出并不能随着PID的输出增大而增大。

2.所以输入1/Tt的信号会随着PID的输出增大而减小,输出一个幅度更大的负值。

3.该信号经过1/Tt的增益之后会叠加到积分之前的信号,经过积分就会减小PID中的积分部分。

可以推测,Tt变小,即1/Tt增大会使执行装置的输出更快的退出饱和状态,使系统更快的进入闭环工作状态,靠近参考值。接下来会证明一下Tt的值对于输出的影响。在simulink中搭好如下图所示的模型。其中step信号设定为初始值10,终值5,跳变时间100。传递函数延时2。

pid_systems

图中包含四个PID,左上角的没有back-calculation,无法抗饱和;其余的均有back-calculation,左下的Tt=10,右上的Tt=1e-1,右下的Tt=1e-3。下方分别使用三个scope观察系统的输出、PID中积分部分的大小、执行装置什么时候能退出饱和状态。

先对比一下使用和不使用抗积分饱和的输出结果。下图中黄色的信号为ref信号。蓝色为Tt=0.1的有back-calculation的抗饱和积分PID的输出结果,粉色为没有进行back-calculation的普通PID的输出结果。可以看出蓝色信号对于给定信号跟踪的更好,能够更快的进入±5%的范围内。

pid_output

而带有back-calculation的PID能使输出更快稳定的直接原因是其执行装置能更快的退出饱和状态,如下图所示。途中四条线均为执行机构的输出,黄色为普通PID,粉红色的为Tt=10的,蓝色为Tt=1e-1的,红色为Tt=1e-3的。可以看出红色的最先退出饱和状态,随着Tt的增大,退出饱和状态的速度越来越慢,普通PID的最慢。

actuator_output

之所以会产生如此差别其实根本原因是各个系统中对于积分部分的抑制能力不同。如下图所示,各个颜色对应的与上图相同。红色和蓝色的积分部分的抑制作用非常明显。

integrator_output

最后对比一下各个系统的输出,明显Tt值更小一些的能很快的进入稳定状态。图中颜色对应关系也与上文中的相同。

system_output

后记:

实际上,TI提供的ACI_Motor中的pid_reg3.pdf page5中的抗积分饱和模型是错误的。

esat经过Kc的增益之后输出到了积分部分中,并未输出到积分环节之前。使用matlab模拟之后的结果显示,这样的结构无论如何增大Kc的值,虽然能够使积分部分的大小被大大抑制,但是并不能使执行装置快速退出饱和状态。而是和普通PID一样,在同样的时间点退出饱和状态。所以对于快速进入闭环工作状态没有帮助,并不能起到预期的效果。

最终用C实现的代码见下,大致的参考了一下TI的例程,不过框图是按照正确的做的。

void PID_calc(PID_handler v)
{
	float error,up,ui,ud,out_presat;
	error = ref - fdb;
	up = error*v->kp;
	ui = (error*v->ki+v->kc*v->satErr)*v->T_sampling + v->ui;
	ud = v->kd*(error-v->err_old)/v->T_sampling;
	out_presat = up + ui + ud;
	if(out_preset>v->outMax)
	{
		v->out = outMax;
	}
	else if(out_preset<v->outMin)
	{
		v->out = outMin;
	}
	else
	{
		v->out = out_presat;
	}
	v->satErr = v->out - v->out_presat;
	v->err_old = err;
}

其实本文可以归结为一句话:

TI罪大恶极,搞得百姓怨声载道啊!

 

参考资料:

anti-windup-control-using-a-pid-controller

Visioli A. Practical PID control[M]. Springer, 2006.