4. 微分先行PID
任务目标
在标准PID控制中,设定值突变会经微分项产生剧烈输出跳变(微分冲击),可能引起执行机构饱和或系统振荡。本案例实现微分先行PID(Differential-First PID),仅对测量值做微分、不对设定值做微分,从而在设定值阶跃时消除微分冲击,同时保留对测量值波动的抑制能力。
核心算法
微分先行PID的位置式离散实现:
- 比例项:
P = Kp * e(k),其中e(k) = SP(k) - PV(k) - 微分项:仅对测量值求导,
D = -Kd * (PV(k) - PV(k-1)) / Ts - 积分项:
I = Ki * Σ e(i) * Ts(含抗积分饱和) - 输出:
u(k) = P + I + D
与标准PID(微分项作用于误差e(k)-e(k-1))相比,设定值阶跃时PV未变化,因此D=0,输出仅由比例和积分平滑过渡。
完整实现
import matplotlib.pyplot as plt
class DiffFirstPID:
def __init__(self, Kp, Ki, Kd, Ts, u_min=-100.0, u_max=100.0):
self.Kp = Kp
self.Ki = Ki
self.Kd = Kd
self.Ts = Ts
self.u_min = u_min
self.u_max = u_max
self.integral = 0.0
self.prev_pv = None
def reset(self):
self.integral = 0.0
self.prev_pv = None
def compute(self, sp, pv):
# 比例项
e = sp - pv
P = self.Kp * e
# 微分项:仅对测量值微分
if self.prev_pv is None:
D = 0.0
else:
D = -self.Kd * (pv - self.prev_pv) / self.Ts
self.prev_pv = pv
# 积分项(带抗积分饱和)
self.integral += e * self.Ts
I = self.Ki * self.integral
# 合成输出并限幅
u = P + I + D
if u > self.u_max:
u = self.u_max
self.integral -= e * self.Ts # 反算撤销积分增量
elif u < self.u_min:
u = self.u_min
self.integral -= e * self.Ts
return u
# 仿真:设定值阶跃 + 测量值扰动
def simulate():
pid = DiffFirstPID(Kp=2.0, Ki=0.5, Kd=0.8, Ts=0.1)
t = [i * 0.1 for i in range(200)]
sp = [0.0] * 50 + [10.0] * 150 # 5s时设定值阶跃
pv = [0.0] * 50 + [0.0] * 150 # 测量值初始为0
# 在10s处加入测量值阶跃扰动
for i in range(100, 200):
pv[i] = 2.0
u_out = []
pv_track = []
for i in range(len(t)):
u = pid.compute(sp[i], pv[i])
u_out.append(u)
# 模拟被控对象:一阶惯性 + 控制量作用
if i == 0:
pv_track.append(0.0)
else:
dt = 0.1
pv_new = pv_track[-1] + dt * (0.5 * (u - pv_track[-1]))
pv_track.append(pv_new)
# 绘图
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 6), sharex=True)
ax1.plot(t, sp, 'r--', label='设定值 SP')
ax1.plot(t, pv_track, 'b-', label='测量值 PV')
ax1.set_ylabel('数值')
ax1.legend()
ax1.grid(True)
ax2.plot(t, u_out, 'g-', label='控制输出 u')
ax2.set_xlabel('时间 (s)')
ax2.set_ylabel('输出')
ax2.legend()
ax2.grid(True)
plt.tight_layout()
plt.show()
if __name__ == '__main__':
simulate()
运行与验证
运行方式:保存为diff_first_pid.py,执行python diff_first_pid.py,需安装matplotlib。
验证方法:
- 观察输出曲线:在
t=5s设定值阶跃瞬间,控制输出u应平滑上升,无尖峰脉冲——这证明微分冲击已被消除。 - 在
t=10s测量值阶跃扰动时,输出应出现反向调节动作,说明微分项仍对测量值变化敏感。 - 对比验证(可选):将
compute()中微分项改为D = Kd * (e - prev_e)/Ts(标准PID),相同参数下设定值阶跃时输出会出现明显尖峰,可直观对比差异。
通过条件:设定值阶跃时输出无瞬时跳变尖峰,且测量值扰动时控制器能产生有效抑制动作。