• 改进初学者的PID-初始化


      最近看到了Brett Beauregard发表的有关PID的系列文章,感觉对于理解PID算法很有帮助,于是将系列文章翻译过来!在自我提高的过程中,也希望对同道中人有所帮助。作者Brett Beauregard的原文网址:http://brettbeauregard.com/blog/2011/04/improving-the-beginner's-pid-initialization/

    1、问题所在

      在前一节中,我们实现了关闭和打开 PID 的功能。我们将其关闭,但现在让我们来看看当我们重新打开它时会发生什么:

     

      呵!PID跳回到它发送的最后一个输出值,然后从那里开始调整。这将导致我们不希望出现的输入颠簸。

    2、解决方案

      这个很容易解决。因为我们现在知道什么时候打开 (从手动到自动),我们只需为一个平稳的过渡做一些初始化。这意味着对2个工作变量的存储 (积分项和最后的输入项) 进行处理,以防止输出跳转。

    3、代码

     1 /*working variables*/
     2 unsigned long lastTime;
     3 double Input,Output,Setpoint;
     4 double ITerm,lastInput;
     5 double kp,ki,kd;
     6 int SampleTime = 1000; //1 sec
     7 double outMin,outMax;
     8 bool inAuto = false;
     9  
    10 #define MANUAL 0
    11 #define AUTOMATIC 1
    12  
    13 void Compute()
    14 {
    15    if(!inAuto) return;
    16    unsigned long now = millis();
    17    int timeChange = (now - lastTime);
    18    if(timeChange>=SampleTime)
    19    {
    20       /*Compute all the working error variables*/
    21       double error = Setpoint - Input;
    22       ITerm+= (ki * error);
    23       if(ITerm> outMax) ITerm= outMax;
    24       else if(ITerm< outMin) ITerm= outMin;
    25       double dInput = (Input - lastInput);
    26  
    27       /*Compute PID Output*/
    28       Output = kp * error + ITerm- kd * dInput;
    29       if(Output> outMax) Output = outMax;
    30       else if(Output < outMin) Output = outMin;
    31  
    32       /*Remember some variables for next time*/
    33       lastInput = Input;
    34       lastTime = now;
    35    }
    36 }
    37  
    38 void SetTunings(double Kp,double Ki,double Kd)
    39 {
    40   double SampleTimeInSec = ((double)SampleTime)/1000;
    41    kp = Kp;
    42    ki = Ki * SampleTimeInSec;
    43    kd = Kd / SampleTimeInSec;
    44 }
    45  
    46 void SetSampleTime(int NewSampleTime)
    47 {
    48    if (NewSampleTime > 0)
    49    {
    50       double ratio  = (double)NewSampleTime
    51                       / (double)SampleTime;
    52       ki *= ratio;
    53       kd /= ratio;
    54       SampleTime = (unsigned long)NewSampleTime;
    55    }
    56 }
    57  
    58 void SetOutputLimits(double Min,double Max)
    59 {
    60    if(Min > Max) return;
    61    outMin = Min;
    62    outMax = Max;
    63    
    64    if(Output > outMax) Output = outMax;
    65    else if(Output < outMin) Output = outMin;
    66  
    67    if(ITerm> outMax) ITerm= outMax;
    68    else if(ITerm< outMin) ITerm= outMin;
    69 }
    70  
    71 void SetMode(int Mode)
    72 {
    73     bool newAuto = (Mode == AUTOMATIC);
    74     if(newAuto && !inAuto)
    75     {  /*we just went from manual to auto*/
    76         Initialize();
    77     }
    78     inAuto = newAuto;
    79 }
    80  
    81 void Initialize()
    82 {
    83    lastInput = Input;
    84    ITerm = Output;
    85    if(ITerm> outMax) ITerm= outMax;
    86    else if(ITerm< outMin) ITerm= outMin;
    87 }

      我们修改了 SetMode (...) 以检测从手动到自动的转换,并添加了初始化功能。它通过设置“积分项=输出”来处理积分项,“最后输入=输入”以防止微分激增。比例项不依赖于过去的任何信息,因此不需要任何初始化。

    4、最终结果

     

      我们从上面的图表中看到,正确的初始化会导致从手动到自动的无扰动切换,这正是我们所追求的。

    5、更新:为什么不 ITerm=0

      我最近收到了很多问题,问为什么我没有把 ITerm=0 设置为初始化。作为答案,我请您考虑以下方案:PID是手动的,用户已将输出设置为50。一段时间后,该过程稳定到75.2 的输入。用户将设置点75.2 打开 PID。会发生什么事?

      我认为,切换到自动后,输出值应该保持在50。由于 P 和 D 项将为零,因此发生这种情况的唯一方法是将 ITerm项初始化为“输出”值。

      如果您处于需要输出初始化为零的情况,则无需更改上面的代码。在将 PID 从“手动”转换为“自动”之前,只需在调用例程中设置Output=0。

     欢迎关注:

  • 相关阅读:
    block 相关清单
    在Objective-C 中使用字符生成NSArray、NSDictionary、NSNumber
    NSURLSession 相关清单
    iOS 相关博客清单
    sqlite 一条记录判断一个字段是否like另一个字段
    iphone程序适配ipad可以用下面的宏进行尺寸改写
    NSURLSession使用说明及后台工作流程分析
    iOS 6 新的快捷初始化写法
    ios 应用发布渠道大全
    iOS-获取当前时间的年、月、日、时、分、秒
  • 原文地址:https://www.cnblogs.com/foxclever/p/11406020.html
Copyright © 2020-2023  润新知