PID算法Demo

pre

最近在准备做一些事的时候可能需要用到PID算法,所以今天下午基于网上的一些教程和博客写了一遍,在写的过程中遇到了一些疑惑和坑,这里分享一个整个过程和最后的成果,留作日后参考。

需求

场景: 锅炉调温
现在有一加热热水锅炉,我们需要他稳定提供70度的热水,当前室温25度,用来加热的水是温度为50度的温水。
锅炉的加热功率能够瞬时加热水到40度,同时功率可以调整,支持从0W到最高瓦数的瞬时切换(这里都是测试数据,不要带入现实)

水会自然散热,散热曲线符合二次曲线,假设曲线为 0.2 *( temperature - environment)^2

增量式PID算法

(这里只使用了增量式的PID,所以不讨论其他类型的PID)
PID算法设计三个变量,分别是偏差的比例(P)、积分(I)和微分(D)。增量式PID套用的公式为
u(k)=Kp * [e(k)-e(k-1)]+Ki * e(k)+Kd * [e(k)-2e(k-1)+e(k-2)]
下面是对上式中变量的解释
u(k): PID的阶段输出,预期dt下的增量,几何意义上是,拟合曲线在当前时间tk下的切线斜率
Kp : 从公式中看出是用来动态调节步伐的,(进小远大)
Ki : 当前偏差的缩放洗漱
Kd : 对前两项值得2次修正调整,使最后的曲线尽可能平滑。 也就是减少扰动

PID参数调整的规则被总结如下(源自论坛)

参数整定找最佳, 从小到大顺序查。
先是比例后积分, 最后再把微分加。
曲线振荡很频繁, 比例度盘要放大。
曲线漂浮绕大弯, 比例度盘往小扳。
曲线偏离回复慢, 积分时间往下降。
曲线波动周期长, 积分时间再加长。
曲线振荡频率快, 先把微分降下来。
动差大来波动慢, 微分时间应加长。
理想曲线两个波, 前高后低四比一。
一看二调多分析, 调节质量不会低。

解决方案

语言采用我熟悉的java,我实现了一套测试环境(模拟锅炉运行环境),基于一些可扩展的想法和某种强迫症,我最终采用了如下设计
类图

PID相关的核心代码如下

class PIDHeat implements Heat{
        float lastError;
        float preError;

        final float P_const = 40f;
        final float I_const = 150f;
        final float D_const = 1f;
        public PIDHeat(){
            preError = lastError = 0;
        }
        private float range(float heatTemp){
            if(heatTemp < 0){
                return 0;
            }
            if(heatTemp > 40){
                return 40;
            }
            return  heatTemp;
        }
        @Override
        public float heat() {
            float currentError = target - current;

            System.out.println("PID params "+ currentError + " " + lastError + " " + preError);

            float heatTemp = P_const * (currentError-lastError)
                    + I_const * currentError
                    + D_const * (currentError + preError -2*lastError);
            preError = lastError;
            lastError = currentError;
            heatTemp = range(heatTemp);
            System.out.println("PID out "+ heatTemp);
            return heatTemp;
        }
    }

类图是后来补的,所以有些出入,但基本正确。
实现的时候采用了java内部类相关的性质,所以如果需要移植到其他语言上去需要做少部分调整。

项目代码存放位置

github仓库链接

Q&A

  • PID算法除了口诀之外,有什么更加直观的方式么?
    在wiki百科上有一张动态图可以提供一定的帮助
    摘自wiki

  • 调整过程中,最后值不收敛,奔着正负无穷去?
    在我的实践中存在开始时dt并不足够小的问题
    方法中存在微分假设,只有在dt足够小下才满足向着最小值收敛的预期,在dt较大时,最终的结果可能会发散向无穷大,这个问题在选择剃度下降下降速率α问题上也有着体现。

reference

https://baike.baidu.com/item/PID%E7%AE%97%E6%B3%95
http://www.arduino.cn/thread-12813-1-1.html
http://www.dfrobot.com.cn/community/thread-14783-1-1.html
http://www.crazepony.com/book/wiki/algorithm-pid.html

猜你喜欢

转载自blog.csdn.net/u010953266/article/details/78428259