本帖最后由 syl312 于 2014-1-23 13:57 编辑
微分过冲: 出现的问题:通过对微分项的弱化处理,目的是消除微分过冲的现象。
[图1微分过冲]
上图说明了这个问题,因为偏差error=Setpoint-Input.任何在系统设定值得改变将立刻引起偏差的变化。所以系统设置值微小的变化将会导致出现一个极大的微分值。解决方法:
【图等式1】
以上公式已经被证明,除了设置值改变的时候,偏差的微分等于输入导数的负值。这就有了一个很好的解决方法。我们用 -kd * dInput取代原来的微分。这就是微分的测量方法。 程序实现:
[mw_shl_code=c,true]unsigned long lastTime;
doubleInput, Output, Setpoint;
doubleerrSum, lastInput;
doublekp, ki, kd;
int SampleTime =1000; //1s
void Compute()
{
unsigned long now = millis();
int timeChange = (now - lastTime);
if(timeChange>=SampleTime)
{
doubleerror = Setpoint - Input;
errSum += error;
doubledInput = (Input - lastInput);
Output = kp * error + ki * errSum - kd * dInput;
lastInput = Input;
lastTime = now;
}
}
void SetTunings(doubleKp,doubleKi,doubleKd)
{
doubleSampleTimeInSec = ((double)SampleTime)/1000;
kp = Kp;
ki = Ki * SampleTimeInSec;
kd = Kd / SampleTimeInSec;
}
void SetSampleTime(int NewSampleTime)
{
if (NewSampleTime >0)
{
doubleratio = (double)NewSampleTime
/ (double)SampleTime;
ki *= ratio;
kd /= ratio;
SampleTime = (unsigned long)NewSampleTime;
}
}[/mw_shl_code]
结果:
【图结果】
这就是我们修正后带来的效果。注意输入依旧是一样的。我们得到了一样的性能,并且不会因为Setpoing的变化导致输出波形有很大的纹波。 问题:对于一个正在运行的PID控制系统PID参数的改变会导致输出的变化。
【图正在运行的PID控制系统PID参数的改变会导致输出的变化】
对于修正正在运行的控制系统的PID参数,会带来很大的变化。以下是PID参数修改前后的变化值:
【表PID参数修改前后的变化值】
通过这张可以看出,以上是因为积分突然变为原来的一半。当参数变化时,带来的变化是巨大的。为什么会是这样的呢?下面的积分公式可以解释:
[公式2]
这就解释了为什么KI没改变之前系统工作的一直很稳定。突然,你乘了一个新的KI值与之前的偏差累计总和。这样带来的变化不是我们所希望的,我们只想改变后能朝着我们希望的方向发展。 解决方法:解决的方法有很多,我在最新的Arduino PID库里使用的方法是重新调整errSum(偏差总和).KI变为原来的两倍时,把errSum变为原来的一半,虽然这个方法有点笨拙,下面有更加明智的方法。这个方法要求有基础的代数基础或者计算技巧。
[公式3]
把KI乘到里面,虽然看起来没什么变化,但是我们将会看到这个小变化带来了很大的不同。现在我们将error和Ki相乘。并且把乘积和保存起来,当Ki变化时,这时不会有很大的变化了,因为之前的KI的乘积和值已经存储起来了。
[mw_shl_code=c,true]unsigned long lastTime;
doubleInput, Output, Setpoint;
doubleITerm, lastInput;
doublekp, ki, kd;
int SampleTime =1000; //1sec
void Compute()
{
unsigned long now = millis();
int timeChange = (now - lastTime);
if(timeChange>=SampleTime)
{
doubleerror = Setpoint - Input;
ITerm += (ki * error);
doubledInput = (Input - lastInput);
Output = kp * error + ITerm - kd * dInput;
lastInput = Input;
lastTime = now;
}
}
void SetTunings(doubleKp,doubleKi,doubleKd)
{
doubleSampleTimeInSec = ((double)SampleTime)/1000;
kp = Kp;
ki = Ki * SampleTimeInSec;
kd = Kd / SampleTimeInSec;
}
void SetSampleTime(int NewSampleTime)
{
if (NewSampleTime >0)
{
doubleratio = (double)NewSampleTime
/ (double)SampleTime;
ki *= ratio;
kd /= ratio;
SampleTime = (unsigned long)NewSampleTime;
}
}[/mw_shl_code]
我们用ITerm变量来替代errSum【第四行】。这样KI就包含在ITerm中,就从主要的PID计算式子中抽离出来。 结果如下:
【图5】
【图6】
当KI调整之前,控制器重新调整了全部的error的总和,每个偏差值都能看到。通过这个程序,先前的偏差值仍旧是原样的,新的KI值只是朝着我们希望的方向有作用。 |