PID算法:如何考虑长时间延迟后的快速输入值变化

电器工程 Arduino 控制 控制系统 pid控制器 算法
2022-01-18 05:42:03

我正在尝试在 Arduino Leonardo 上实现一个基本的 PID 算法,以使用伺服控制阀混合冷热水。目标是将温度保持在尽可能接近设定点。尤其重要的是防止输出温度超过设定值,以保护用户免受灼伤。其次重要的是尽快使温度接近设定点。

对于温度的微小变化,PID 算法的标准实现似乎可以正常工作。但我不知道如何解释等待热水到达阀门时可能发生的长时间延迟,因为这些延迟比改变阀门位置后的标准延迟要长得多。

显然,根据热水管路的长度和自上次使用热水以来的时间,热水可能需要数十秒才能到达阀门,因此在此期间,水温在低温下保持相当恒定热水阀很快打开 100%。积分分量开始累积很大的误差值。

当热水最终到达阀门时,检测到的温度会迅速上升到最高热水温度。由于积分误差大,热水阀在温度超过设定值后长时间保持在100%,等待积分值降低到正常水平。因此,结果是几(几十)秒的最高温度水。

我不确定如何解释这种可能的长时间延迟。在这种情况下,设置积分误差值的上限(和下限)以限制最大响应时间是否明智?这似乎违背了积分组件的目的,并且在达到设定点后仍然会施加一些滞后。

或者有没有更好的方法来处理长时间延迟后的快速输入变化?

感谢您的任何建议!

4个回答

您的问题称为Integral Windup,这是一个常见的控制问题。在非线性或其他有界区域中,控制器无法跟踪设定点,并且积分增加到一个很大的值。当最终达到设定点时,这会导致很大的超调,这正是您推断出的问题。

最简单的解决方案是将积分器值本身限制在合理的最大值。限制积分贡献也不会起作用,因为积分器仍然会被清盘到某个较大的值。

Mathworks 有一个页面,其中包含积分饱和的其他一些解决方案。

在 PID 控制器中,您通常需要尽可能少的积分项。在标准的机械温度控制阀中,仅使用比例控制,它们工作正常。保持积分项尽可能小 - 用户不会注意到最终温度的小错误。您可能会发现仅使用 PD 即可获得可接受的性能。

由于这是一个非常特殊的已知案例,您可能会考虑为控制器设置不同的模式。测量热入口温度,当它低于设定值时,热运行 100%,冷运行 20%。当它预热时,切换到具有良好初始条件的 PID。

有效控制这一过程的关键是要认识到冷热水龙头不是对称运行的,任何优化算法都必须考虑到这一点。

当您一段时间不使用热水时,它会在管道中冷却。

当您有一段时间不使用冷水时,它会保持原样(除非冷水来自带有冷却器的冷水箱,这在炎热的夏天会很棒,但我投注在实践中相当罕见)。

因此,我们假设我们不知道我们从热水管中得到了什么,但我们可以依靠冷水管在整个运行过程中几乎是恒定的。

因此,根据混合水的温度,知道阀门设置,以及对冷水温度的估计,我们可以估计当前来自热水管的水有多热。然后您可以调整阀门以在没有 PID 的情况下获得正确的输出温度,仅基于对热力学公式的评估。

要获得“冷水温度的估计”,您可以在循环开始时运行冷水一小段时间(可能是几秒钟)并读取温度。然后假设它此后不会改变,因为您没有足够的数据来解决这两个温度。

这个方案不会完全准确,但我估计它会可靠地进入球场,而不会出现剧烈过冲的可能性。然后在此方案之上运行 PID 以微调结果,但将更改限制在允许 PID 产生的阀门设置。当热水输入温度发生显着变化时,可能会重置 PID 状态。

使用多个温度传感器可以实现更高级的解决方案。

我只是想在上面的好答案中添加一个细节,即控制工程师为整体发条可能性所做的工作。这也发生在许多工业过程中,它是一门艺术而不是科学。

在不牺牲性能规范可能真正需要的积分增益的情况下,有一些典型的教科书行动反对这一点。

  1. 每次您越过零错误级别时,您都会重置积分器。这使得积分器成为按需积分器类型的非线性元件,而不是盲累加器。

  2. 您基本上将积分动作输入块连接到循环中的指示元素。这可能是积分器的输出,用于判断它是否开始了构建(这需要了解过程才能做出正确的判断)。或者您检查执行器是否饱和,并根据该信息形成反馈回路。我只是随机选择了来自 google 的第一个链接,在这个视频的结尾有我最后一点的图形解释。https://www.youtube.com/watch?v=H4YlL3rZaNw

有时,对于系统操作范围的粗粒度阶段,拥有多组 PID 参数会很有帮助,当系统从一个行为阶段过渡到另一个行为阶段时,您可以随时更改这些参数。例如,一组 Kp、Ki 和 Kd 用于当您打开热水龙头并只获得冷水时;然后一旦你开始看到温度上升,切换到另一组 Kp、Ki 和 Kd。然后相应地调整两者。

您是否在 Brett Beauregard 的 Arduino Playground 中使用 PID 库?这个挺好看的。那里也有一个“自适应”的例子。