为什么较低的delta会导致我的PID控制器以较低的精度进行调整?

Vol*_*ort 6 java algorithm

我不完全确定这是否是正确的问题.嗯,我想这一个编程问题.


我正在尝试用Java创建一个简单的PID控制器模拟.

简而言之,存在目标值和当前值.当前值由数字修改.您为PID控制器提供当前值,它将尝试返回一个数字,希望这个数字将使当前值接近目标值.加班,你使用PID控制器的次数越多,它就会"学习"(使用积分和导数),并最终会返回越来越准确的值.这对于通过控制车轮运动来维持船的平衡是有用的.


PID控制器使用的公式非常通用且非常简单 - 或者我认为.在下面的示例中,PID控制器返回的值只是添加到当前值.我认为它适用于更复杂的应用程序(涉及乘法或除法等).这是我的计划:

public class PID {

    private static double Kp = 0.1;
    private static double Kd = 0.01;
    private static double Ki = 0.005;

    private static double targetValue = 100.0;
    private static double currentValue = 1.0;

    private static double integral = 0.0;
    private static double previousError = 0.0;

    private static double dt = 0.5;

    private static double max = 5;
    private static double min = -5;

    public static void main(String[] args) throws Exception {
        while (true) {
            Thread.sleep((long) (1000.0 * dt));
            double error        = targetValue - currentValue;
            double derivative   = 0.0;
            double output       = 0.0;
            integral = integral + error * dt;
            derivative          = (error - previousError) / dt;
            output              = Kp * error + Ki * integral + Kd * derivative;
            previousError         = error;
            if (output > max) output = max;
            if (output < min) output = min;

            // Apply the output to the current value:
            System.out.println(currentValue + " + " + output + " = " + (currentValue + output));
            currentValue += output;
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

如果运行此操作,您将看到PID控制器最终设法使当前值非常接近目标值.

它太酷了.现在,我希望看到我的结果更快一点(因为我计划制作某种交互式图形),所以我决定将delta更改dt0.1.

唉,结果价值不再接近100!现在它似乎达到105,然后,非常,减少到100.这不好!

现在想象dt一下0.01!现在它达到102非常慢,现在它甚至没有回到100,现在它只是不断增加!

所以我的问题是:为什么较低的delta会导致这种情况?

我的代码基于这个PDF文档,它们使用0.01得很好.

Les*_*sto 1

这很容易,你会得到一个完整的结束。

请注意,“积分”不限制增长,但您将输出的效果限制在 [-5, 5] 范围内

有很多解决方案,我的转储修复是限制最小值和最大值之间的积分。

通过该修复,循环时间为 0.5、0.1 和 0.01 的情况下,不会出现大于数字的过冲(但也限制导数)

限制导数可以通过使用与防止“导数踢”相同的技巧来解决:使用先例和实际值之间的差异而不是误差之间的差异。请注意,您还需要反转符号

但如果你需要尽可能快地模拟具有任意值的 dt 的 PID,只需注释 sleep 即可!