Python实现PID控制基于simple_pid库

本文将通过案例介绍基于simple_pid库实现PID控制系统。但不涉及PID的原理(案例的完整代码在文末)(案例程序借鉴了我学习simple_pid库时的案例)

这是simpel_pid库的官方介绍:

A simple and easy to use PID controller in Python. If you want a PID controller without external dependencies that just works, this is for you! The PID was designed to be robust with help from Brett Beauregards guide.
Translation from Jason:Python中的一个简单并且容易使用的PID控制器。如果你想要一个不依靠外部环境的PID控制器,这正好适合你。设计更加具有鲁棒性的PID controller,可以从 Brett Beauregards guide得到帮助。

正如官网所说的那样,这个PID controller 真的非常容易使用。

下面是来自官方的程序框架:

from simple_pid import PID
pid = PID(1, 0.1, 0.05, setpoint=1)

# assume we have a system we want to control in controlled_system
v = controlled_system.update(0)

while True:
    # compute new ouput from the PID according to the systems current value
    control = pid(v)

    # feed the PID output to the system and get its current value
    v = controlled_system.update(control)

这个程序是不能运行的,因为这个程序里面并没有被控制的系统(controlled_system),这个被控制的系统(controlled_system)是需要我们来决定的。
我们只需要在这个框架中加入由我们设计的需要被控制的系统并调整PID controller 的三个参数(比例系数:Kp,积分系数:Ki,微分系数:Kd)就可以完成一个由PID controller 控制的完整闭环系统,因此这个是非常容易使用的PID contraller 。

PID controller 的三个环节的作用:

比例环节:与系统响应有关,比例系数Kp :决定系统的响应速度

积分环节: 累计误差,使输出更接近target,通过调整积分系数Ki,调节为积环节的作用,Ki过大会产生过冲现象。

微分环节: 通过对误差微分,减小响应的振动,通过调节微分系数Kd,调节微分环节的作用。

以加热房间为例:

创建模型:

class heater:
    def __init__(self):
        self.temp = 25
    def update(self, power, dt):
        if power > 0:
             
            #加热时房间温度随变量power和时间变量dt 的变化
            self.temp += 2 * power * dt
        #表示房间的热量损失
        self.temp -= 0.5 * dt
        return self.temp

变量temp是整个系统的输出,它反映的是变量power的情况,变量power是我们用PID controller 控制的变量。dt 是时间变量。

将模型参数写进程序框架

if __name__ == '__main__':
	#将创建的模型写进主函数
    heater = heater()
    temp = heater.temp
	#设置PID的三个参数,以及限制输出
    pid = PID(2, 0.01, 0.1, setpoint=temp)
    pid.output_limits = (0, None)
	#用于设置时间参数
    start_time = time.time()
    last_time = start_time
	#用于输出结果可视化
    setpoint, y, x = [], [], []
	#设置系统运行时间
    while time.time() - start_time < 10: 
       	
       	#设置时间变量dt
        current_time = time.time()
        dt = (current_time - last_time)
        
        #变量temp在整个系统中作为输出,变量temp与理想值之差作为反馈回路中的输入,通过反馈回路调节变量power的变化。
        power = pid(temp)
        temp = heater.update(power, dt)
        
        #用于输出结果可视化
        x += [current_time - start_time]
        y += [temp]
        setpoint += [pid.setpoint]
		#用于变量temp赋初值
        if current_time - start_time > 0:
            pid.setpoint = 100

        last_time = current_time
	
	#输出结果可视化
    plt.plot(x, setpoint, label='target')
    plt.plot(x, y, label='PID')
    plt.xlabel('time')
    plt.ylabel('temperature')
    plt.legend()
    plt.show()

输出结果:

Python实现PID控制基于simple_pid库_第1张图片
可以观察到,系统超调量几乎为零,震荡次数也几乎为零,系统表现比较好。这是因为系统得到反馈的频率非常高。

通过修改PID的三个参数,来观察参数对系统响应的影响。

更改PID的三个参数,我们会得一个不好的系统。

增大比例系数Kp

将语句:

    pid = PID(2, 0.01, 0.1, setpoint=temp)

改为:

    pid = PID(100, 0.01, 0.1, setpoint=temp)

输出结果:此时系统的超调量非常大,但是响应非常快,并且其存在下降趋势可知,最终还是会收敛与target。
Python实现PID控制基于simple_pid库_第2张图片

增大积分系数Ki

将语句:

    pid = PID(2, 0.01, 0.1, setpoint=temp)

改为:

    pid = PID(2, 1, 0.1, setpoint=temp)

输出结果:此时系统超调量较大,但相比更改比例系数,系统的响应相对缓慢。是因为比例系数较小。但是存在较大的积分系数,累计误差对系统的影响太大,依旧存在超调,但是最终还是会收敛于target。
Python实现PID控制基于simple_pid库_第3张图片

增大微分系数Kd

将语句:

    pid = PID(2, 0.01, 0.1, setpoint=temp)

改为:

    pid = PID(2, 0.01, 10, setpoint=temp)

输出结果:由于巨大的微分系数Kp,系统存在过冲现象,他最终不会收敛与target。
Python实现PID控制基于simple_pid库_第4张图片

根据官方提示:如果按固定的时间间隔对PID算法进行评估,那么PID算法的性能最好。如果算法知道这个区间,我们也可以简化一些内部的数学运算。

通过添加语句:

pid.sample_time = 0.01

将PID controller改为:

    pid = PID(2, 0.01, 0.1, setpoint=temp)
    pid.output_limits = (0, None)
    pid.sample_time = 0.01

输出结果:系统表现的提升表现并不明显,这是因为在之前的系统中PID controller 接收到反馈的频率已经很快了,所以系统的表现不会有明显的提高。
Python实现PID控制基于simple_pid库_第5张图片

你可能感兴趣的:(Cybernetics,机器学习,算法,python)