Qurak

Make Code Talk

0%

控制算法笔记

目录

  • PID 控制算法
  • 未完待续……

PID 控制算法

PID 算法介绍

u(t)=kpe(t)+ki0te(τ)dτ+kdddte(t)u(t)=k_{p}e(t)+k_{i}\int^{t}_{0}e(\tau)d{\tau}+k_{d}\frac{d}{dt}e(t)

PID 算法的名字就是由它的控制方式来的,P-Proportion 比例单元,I-Integral 积分单元,D-Derivative 微分单元,所以 PID 也叫做 “比例-积分-微分控制算法”。PID 主要适用于基本上线性,且动态特性不随时间变化的系统(也就是 线性时不变系统

从结构上来看,PID 控制本质上就是一个反馈调节的过程,根据实际输出与预设的误差来动态调节。根据误差进行了比例,积分和微分三种调节,对应的参数是 kp,ki,kd。PID 的性能几乎取决于这三个参数的设置,因此调节这三个参数是整个算法最重要的。由于不同的系统对应的参数不尽相同,所以这三个参数需要根据实际情况来调节。

img

上面给出了 PID 数学表达,当我们在编程的时候,更多的时候需要将连续转化为离散的形式,根据定义我们可以得到离散形式的 PID 表达:

u(k)=kpe(t)+kin=0ke(n)+kd[e(k)e(k1)]u(k)=k_{p}e(t)+k_{i}\sum^{k}_{n=0}e(n)+k_{d}[e(k)-e(k-1)]

其实,如果熟悉信号与系统或者数字信号处理,PID 控制器还可以认为是一种滤波器,它的系统函数可以由上面给出的差分形式通过拉普拉斯变换得到:

H(s)=kds2+kps+kis+CH(s)=\frac{k_{d}s^{2}+k_ps+k_{i}}{s+C}

其中,C 是取决于系统带宽的常熟。因此,如果数值挑选不当,容易产生输出的自激震荡而不稳定,此时系统将永远无法达到期望的预设值。

下面具体介绍一下 PID 中 P,I 和 D 控制的含义。

比例控制(Proportion-Control)

比例控制为主要的减小误差方式,根据当前输出与预设值,乘上一定的比例后来调节输出。

我们可以假设有一个水池,我们需要动态调节水位保持在 1m 的深度。这时我们控制的对象(Process)为水阀下次需要加多少水。根据传感器我们可以知道当前的水位 0.2m,因此我们就可以计算出当前的误差 e = 1 - 0.2 = 0.8m。这里我们采用比例调节加水,假设当前比例 kp 为 0.5,我们得到比例控制的输出为 0.8*0.5 = 0.4 m。经过控制器(Process)得到第一次调节后的水位为 0.2 + 0.4 = 0.6m,以此类推。我们推出最后的水位将会无限接近我的预设 1m,在一定精度下可以认为达到预设的 1m 水位。下面采用 Matlab 来简单模拟一下水位的变化:

PID_Matlab_1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
%% Proportion-Control-ideal
clear;
%% 初始化 %%
N = 100; % 离散时间
n = 1:1:N;
target = 100; % 目标
start = 20; % 初始值
r = target*ones(1,N); % 目标参考
u = zeros(1,N); % 实际输出
error = zeros(1,N); % 误差
e_sum = 0;

%% PID 参数
kp = 0.5;
ki = 0;
kd = 0;
miss = 0; % 每次输出减去固定的误差,以形成稳态误差

%% PID 算法
% 初始化
u(1) = start;
error(2) = target - u(1);
e_sum = e_sum + error(2);
de = error(2)-error(1);
u(2) = kp*error(2)+ki*e_sum+kd*de + u(1) - miss;
% PID 调节
for k = 3:1:N
error(k) = target - u(k-1);
e_sum = e_sum + error(k);
de = error(k)-error(k-1);
u(k) = kp*error(k)+ki*e_sum+kd*de+u(k-1) - miss;
end

%% 绘图显示结果
figure;
plot(n, r, '-.');
hold on;
plot(n, u,'--');
legend("target", "present");
xlabel("离散时间 n");
ylabel("水位/cm");
ylim([0,120]);
title("PID 水位控制");

这个时候读者难免会有疑惑,既然比例调节就可以比很快的调节到预设值,那么为什么还要引入积分和微分的控制,这不是会增加算法复杂度和调参的复杂度吗?其实这是因为这里所设置的场景是一个非常理想的情况,然而实际上我们需要考虑水池是否会漏水,水阀防水量存在精度误差……一系列问题,这些考虑实际情况产生的误差我们可以合起来认为是总误差 miss。

这里我们再次利用上面的例子,我们假设上面水池系统的总误差 miss = 10,即每次加水后都会少掉 10 cm = 0.1m,由于我们的比例控制只看当前的输出和预设值的误差,因此当 kp*e = miss 的时候,我们会发现我们控制水阀加水的量等于损失的量,此时水阀还在放水,但是水位已经不会变化了。我们把这个稳定的误差称为 稳态误差。下面是 Matlab 模拟的水位变化:

PID_Matlab_2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
% Proportion-Control-miss
clear;
%% 初始化 %%
N = 100; % 离散时间
n = 1:1:N;
target = 100; % 目标
start = 20; % 初始值
r = target*ones(1,N); % 目标参考
u = zeros(1,N); % 实际输出
error = zeros(1,N); % 误差
e_sum = 0;

%% PID 参数
kp = 0.5;
ki = 0;
kd = 0;
miss = 10; % 每次输出减去固定的误差,以形成稳态误差

%% PID 算法
% 初始化
u(1) = start;
error(2) = target - u(1);
e_sum = e_sum + error(2);
de = error(2)-error(1);
u(2) = kp*error(2)+ki*e_sum+kd*de + u(1) - miss;
% PID 调节
for k = 3:1:N
error(k) = target - u(k-1);
e_sum = e_sum + error(k);
de = error(k)-error(k-1);
u(k) = kp*error(k)+ki*e_sum+kd*de+u(k-1) - miss;
end

%% 绘图显示结果
figure;
plot(n, r, '-.');
hold on;
plot(n, u,'--');
legend("target", "present");
xlabel("离散时间 n");
ylabel("水位/cm");
ylim([0,120]);
title("PID 水位控制");

稳态误差在实际的工程中是十分常见的,例如控制马达转速,在运行时马达会受到摩擦力;控制温度时,由于热传导和热辐射会损失一部分热量……因此消除这个误差还是十分必要的。为了消除这个稳态误差,我们便引入了 积分控制

积分控制(Integral-Control)

从比例控制的例子我们知道了当系统存在固定的误差 miss 时,我们还简单采用 P 控制则会形成稳态误差,无法达到我们的预设值。因此我们引入了积分控制 I:

Iout=ki0te(τ)dτI_{out}=k_{i}\int^{t}_{0}e(\tau)d{\tau}

积分控制会把过去的误差也考虑进来,将过去一段时间的误差综合乘上一个系数 ki 得到一个平均误差,但由于系统在不断累积中会产生震荡,因此最后的结果一般都不会是平稳的收敛到预设值,而是在预设值附近震荡。继续使用上面的例子,我们加入积分控制系数 ki = 0.5:

PID_Matlab_3
1
2
3
4
5
%% PID 参数
kp = 0.5;
ki = 0.5;
kd = 0;
miss = 10; % 每次输出减去固定的误差,以形成稳态误差

从仿真的结果来看,我们可以很明显看到在加入积分控制后,虽然我们成功消除了稳态误差达到了预设值,但是我们的 PID 控制输出并不是平稳地收敛到预设值,而是产生了震荡,然后逐渐收敛到预设值。积分控制会加速系统趋近预设值的过程,并且消除稳态误差。积分增益越多、趋近预设值的速度越快,不过同样会因为累加而产生过冲的现象。

不过有的时候,我们细心调教参数后还是可以近似平稳地收敛到预设值。但是大多数情况引入积分控制器都会是系统不稳定、震荡。为了解决积分器产生的震荡,我们引入微分控制来消抖。

微分控制(Derivative-Control)

微分控制不同于积分控制考虑过去的累加效果,考虑了将来的误差,对系统的输出做出快速反应。因此含有 kd 的 PID 也被称为可与则的控制器。kd 对减少控制器短期的改变很有帮助,能够达到消抖的功能。

Dout=kdddte(t)D_{out}=k_{d}\frac{d}{dt}e(t)

微分控制器可以提升稳定性,但也因微分系统不是因果系统,所以在 PID 实现的时候,需要加上一个低通滤波以限制高频噪声。(不过实际上大约只有 20% 的PID控制器用到了微分控制)

下面我们在积分控制的基础上加一点微分控制 kd = 0.24,来看看效果如何:

PID_Matlab_4
1
2
3
4
5
%% PID 参数
kp = 0.5;
ki = 0.5;
kd = 0.24;
miss = 10; % 每次输出减去固定的误差,以形成稳态误差

我们可以看到幅度上有所削弱,由于之前的 kp 和 ki 没有调整好,所以效果可能不是很明显,但根据上图我们仍可以看出加入了微分控制后,整体上加快了稳定过程。(不过随着 kd 的变大,会产生尖刺,系统在收敛时也会有一段不大稳定的阶段。)

PID 参数调节

虽然 PID 整体上不难,但是在实际应用中要找到一对合适的系数来优化实际系统还是比较难的。由于目前笔者还没有丰富的调参经验,就在网上查阅了相关资料,简单介绍一下调参的方式。

  1. 人工调参
    最典型的做法是先将所有 k 均置零,调节 kp 直到回路起振,然后再将 kp 设置为 “1/4 振幅衰减”,然后增加 ki 直到一定时间后稳态误差被修正。最后根据情况调节 kd 或者 ki 和 kp 来使系统趋于稳定。
    PID_Compensation_Animated

    调整方式 上升时间 超调量 安定时间 稳态误差 稳定性
    P 减少 增加 小幅增加 减少 变差
    PI 小幅减少 增加 增加 大幅减少 变差
    PID 小幅减少 减少 减少 变动不大 变好
  2. 齐格勒·尼科尔斯方法
    这是齐格勒·尼科尔斯在 1940 年导入的,一开始也是将 ki 与 kd 设置为 0,增加 kp 直到系统开始等幅震荡为止,此时增益称为 ku 时,而在振荡周期为 Pu,采用以下方式计算:

    控制器种类 kp ki kd
    P 0.5ku - -
    PI 0.45ku 1.2kp/Pu -
    PID 0.6ku 2kp/Pu kpPu/8
  3. 软件工具

    大部分现代的工业设备不再用上述人工计算的方式调试,而是用PID调试及最佳化软件来达到一致的效果。软件会收集资料,建立模型,并提供最佳的调试结果,有些软件甚至可以用参考命令的变化来进行调试。

    数学的PID调试会将脉冲加入系统,再用受控系统的频率响应来设计PID的参数。若是响应时间要数分钟的系统,建议用数学PID调试,因为用试误法可能要花上几天才能找到可让系统稳定的参数。最佳解不太容易找到,有些数位的回路控制器有自我调试的程序,利用微小的参考命令来计算最佳的调试值。

PID 算法改进

参考:

PID控制器 - 维基百科,自由的百科全书

PID控制算法原理(抛弃公式,从本质上真正理解PID控制)


(未完待续……)