原文地址:http://brettbeauregard.com/blog/2011/04/improving-the-beginner%e2%80%99s-pid-tuning-changes/
问题The Problem
在系统运行时调参是一个优秀PID算法必须具备的。
最初的PID当你在系统运行时调整时显得有点懒惰。让我们看看这是什么原因。这里是最初的PID调整前后的状态:
因此我们立即认为这个问题出在积分项(或者I项)。唯一的参数变化引起急剧变化。为什会这样?这不得不解释初步的积分:
这个公式正常工作知道Ki改变。突然的,你新的Ki被乘以错误之和的累积。这不是我们想要的!我们只想把事情向前推进。
解决方案The Solution
我知道几种方法来解决这个问题。在最后的库里面我用的方法是从新调整误差和errSum。双倍Ki?errSum减半。这样避免了I项的跳动,并且工作良好。这个看起来有点粗糙,我想出一些更好的办法。
解决方案需要一些基础代数
和让Ki外部积分相反,我们把它放进去。看上去我们没做什么,但是我们将看到实际情况是有很大不同的。
现在误差乘以Ki。我们保存乘积的和。当Ki变化是,这里不会有抖动,因为旧的Ki已经保存了。我们得到一个平滑的过渡而不用一个附加的数学操作。这让我成为一个极客,但我认为这很性感。
The Code
/*working variables*/
unsigned long lastTime;
double Input, Output, Setpoint;
double ITerm, lastInput;
double kp, ki, kd;
int SampleTime = 1000; //1 sec
void Compute()
{
unsigned long now = millis();
int timeChange = (now - lastTime);
if(timeChange>=SampleTime)
{
/*Compute all the working error variables*/
double error = Setpoint - Input;
ITerm += (ki * error);
double dInput = (Input - lastInput);
/*Compute PID Output*/
Output = kp * error + ITerm - kd * dInput;
/*Remember some variables for next time*/
lastInput = Input;
lastTime = now;
}
}
void SetTunings(double Kp, double Ki, double Kd)
{
double SampleTimeInSec = ((double)SampleTime)/1000;
kp = Kp;
ki = Ki * SampleTimeInSec;
kd = Kd / SampleTimeInSec;
}
void SetSampleTime(int NewSampleTime)
{
if (NewSampleTime > 0)
{
double ratio = (double)NewSampleTime
/ (double)SampleTime;
ki *= ratio;
kd /= ratio;
SampleTime = (unsigned long)NewSampleTime;
}
}
The Result
那么这是如何解决问题的呢。在ki改变之前,重新调整了整个误差和;每个误差值我们都已经看到。这段代码中,前面的误差保持不变,只有新的Ki会影响变化,这正是我们想要的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)