引子
本文将分析《手把手教你看懂并理解Arduino PID控制库》中:初始化的问题
问题定义
先看问题的图示:
上一节,讨论的是PID控制由开转关的过程中存在的问题,那么紧接着上一节,如果在关闭后,突然再次开启,那么会产生什么问题呢?直观来看,对于被控量会出现图中,绿色线的一个bump,这个bump是由于由关转开的一瞬间,输出突然放大,那么对于灵敏度高的系统,则会出现,滞后大的系统可能不会如此明显,但不管怎么说,为了杜绝一切不利因素,我们都应该想办法消除这个bump。由于这个bump的根因是由于输出的突变而造成的,所以需要想办法控制这个输出的突变。
解决方案
想一想,所有此类问题都是发生在时间轴上的,那么PID控制中时间轴会影响的项只有积分项和微分项(可以想象,比例向为Kp * (设定值 - 被控量),这是一个连续量,不存在突变的可能(除非是采样时间特别长,在改变输出前,被控量飞上天了),所以只需要从这两项上想办法,控制住这两项的突变,即可控制住输出的突变。首先问题发生在PID关闭转开启的过程中,由于PID开启关闭控制的函数是SetMode,所以在此函数中,增加一个initial函数用于控制积分项和微分项即可。具体做法是:
1、更新微分项上一次采样值为PID开启一瞬间的采样值,这样可以保持微分项维持在上一次开启结束的状态不变。
2、将积分项设置为当前的输出,为什么要这么做呢?积分项由于PID关闭长时间维持关闭前的状态,一旦开启,如果不改变积分项,输出会瞬间被拉回到上一次开启结束的状态,突变就这样产生了
代码
/*working variables*/
unsigned long lastTime;
double Input, Output, Setpoint;
double ITerm, lastInput;
double kp, ki, kd;
int SampleTime = 1000; //1 sec
double outMin, outMax;
bool inAuto = false;
#define MANUAL 0
#define AUTOMATIC 1
void Compute()
{
if(!inAuto) return;
unsigned long now = millis();
int timeChange = (now - lastTime);
if(timeChange>=SampleTime)
{
/*Compute all the working error variables*/
double error = Setpoint - Input;
ITerm+= (ki * error);
if(ITerm> outMax) ITerm= outMax;
else if(ITerm< outMin) ITerm= outMin;
double dInput = (Input - lastInput);
/*Compute PID Output*/
Output = kp * error + ITerm- kd * dInput;
if(Output> outMax) Output = outMax;
else if(Output < outMin) Output = outMin;
/*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;
}
}
void SetOutputLimits(double Min, double Max)
{
if(Min > Max) return;
outMin = Min;
outMax = Max;
if(Output > outMax) Output = outMax;
else if(Output < outMin) Output = outMin;
if(ITerm> outMax) ITerm= outMax;
else if(ITerm< outMin) ITerm= outMin;
}
void SetMode(int Mode)
{
bool newAuto = (Mode == AUTOMATIC);
if(newAuto && !inAuto)
{ /*we just went from manual to auto*/
Initialize();
}
inAuto = newAuto;
}
void Initialize()
{
lastInput = Input;
ITerm = Output;
if(ITerm> outMax) ITerm= outMax;
else if(ITerm< outMin) ITerm= outMin;
}
结论
图片说明一切。。。。。
NOTE:如有不足之处请告知。^.^
下一章将介绍如果在系统运行过程中,控制方向对系统的影响
PS:转载请注明出处:欧阳天华