什么是PID控制器 PID控制器(比例-积分-微分控制器),由比例单元(P)、积分单元(I)和微分单元(D)组成。可以通过调整这三个单元的增益$k_p$, $k_i$和$k_d$来调整其特性。PID控制器适用于基本上线性,且动态特性不随时间变化的系统。
PID控制器是一个在工业控制应用中常见的反馈回路部件。这个控制器把收集到的数据和一个参考值进行比较,然后把这个差别用于计算新的输入值,这个新的输入值的目的是可以让系统的数据达到或者保持在参考值。PID控制器可以根据历史数据和差别的出现率来调整输入值,使系统更加准确而稳定。
PID控制器的比例单元(P)、积分单元(I)和微分单元(D)分别对应目前误差、过去累计误差及未来误差。若是不知道受控系统的特性,一般认为PID控制器是最适用的控制器。借由调整PID控制器的三个参数,可以调整控制系统,设法满足设计需求。控制器的响应可以用控制器对误差的反应快慢、控制器过冲的程度及系统震荡的程度来表示。不过使用PID控制器不一定保证可达到系统的最佳控制,也不保证系统稳定性。
有些应用只需要PID控制器的部分单元,可以将不需要单元的参数设为零即可。因此PID控制器可以变成PI控制器、PD控制器、P控制器或I控制器。其中又以PI控制器比较常用,因为D控制器对回授噪声十分敏感,而若没有I控制器的话,系统不会回到参考值,会存在一个误差量。
水箱模型1.0 - P 受控模型 以一个简单的水箱模型为例,假设有一个水箱,要从空箱开始注水到某个液位,可以通过控制水龙头的大小来控制注水的速度,用下面的代码来模拟这个过程。
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 """model.py: 定义了PID控制的对象模型类 - Model""" class Model (object ): """接受PID控制的模型类(水箱)。 Attributes: target: 经过控制,最终期望达到的目标值(目标液位)。 curr: 当前达到的值(当前液位) """ def __init__ (self, target=100 ): """初始化""" self.target = target self.curr = 0 def get_leavings (self ): """获取偏差值(剩余容量) Return: 目标值与当前值之差 """ return self.target - self.curr def click (self, val ): """模型进行一次跳动(单位时间注水) Paraments: val: 本次跳动中变化的值(注水量) """ self.curr += val pass
控制器 对于这样的模型,我们只需要通过比例单元来进行控制就可以快速达到期望的液位。数学公式描述如下: $$ u = k_pe $$ 下面的代码实现了一个控制器的类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 """controller.py: 定义了一个PID控制器 - Controller""" class Controller (object ): """PID控制器类 Attributes: kp: 比例参数 """ def __init__ (self, kp = 0.5 ): """初始化""" self.kp = kp pass def click (self, m ): """跳动一次,通过PID计算本次应该变化的量 Paraments: m: 接受控制的模型对象 """ e = m.get_e() u = self.kp * e m.click(u) pass
控制效果 使用下面的代码可以显示$k_p\in(0, 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 from model import Modelfrom controller import Controllerimport matplotlib.pyplot as pltDATA_SIZE = 10 END_TIME = 50 STATIC_KP = False if __name__ == "__main__" : plt.figure(1 ) for i in range (1 , DATA_SIZE): m = Model(100 ) kp = 0.5 if (STATIC_KP) else 1 / DATA_SIZE * i con = Controller(kp) lst = [] for t in range (0 , END_TIME+1 ): con.click(m) lst.append(m.curr) label_str = 'kp=%.1f' % (kp) plt.plot(range (0 , END_TIME+1 ), lst, label=label_str) plt.legend(loc='best' ) plt.show()
不同比例参数$k_p$下的控制曲线如下:
可以看出,随着比例系数$k_p$的增加,达到期望液位的速度就越快。
水箱模型2.0 - PI 在上面的水箱模型中,我们只用了一个比例单元就完成了对液位的控制,现在假设水箱模型有了新的变化,现在,在往水箱注水的同时,水箱也会作为水源向外供水,这里设定水箱向外供水的速度恒定为每个单位时间减5,水箱模型的代码修改如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 def click (self, u ): """模型进行一次跳动 Paraments: val: 本次跳动中变化的值 """ self.curr += u - 5 pass