欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

PID调优——样本时间

程序员文章站 2022-05-26 10:25:43
...

 

问题

PID设计为无规则调用,存在2个问题:

  • 你不能从PID得到确定的行为,因为调用时可能是频繁的也可能不是。
  • 你需要做额外的微分和积分数学计算,因为它们都依赖于时间变化。

方案

确保PID在规律的时间间隔调用。通过指定每个调用PID循环,基于预定义的一个样本时间,PID决定计算还是立即返回。

当我们知道PID在固定的间隔被调用,微分和积分运算就可以简化。

代码

/*working variables*/
unsigned long lastTime;
double Input, Output, Setpoint;
double errSum, lastErr;
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;
      errSum += error;
      double dErr = (error - lastErr);
 
      /*Compute PID Output*/
      Output = kp * error + ki * errSum + kd * dErr;
 
      /*Remember some variables for next time*/
      lastErr = error;
      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;
   }
}
 

算法可以判断是否是计算的时间了。同样,我们现在知道算法使用相同的样本时间,我们不需要常常乘以时间变化。我们仅仅适当调整Ki和Kd,哪样在数学上是相等的,而且更加有效。

一个小缺陷是。如果用户决定修改样本时间,Ki和Kd需要重新调整以反应新的修改,SetSampleTimp就是做这个事的。

需要注意,我把样本时间的单位换算成秒。严格来说这不是必须的,但是这让用户可以输入Ki和Kd的单位是1/秒和秒,而不是1/毫秒和毫秒。

结果

上面的修改为我们做了三件事

  1. 不管Compute()的调用频率是多少,PID算法始终是固定的间隔调用。
  2. millis()为0时,时间相减不再是问题。
  3. 我们再也不需要去乘除时间变化。因为这是个常数,我们将它从计算代码中移除,整合进调整常数中。从数学上来说是等价的,但是节约了每一次乘除带来的成本。

Side note about interrupts

如果这个PID运行在单片机中,一个非常好的想法是使用一个中断。SetSampleTime设置中断频率,然后到时调用Compute。在这种情况下时间计算和判断就不会有需要。
这里有三个原因我没有使用中断:

  1. 不是每个人都能用中断。
  2. 同一时间实现多个PID控制器将变得棘手。
  3. 我将在以后的PID实现中使用终端。
相关标签: PID 样本时间