PID是“比例-积分-微分控制器”(Proportional-Integral-Derivative Controller)的缩写,是一种广泛应用于工业控制系统的反馈控制技术。PID控制器通过计算当前误差(目标值与实际值之间的差异)来调整控制输出,以使系统达到并保持在设定的目标值。下面我将详细解释PID的三个组成部分及其工作原理。
1. 比例(P)控制
定义:比例控制是根据当前误差的大小来调整控制输出的部分。
工作原理:当误差(目标值与实际值之间的差)增大时,比例控制会提供一个与误差成正比例的输出。这意味着,误差越大,控制输出的调整就越大。
公式:
其中:
是比例增益(一个常数,用于调节比例控制的强弱)。
e(t)是当前的误差。
优点:快速响应。
缺点:可能会导致稳态误差(即系统在稳定状态时仍然与目标值存在差异)。
2. 积分(I)控制
定义:积分控制是根据过去的误差累积来调整控制输出的部分。
工作原理:积分作用使得控制器关注系统长时间的误差。通过对误差的累积(积分),可以消除稳态误差。这意味着即使是小的持续误差,积分控制也会逐步增加控制输出,直到误差消失。
公式:
其中:
是积分增益。
是误差随时间的积分(累积)。
优点:消除稳态误差。
缺点:可能导致系统过冲(超过目标值)和振荡,尤其在增益设置不当时。
在离散系统中,积分被替换为离散时间步长的累加,用矩形法(或梯形法)近似: 。为了避免每次都计算整个历史累加(计算量大),通常采用递推形式,即只基于上一次的结果更新:
。
3. 微分(D)控制
定义:微分控制是根据误差变化率来调整控制输出的部分。
工作原理:微分作用预测误差的未来趋势。它通过观察误差的变化速度来提供一个快速的反应,以减小系统的过冲和振荡。
公式:
其中:
是微分增益。
是误差的变化率。
优点:提高系统的稳定性,减少振荡。
缺点:对噪声敏感,可能导致控制不稳定。
在离散系统中,时间以采样点k表示,导数通过前后两个采样点的误差差值近似: 。因此,离散微分项D(k)可表示为:
,当前时刻的误差。
:前一时刻的误差。
:采样周期。
:微分增益,控制微分项的强度。 这是一种向后差分法(Backward Difference),是最简单的离散微分近似。
4. PID 控制器的综合输出
将三部分结合在一起,PID控制器的输出可以表示为:
其中,u(t) 是控制器的最终输出。通过调整、
和
的值,可以优化控制器的性能,以适应特定的系统需求。
唉,实际上人生也可以看作一个动态调节的过程,通过实时反馈(P)、经验积累(I)和趋势预测(D)来调整自己的行为,以实现目标。就比如考研,模拟考英语只有40分(目标70分),偏差30分。应该立刻调整策略,每天多背50个单词、做两篇阅读理解,而不是盲目增加其他科目时间。P项的特点是快速反应,但若过于依赖“当下”(比如只顾眼前的分数而忽略长期规划),可能导致复习不全面。而我当时没有这个简单的觉悟。
示例代码:
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['font.size'] = 12
plt.rcParams['axes.linewidth'] = 1.5
plt.rcParams['xtick.direction'] = 'in'
plt.rcParams['ytick.direction'] = 'in'
plt.rcParams['lines.linewidth'] = 2.0
class PIDController:
def __init__(self, Kp, Ki, Kd, setpoint):
self.Kp = Kp
self.Ki = Ki
self.Kd = Kd
self.setpoint = setpoint
self.integral = 0
self.prev_error = 0
def compute(self, pv, dt):
error = self.setpoint - pv
P = self.Kp * error
self.integral += error * dt
I = self.Ki * self.integral
derivative = (error - self.prev_error) / dt
D = self.Kd * derivative
output = P + I + D
self.prev_error = error
return output
def system_model(pv, control_signal, dt, tau=1.0):
dpv_dt = (-pv + control_signal) / tau
pv_next = pv + dpv_dt * dt
return pv_next
dt = 0.1
time = np.arange(0, 100, dt)
setpoint = 10.0
pv = 0.0
control_signals = []
pvs = []
Kp = 1.0
Ki = 0.1
Kd = 0.05
pid = PIDController(Kp, Ki, Kd, setpoint)
for t in time:
control_signal = pid.compute(pv, dt)
pv = system_model(pv, control_signal, dt)
control_signals.append(control_signal)
pvs.append(pv)
fig = plt.figure(figsize=(10, 8), facecolor='#F5F5F5')
fig.suptitle('PID 控制器仿真', fontsize=16, fontweight='bold', y=0.95)
ax1 = plt.subplot(2, 1, 1)
ax1.plot(time, pvs, label='过程值 (PV)', color='#1F77B4', linewidth=2.5)
ax1.plot(time, [setpoint] * len(time), '--', label='设定值 (SP)', color='#FF7F0E', linewidth=2)
ax1.set_ylabel('值', fontsize=12)
ax1.set_title('过程值与设定值', fontsize=14, pad=10)
ax1.grid(True, linestyle='--', alpha=0.6, color='gray')
ax1.set_facecolor('#FFFFFF')
ax1.legend(loc='upper right', fontsize=10, frameon=True, edgecolor='black')
ax1.spines['top'].set_visible(False)
ax1.spines['right'].set_visible(False)
ax2 = plt.subplot(2, 1, 2)
ax2.plot(time, control_signals, label='控制信号', color='#2CA02C', linewidth=2.5)
ax2.set_xlabel('时间 (秒)', fontsize=12)
ax2.set_ylabel('控制信号', fontsize=12)
ax2.set_title('控制信号输出', fontsize=14, pad=10)
ax2.grid(True, linestyle='--', alpha=0.6, color='gray')
ax2.set_facecolor('#FFFFFF')
ax2.legend(loc='upper right', fontsize=10, frameon=True, edgecolor='black')
ax2.spines['top'].set_visible(False)
ax2.spines['right'].set_visible(False)
plt.tight_layout(rect=[0, 0, 1, 0.92])
plt.show()