1. 模糊PID基础整定
任务目标
针对一阶惯性系统,设计一个模糊PID控制器。控制器根据误差e和误差变化率ec,通过模糊规则在线调整ΔKp、ΔKi、ΔKd,叠加到初始PID参数上,使系统对阶跃输入实现无超调且快速的响应。
被控对象与控制器结构
被控对象为一阶惯性系统(含纯滞后可选):
G(s) = K * e^(-τs) / (T*s + 1)
本案例取 K=2,T=5,τ=0.5。控制器采用增量式模糊PID,结构如下:
- 输入:e(k)、ec(k) = e(k) − e(k−1)
- 模糊量化:e、ec 归一化到 [−1, 1],论域取 [−3, 3],量化因子 Ke=1.0,Kec=3.0
- 输出:ΔKp、ΔKi、ΔKd,比例因子 Kp0=1.2,Ki0=0.15,Kd0=0.4
- 模糊规则:7×7 规则表,隶属函数采用三角形,重心法解模糊
完整实现代码
import numpy as np
import matplotlib.pyplot as plt
# ---------- 模糊隶属函数与规则 ----------
def trimf(x, a, b, c):
return np.maximum(0, np.minimum((x-a)/(b-a+1e-9), (c-x)/(c-b+1e-9)))
# 7个语言值: NB, NM, NS, ZO, PS, PM, PB
centers = [-3, -2, -1, 0, 1, 2, 3]
def membership(x):
"""返回x在7个模糊集合上的隶属度"""
mu = np.zeros(7)
for i, c in enumerate(centers):
mu[i] = trimf(x, c-1, c, c+1)
return mu
# 模糊规则表: 行=ec, 列=e, 值=输出语言值索引(0~6)
# 规则设计原则: 大误差时强比例作用, 小误差时增强积分消除静差
rule_table = {
'Kp': np.array([
[6, 6, 5, 5, 4, 3, 2],
[6, 5, 5, 4, 3, 2, 2],
[5, 5, 4, 3, 2, 2, 1],
[5, 4, 3, 2, 1, 1, 1],
[4, 3, 2, 1, 1, 0, 0],
[3, 2, 2, 1, 0, 0, 0],
[2, 2, 1, 0, 0, 0, 0],
]),
'Ki': np.array([
[0, 0, 1, 2, 3, 4, 5],
[0, 1, 1, 2, 3, 4, 5],
[1, 1, 2, 3, 4, 5, 5],
[1, 2, 3, 4, 5, 5, 6],
[2, 3, 4, 5, 5, 6, 6],
[3, 4, 5, 5, 6, 6, 6],
[4, 5, 5, 6, 6, 6, 6],
]),
'Kd': np.array([
[3, 2, 1, 1, 1, 2, 3],
[2, 2, 1, 0, 1, 2, 2],
[1, 1, 0, 0, 0, 1, 1],
[1, 0, 0, 0, 0, 0, 1],
[1, 1, 0, 0, 0, 1, 1],
[2, 2, 1, 0, 1, 2, 2],
[3, 2, 1, 1, 1, 2, 3],
])
}
def fuzzy_infer(e, ec):
"""输入e, ec(已量化到[-3,3]), 返回ΔKp, ΔKi, ΔKd(归一化[-1,1])"""
mu_e = membership(np.clip(e, -3, 3))
mu_ec = membership(np.clip(ec, -3, 3))
outputs = {}
for name, table in rule_table.items():
num = 0.0
den = 0.0
for i in range(7):
for j in range(7):
w = mu_e[i] * mu_ec[j]
if w > 0:
num += w * centers[table[i][j]]
den += w
outputs[name] = num / (den + 1e-9) / 3.0 # 归一化到[-1,1]
return outputs['Kp'], outputs['Ki'], outputs['Kd']
# ---------- 一阶惯性系统仿真 ----------
def plant_model(y, u, dt, K=2.0, T=5.0, tau=0.5):
"""一阶惯性+纯滞后, 使用欧拉法离散"""
# 纯滞后用延迟数组近似
return y, u # 实际延迟在仿真主循环中处理
# 仿真参数
dt = 0.1
t_end = 30.0
t = np.arange(0, t_end, dt)
n = len(t)
# 初始化
y = np.zeros(n)
u = np.zeros(n)
e_prev = 0.0
y_delay = np.zeros(int(0.5/dt) + 1) # 纯滞后缓冲
# PID参数初始值
Kp_base, Ki_base, Kd_base = 1.2, 0.15, 0.4
Kp, Ki, Kd = Kp_base, Ki_base, Kd_base
# 量化因子
Ke, Kec = 1.0, 3.0
# 输出比例因子
Gp, Gi, Gd = 0.5, 0.05, 0.2
# 阶跃输入
r = np.ones(n) * 1.0
# 主循环
for k in range(1, n):
# 当前实际输出(带滞后)
if k < len(y_delay):
y_cur = 0.0
else:
y_cur = y_delay[0]
e = r[k] - y_cur
ec = e - e_prev
e_prev = e
# 模糊推理
e_q = np.clip(e * Ke, -3, 3)
ec_q = np.clip(ec * Kec, -3, 3)
dKp, dKi, dKd = fuzzy_infer(e_q, ec_q)
# 更新PID参数
Kp = Kp_base + dKp * Gp
Ki = Ki_base + dKi * Gi
Kd = Kd_base + dKd * Gd
# 增量式PID
du = Kp * (e - e_prev) + Ki * e * dt + Kd * (e - 2*e_prev + 0) / dt
u[k] = np.clip(u[k-1] + du, -5, 5)
# 更新被控对象(一阶惯性)
dy = (K * u[k] - y_delay[-1]) / T * dt
y_delay = np.roll(y_delay, 1)
y_delay[0] = y_delay[1] + dy
y[k] = y_delay[0]
# ---------- 结果可视化 ----------
plt.figure(figsize=(10, 5))
plt.subplot(2, 1, 1)
plt.plot(t, r, 'k--', label='设定值')
plt.plot(t, y, 'b-', label='模糊PID响应')
plt.ylabel('输出')
plt.legend()
plt.grid(True)
plt.subplot(2, 1, 2)
plt.plot(t, u, 'r-', label='控制量')
plt.xlabel('时间 (s)')
plt.ylabel('控制量')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.savefig('fuzzy_pid_result.png', dpi=100)
plt.show()
# 性能指标计算
overshoot = max(0, (np.max(y) - 1.0) / 1.0 * 100)
idx_settle = np.where(np.abs(y - 1.0) > 0.02)[0]
settle_time = t[idx_settle[-1]] if len(idx_settle) > 0 else 0
print(f"超调量: {overshoot:.2f}%")
print(f"调节时间(±2%): {settle_time:.1f}s")
运行方式
pip install numpy matplotlib
python fuzzy_pid.py
验证方法与通过标准
- 运行后应生成
fuzzy_pid_result.png,包含输出响应曲线和控制量曲线 - 通过条件:输出曲线无超调(超调量≈0%),调节时间(进入±2%误差带)小于15秒,稳态误差为0
- 对比验证:将模糊规则表全部置为0(即固定PID参数),同条件下系统超调约15%~20%,调节时间约20秒,可验证模糊整定的效果
关键说明
- 模糊规则表的设计核心:大误差时增大Kp加快响应,小误差时增大Ki消除静差,误差变化大时增大Kd抑制超调
- 量化因子Ke、Kec和比例因子Gp、Gi、Gd需要根据实际系统调整,本案例参数已针对G(s)=2e^(-0.5s)/(5s+1)整定
- 纯滞后通过延迟缓冲数组实现,若被控对象无滞后,可将τ设为0并移除延迟逻辑