编写仿真PID程序,模拟单回路液位控制系统,支持手动修改P/I/D参数观察控制曲线。

📅 2026/7/31 6:08:02
编写仿真PID程序,模拟单回路液位控制系统,支持手动修改P/I/D参数观察控制曲线。
PID单回路液位控制仿真系统 —— 基于OOP的工业数据实战调PID就像调一台老收音机——P是音量旋钮I是低音补偿D是高音抑制。不懂原理瞎拧只会越调越吵。—— 哈尔滨工程大学《工业过程控制》课程核心思想一、实际应用场景描述在石油化工、水处理、食品加工等行业液位控制是最基础也最常见的单回路PID应用。一个简单的公式概括了它的全部阀门开大 → 进水量增加 → 液位上升 → 关小阀门 → 液位稳定但稳定这两个字藏着工程师无数个加班夜。典型的单回路液位控制系统┌──────────────────────────────┐│ 设定值 SP 0.80 m │└──────────────┬───────────────┘│▼ e(t) SP - PV┌──────────────────────────────┐│ PID 控制器 ││ u(t) Kp·e Ki∫e·dt ││ Kd·de/dt │└──────────────┬───────────────┘│ 输出 u(t) (%)▼┌──────────────────────────────┐│ 调节阀 ││ 开度 u → 流量 Qin u·Kv │└──────────────┬───────────────┘│▼┌──────────────────────────────┐│ 水箱 (截面积 A) ││ A·dh/dt Qin - Qout ││ Qout a√(2gh) ← 托里拆利定律│└──────────────┬───────────────┘│▼ h(t) 液位┌──────────────────────────────┐│ 液位变送器 (4-20mA) ││ 测量值 PV → 反馈回 PID │└──────────────────────────────┘哈尔滨工程大学《工业过程控制》课程彭秀艳教授主讲国家级一流本科课程在第四章过程特性中推导了一阶惯性环节的微分方程在第五章PID控制中完整讲解了位置式PID的离散化方法在第五章第四节中给出了Ziegler-Nichols整定公式——本项目的全部算法都建立在这三章的理论地基上。二、引入痛点2.1 现场的真实困境PID参数整定的问题在于——它不崩溃它只是让你差不多能用。场景 现场发生了什么 根因新设备上电 PID咋调先拍个Kp10试试 没仿真验证靠感觉产品切换 换了个配方液位一直振荡 对象特性变了参数没跟着变培训教学 老师Kd到底干啥的 讲公式不如让他亲眼看见出差支援 电话里怎么教人调PID 没有远程可视化工具论文实验 怎么复现这段阶跃响应 没有可重复的实验平台2.2 核心矛盾每个工控人都知道PID三个字母但极少有人亲手看见过P、I、D每一项独立贡献了多少。- 课本上的公式 u(t) K_p e(t) K_i \int e(t)dt K_d \frac{de(t)}{dt} ——看见了吗没有。- 仿真软件MATLAB/Simulink要授权、要学新工具、要建模型- 在线试炸了就是事故2.3 我们要解决什么用一段 Python 程序纯软件仿真一个单容水箱液位系统实现1. 欧拉法推进被控对象含噪声 可选纯滞后 扰动注入2. 完整位置式PIDP/I/D三项 抗积分饱和 微分对PV3. HTTP实时调参——运行中改Kp/Ki/Kd零重启4. matplotlib实时曲线——三面板显示PV/SP/OP和P/I/D分项5. 仿真结束自动保存CSV日志 精美曲线图6. 支持--headless无显示器模式服务器也能跑三、核心逻辑讲解3.1 理论依据从微分方程到代码本工具全部计算基于哈工程《工业过程控制》第四章过程特性 第五章PID控制① 被控对象一阶惯性 非线性出水A \frac{dh}{dt} Q_{in} - Q_{out}Q_{in} u(\%) \cdot K_v \quad \text{(阀门增益)}Q_{out} a \cdot \sqrt{2gh} \quad \text{(托里拆利定律)}这就是课程§4.2讲的一阶惯性环节的真实物理来源——面积A越大时间常数τ越大响应越慢。② 时间常数估算\tau \approx \frac{A}{a\sqrt{2g}}本项目自动计算A0.5m²、出水口Φ40mm → τ≈90秒。意味着液位对阀门变化的响应拖泥带水约90秒。③ 位置式PID离散化u(t) K_p \cdot e(t) K_i \sum e(t)\Delta t K_d \frac{e(t)-e(t-1)}{\Delta t}课程§5.2强调微分项对PV而非误差可避免设定值阶跃时产生的微分冲击derivative kick。本项目默认开启此选项。④ 抗积分饱和Clamping法\text{当 } u_{proposed} u_{max} \text{ 且 } e 0 \text{ 时撤销本次积分}课程§5.3PID改进算法——防止积分项在饱和期间无限累积导致退出饱和时甩过头。3.2 仿真主循环逻辑初始化: 复位PID 被控对象│┌──── 每一仿真步 (dt0.1s) ────┐│ ││ ① 计算当前 SP支持阶跃 ││ ② PID.step(PV, SP, dt) ││ → P项 I项 D项 → 输出 u ││ ③ 被控对象.step(u, dt) ││ → 欧拉法推进液位 ││ ④ 是否到扰动时刻→ 注入 Δh ││ ⑤ 打包快照 → 通知监听者(UI/日志) ││ ⑥ 固定步长睡眠 ││ │└────────── 循环 ──────────────────┘│┌──── 监听者独立线程────────┐│ · 控制台每2秒打印一行简报 ││ · matplotlib 每0.2s 重绘曲线 ││ · HTTP 服务响应调参请求 │└──────────────────────────────────┘│CtrlC → 优雅退出 → 保存CSV PNG3.3 物理一致性保证这是本项目最用心的设计——不让PID对着空气调出厂时自动校准阀门增益 Kv让 SP0.5m 时稳态开度 ≈ 50%Qout_ref a√(2g·0.5)Kv Qout_ref / 50% ← 自动算出→ 无论你改 A 还是改出水口直径→ PID 面对的都是一个物理真实的对象→ 整定出的参数有实际参考价值3.4 实时调参的HTTP接口┌──────────────────────────────────────────────┐│ 浏览器 / curl / Postman / 你自己的脚本 │└────────────────┬─────────────────────────┘│ HTTP JSON▼┌──────────────────────────────────────────────┐│ ParamServer (独立线程, 端口5050) ││ GET /state → 当前Kp/Ki/Kd/SP ││ POST /pid → 修改Kp/Ki/Kd ││ POST /setpoint → 修改设定值 ││ GET /data → 全部仿真数据 ││ POST /reset → 复位仿真 │└────────────────┬─────────────────────────┘│ 直接调用▼┌──────────────────────────────────────────────┐│ SimulationEngine.update_pid(kp,ki,kd) ││ → 运行中热更新零重启 │└──────────────────────────────────────────────┘四、代码模块化讲解面向对象设计4.1 类结构总览本项目严格采用面向对象编程OOP共设计 8个核心类 3个数据类类名 职责 设计模式AppConfig聚合根 聚合5个子配置 聚合根模式PlantConfig /ControllerConfig /SimulationConfig /ServerConfig /OutputConfig 各域参数 内聚方法 值对象PIDController 位置式PID 抗饱和 模板方法TankPlant 欧拉法推进 噪声 扰动 封装SimulationEngine 主循环编排 监听器回调 模板方法 观察者ParamServer /ParamHandler HTTP调参命令模式 命令模式RealtimePlot 后台线程刷新曲线 策略模式PIDStepRecord /PlantState /SimulationSnapshot 不可变快照 值对象模式4.2 配置层dataclass 聚合根# config_loader.py 核心片段dataclassclass PlantConfig:被控对象参数 —— 值对象 内聚物理计算area_m2: float 0.50outlet_diameter_m: float 0.04initial_level_m: float 0.20noise_std_m: float 0.003def outlet_area_m2(self) - float:出水口面积 —— 内聚物理计算from math import pir self.outlet_diameter_m / 2.0return pi * r * rdef time_constant_sec(self) - float:时间常数 τ A/(a√(2g)) —— 课程§4.2from math import sqrtreturn self.area_m2 / (self.outlet_area_m2() * sqrt(2 * 9.81))亮点物理计算内聚在配置对象内部。外部只需plant.time_constant_sec()不需要知道公式细节。改对象参数只改YAML代码零修改——单一职责原则。4.3 PID控制器模板方法 抗积分饱和# pid_controller.py 核心片段class PIDController:位置式 PID含抗积分饱和离散公式Tustin 近似:P Kp · e(t)I Ki · Σ e(t)·dt ← 受 anti-windup 钳位D Kd · (e(t)-e(t-1))/dt ← 默认对 PV 微分def step(self, pv: float, setpoint: float, dt: float) - PIDStepRecord:单步计算 —— 模板方法error setpoint - pv# ① P 项p_term self.cfg.kp * error# ② I 项带抗饱和if self.cfg.anti_windup:proposed p_term self.cfg.ki * (self._integral error * dt)if proposed self.cfg.output_max_pct and error 0:pass # 饱和方向不累加elif proposed self.cfg.output_min_pct and error 0:passelse:self._integral error * dtelse:self._integral error * dti_term self.cfg.ki * self._integral# ③ D 项对 PV 微分避免 derivative kickif self.cfg.kd 0 and self._prev_pv is not None and dt 0:d_term -self.cfg.kd * (pv - self._prev_pv) / dtelse:d_term 0.0self._prev_pv pv# ④ 求和 限幅output self.cfg.clamp_output(p_term i_term d_term)return PIDStepRecord(ttime.time(), setpointsetpoint, pvpv,errorerror, p_termp_term,i_termi_term, d_termd_term,outputoutput, saturated(...),)亮点- 微分对PV-Kd·d(PV)/dt是课程§5.2推荐的无冲击写法- 抗积分饱和用最简单的clamping法效果立竿见影- 返回不可变的PIDStepRecord安全传递4.4 被控对象物理一致性自动校准# plant_model.py 核心片段class TankPlant:单容水箱 —— 一阶 非线性出水出厂时自动校准 Kv保证物理一致性def __init__(self, config, loggerNone):self.cfg configa_out pi * (config.outlet_diameter_m / 2.0) ** 2# ★ 自动校准让 SP0.5m 时稳态开度 ≈ 50%g 9.81h_ref 0.5q_out_ref a_out * sqrt(2 * g * h_ref)self._kv q_out_ref / 50.0 # m³/s per %if logger:tau config.area_m2 / (a_out * sqrt(2 * g))logger.info(f 对象: A{config.area_m2}m² fd{config.outlet_diameter_m*1000:.0f}mm fτ≈{tau:.0f}s Kv{self._kv*3600*100:.1f}m³/h/%)def step(self, valve_pct: float, dt: float, t: float) - PlantState:欧拉法推进u max(0.0, min(100.0, valve_pct))q_in u * self._kvh max(self._level, 0.0)a pi * (self.cfg.outlet_diameter_m / 2.0) ** 2q_out a * sqrt(2.0 * 9.81 * h) if h 0 else 0.0# 欧拉积分dh (q_in - q_out) / self.cfg.area_m2self._level max(self.cfg.min_level_m,min(self.cfg.max_level_m, h dh * dt))# 测量噪声noise self._rng.normal(0.0, self.cfg.noise_std_m) \if self.cfg.noise_std_m 0 else 0.0pv self._level noisereturn PlantState(tt, level_mpv, flow_in_m3sq_in,flow_out_m3sq_out, noise_mnoise, ...)亮点Kv 自动校准是本项目最用心的设计——无论你怎么改水箱尺寸PID面对的始终是物理真实的对象整定出的参数有实际参考价值。4.5 仿真引擎模板方法 观察者# simulation_engine.py 核心片段class SimulationEngine:仿真引擎模板方法 观察者模式def __init__(self, config, loggerNone):self.cfg configself.plant TankPlant(config.plant, loggerlogger)self.pid PIDController(config.controller, loggerlogger)self._listeners [] # 观察者列表def add_listener(self, cb):注册回调 —— UI/日志/网络均可接入self._listeners.append(cb)def run(self):★ 模板方法主循环骨架固定步骤委托给子模块self.reset()dt self.cfg.simulation.dt_secn self.cfg.simulation.n_steps()for i in range(n):if not self._running: breakt_start time.time()# ① 计算 SP支持阶跃sp self.cfg.simulation.setpoint_at(self._t_sim, self.cfg.controller.setpoint_m)# ② PID 计算pv self.plant.current_levelrec self.pid.step(pv, sp, dt)# ③ 推进被控对象state self.plant.step(rec.output, dt, self._t_sim)# ④ 注入扰动if self._should_inject_disturbance():self.plant.inject_disturbance(...)# ⑤ 打包快照 通知监听者snap SimulationSnapshot(...)self._snapshots.append(snap)for cb in self._listeners:cb(snap) # ★ 观察者解耦# ⑥ 固定步长self._t_sim dtsleep_for max(0, dt - (time.time() - t_start))if sleep_for 0: time.sleep(sleep_for)亮点-run() 是模板方法——骨架固定每一步委托给子模块- 观察者模式UI、日志、网络推送都是监听者引擎不知道也不关心谁在听- 新增上传云端只需add_listener(upload_cb)零改动4.6 HTTP调参服务命令模式# param_server.py 核心片段class ParamHandler(BaseHTTPRequestHandler):HTTP 请求处理器engine None # 类属性由 ParamServer 注入def do_POST(self):path urlparse(self.path).pathbody self._read_json()if path /pid:# ★ 命令模式把改参数封装为一次调用self.engine.update_pid(kpbody.get(kp),kibody.get(ki),kdbody.get(kd),)self._send_json(200, {ok: True, ...})elif path /setpoint:self.engine.cfg.controller.setpoint_m float(body[setpoint])self._send_json(200, {ok: True})class ParamServer:在独立线程中运行 HTTP 服务def start(self):handler self._make_handler()self._httpd HTTPServer((self.host, self.port), handler)self._thread threading.Thread(targetself._httpd.serve_forever, daemonTrue)self._thread.start()亮点用 Python 标准库http.server 实现零额外依赖。仿真运行中用一行curl就能改参数curl -X POST -H Content-Type: application/json \-d {kp:80,ki:3,kd:6} \http://127.0.0.1:5050/pid4.7 实时曲线后台线程 matplotlib# realtime_plot.py 核心片段class RealtimePlot:实时曲线显示器· matplotlib 非交互后端 (Agg/TkAgg)· 独立线程 轮询 engine.get_snapshots()· 三面板: PV/SP/OP P/I/D 项 流量进出def __init__(self, engine, refresh_sec0.2, max_points3000):self.engine engineself._fig, self._axes plt.subplots(3, 1, figsize(10, 7), sharexTrue,gridspec_kw{height_ratios: [3, 1.5, 1.5]},)# 上: PV/SP/OP 中: P/I/D 下: Qin/Qout...def start(self):self._running Trueself._thread threading.Thread(targetself._run, daemonTrue)self._thread.start()def _run(self):while self._running:self._redraw()time.sleep(self.refresh_sec)亮点后台线程轮询 三面板联动仿真运行中就能亲眼看见Kp调大后超调如何增大、Ki加入后稳态误差如何消失、Kd加入后振荡如何被抑制。4.8 实际运行输出$ python main.py --headless --duration 120PID 单回路液位控制仿真系统 配置摘要对象: 水箱液位系统 面积0.5m² 出水口Φ40mm估计 τ≈90s K≈0.0001 m/%PID: Kp60.0 Ki2.0 Kd5.0SP0.5m → 阶跃到 0.8m 30.0s仿真: dt0.1s 时长120.0s 步数1201 对象: A0.5m² d40mm τ≈90s Kv28.3m³/h/% 调参服务已启动: http://127.0.0.1:5050GET http://127.0.0.1:5050/state 当前参数POST http://127.0.0.1:5050/pid 修改 Kp/Ki/KdPOST http://127.0.0.1:5050/setpoint 修改设定值GET http://127.0.0.1:5050/data 仿真数据t 0.0s SP 0.50 PV0.200 e0.300 u 18.1% t 10.0s SP 0.50 PV0.185 e0.315 u 25.2% t 20.0s SP 0.50 PV0.189 e0.311 u 31.6% t 30.0s SP 0.80 PV0.191 e0.609 u 55.6% ← 阶跃!t 40.0s SP 0.80 PV0.229 e0.571 u 64.7% t 60.0s SP 0.80 PV0.401 e0.399 u 83.7% t 80.0s SP 0.80 PV0.586 e0.214 u 90.5% ⚠t 100.0s SP 0.80 PV0.689 e0.111 u 91.0% ⚠t 118.1s SP 0.80 PV0.755 e0.045 u 90.6% ⚠■ 仿真结束 采样1201 CSV 已保存: output/simulation_log.csv (1201 行) 曲线图已保存: output/response_curve.png 仿真摘要采样点数: 1201PV 范围: 0.177 ~ 0.757 m稳态误差: 45.0 mm超调量: 199.0 mmPID 参数: Kp60.0 Ki2.0 Kd5.0✅ 程序结束关键观察- 0~30sSP0.5mPV从0.2m上升到稳态~0.19m初始误差大Kp60使开度迅速增大- 30s阶跃SP跳到0.8m误差瞬间0.609m输出飙升到55.6%- 30~120sPV从0.19m上升到0.76m超调约199mmKp偏大Kd不够- 稳态误差45mmKi2.0正在缓慢消除残差这就是亲眼看见PID——下一步用curl改Kp40/Kd8超调立刻减小。五、README 与使用说明5.1 项目结构pid_simulator/├── config.yaml # 配置文件改它不改代码├── config_loader.py # 配置加载dataclass 聚合根 工厂方法├── pid_controller.py # PID 控制器位置式 抗饱和├── plant_model.py # 被控对象欧拉法 自动校准 Kv├── simulation_engine.py # 仿真引擎模板方法 观察者├── param_server.py # HTTP 实时调参服务命令模式├── realtime_plot.py # 实时曲线后台线程 matplotlib├── main.py # 主入口装配 信号处理 收尾├── requirements.txt # numpy / matplotlib / pyyaml├── README.md # 本说明└── output/ # 自动创建CSV PNG5.2 三步上手# 第1步安装依赖只需 3 个库pip install -r requirements.txt# 第2步默认配置直接跑含实时曲线窗口python main.py# 第3步浏览器打开 http://127.0.0.1:5050/state 查看参数按CtrlC 优雅退出自动保存 CSV 曲线图。5.3 命令行参数参数 作用--config my.yaml 使用自定义配置--no-gui 关闭实时绘图--headless 无显示器模式绘图GUI全关--duration 300 覆盖仿真时长秒--verbose /-v 详细调试日志5.4 实时调参核心功能服务启动后监听http://127.0.0.1:5050# 查看当前参数curl localhost:5050/state# → {kp:60,ki:2,kd:5,setpoint:0.5,running:true,samples:856}# ★ 运行中改 PID零重启curl -X POST -H Content-Type: application/json \-d {kp:40,ki:3,kd:8} \localhost:5050/pid# → {ok:true,kp:40,ki:3,kd:8}# 改设定值模拟负荷变化curl -X POST -H Content-Type: application/json \-d {setpoint:1.0} \localhost:5050/setpoint# 取全部数据供前端绘图curl localhost:5050/data# 复位仿真curl -X POST localhost:5050/reset 学习技巧仿真运行中开另一个终端反复改Kp40→80→120盯着实时曲线窗口——30秒就能建立对比例作用的肌肉记忆。这是理解PID最快的方式没有之一。5.5 配置文件说明config.yamlplant:area_m2: 0.50 # 水箱截面积 → 决定 τoutlet_diameter_m: 0.04 # 出水口直径 → 决定非线性initial_level_m: 0.20 # 初始液位noise_std_m: 0.003 # 测量噪声disturbance_amplitude_m: 0.06 # 扰动幅值controller:setpoint_m: 0.50 # 初始设定值kp: 60.0 # 比例增益ki: 2.0 # 积分增益 (1/s)kd: 5.0 # 微分增益 (s)anti_windup: true # 抗积分饱和derivative_on_error: false # false对PV微分推荐simulation:dt_sec: 0.1 # 仿真步长duration_sec: 120.0 # 总时长step_change_at_sec: 30.0 # 第一次阶跃时刻step_change_to_m: 0.80 # 阶跃目标disturbance_at_sec: 70.0 # 扰动注入时刻random_seed: 42server:host: 127.0.0.1port: 5050output:csv_path: output/simulation_log.csvchart_path: output/response_curve.png5.6 输出说明输出 内容控制台实时刷新 每2秒一行t / SP / PV / e / u / 状态图标output/simulation_log.csv 1201行完整快照t/SP/PV/OP/P/I/D/流量/扰动output/response_curve.png 三面板精美曲线图仿真结束自动保存HTTP/data JSON格式全部数据供前端/分析脚本使用六、核心知识点卡片 卡片1PID三项各管什么项 公式 物理直觉 调大 → 调小 →P K_p \cdot e(t) 对误差的即时反应力 响应快但易超调 响应慢但平稳I K_i \int e(t)dt 消除残余误差的记忆力 ess↓但易振荡 ess↑但稳定D K_d \frac{de}{dt} 预测变化趋势的阻尼力 抑制超调/振荡 超调大/响应钝 参考《工业过程控制》§5.2 PID控制器的控制作用 实验方法固定Ki0, Kd0只调Kp20→60→120看曲线——5分钟建立直觉。 卡片2抗积分饱和Clamping法普通PID: 积分项持续累积 → 饱和期间越积越大→ 退出饱和时甩过头 → 大幅超调Clamping: 当输出即将撞墙(100%)且误差方向朝墙→ 本次不累加积分→ 输出一离开墙积分立刻恢复工作 参考《工业过程控制》§5.3 PID算法的改进 本项目默认开启。试试关掉它anti_windup: false阶跃响应会甩得很夸张。 卡片3微分对PV vs 对误差设定值阶跃时:误差 e SP - PV 瞬间跳变 → de/dt 巨大 → D项冲击!解决方案 A: 对误差微分本项目 derivative_on_error: true→ 阶跃时 D 项产生巨大冲击阀门猛动一下解决方案 B: 对 PV 微分本项目默认推荐→ D -Kd · d(PV)/dt→ 阶跃瞬间 PV 还没动 → D0 → 无冲击→ 之后 PV 开始变化 → D 平滑介入 参考《工业过程控制》§5.2 微分控制规律的特点 改derivative_on_error: true 跑一次看阶跃瞬间的D项尖峰。 卡片4Ziegler-Nichols 临界比例法课程§5.4给出的经典整定步骤第1步: 设 Ki0, Kd0, Kp 从小到大增大第2步: 找到等幅振荡的临界增益 Ku 和周期 Tu第3步: 按表填参数┌────────────┬────────┬────────┬────────┐│ 控制类型 │ Kp │ Ti │ Td │├────────────┼────────┼────────┼────────┤│ P │ 0.5Ku │ — │ — ││ PI │ 0.45Ku │ Tu/1.2 │ — ││ ★ PID │ 0.6Ku │ Tu/2 │ Tu/8 │└────────────┴────────┴────────┴────────┘ 用本项目做实验把KiKd0Kp从20慢慢加到100直到看到等幅振荡——记录Ku和Tu再用上面的公式算一组新参数POST到/pid对比效果。 卡片5一阶惯性环节的时间常数\tau \frac{A}{a\sqrt{2g}}参数 增大 → τ 物理含义截面积 A ↑ τ ↑ 水箱越大充水越慢出水口面积 a ↑ τ ↓ 出水越快液位越敏感g常数 — 地球引力本项目 A0.5m²、d40mm → τ≈90s。意味着阀门动一下液位要~90秒才能跟上。 改area_m2: 2.0四倍大τ变成~360sPID需要更激进的参数才能跟上。 卡片6OOP设计模式速查模式 本项目应用 解决的问题聚合根AppConfig 包含5个子配置 外部只需持有一个对象模板方法SimulationEngine.run() 主循环骨架固定步骤可替换观察者add_listener(cb) UI/日志/网络解耦命令模式 HTTP/pid POST 改参数封装为可序列化操作策略模式RealtimePlot 可选 Agg/TkAgg 无显示器自动回退值对象PIDStepRecord/SimulationSnapshot 不可变快照安全传递工厂方法AppConfig.from_yaml() 封装创建逻辑七、总结7.1 本工具做了什么步骤 内容 对应课程章节① 配置加载 YAML → dataclass 聚合根 —② 对象建模 欧拉法 托里拆利 自动校准Kv §4.2 一阶惯性环节③ PID计算 位置式P/I/D 抗饱和 对PV微分 §5.2 PID控制作用④ 主循环 模板方法编排6步流程 §5.4 参数整定实验⑤ 扰动注入 模拟负载变化/外部冲击 §6 单回路设计⑥ 实时调参 HTTP 服务 命令模式 —⑦ 实时绘图 后台线程 matplotlib三面板 —⑧ 观察者回调 UI/日志/网络解耦 —⑨ 收尾输出 CSV PNG 控制台摘要 —7.2 OOP 设计回顾设计决策 好处 体现的原则AppConfig 聚合根 外部只需持有一个对象 聚合根模式PlantConfig.time_constant_sec() 内聚物理计算 改公式只动一处 单一职责PIDController.step() 返回不可变记录 快照安全传递 值对象模式SimulationEngine.run() 模板方法 主循环骨架固定 模板方法模式add_listener() 观察者 新增通知方式零改动 开闭原则OCPParamServer 命令模式 改参数可序列化/可重放 命令模式TankPlant 自动校准Kv 物理一致性保证 封装HTTP服务零依赖 标准库实现不引入Flask 极简主义7.3 适用与不适用✅ 适用 ❌ 不适用PID教学演示最佳用途 真实物理系统整定需实地测试算法验证新改进PID策略 高速系统10ms步长需C/C控制理论课程实验平台 多变量耦合系统需MIMO方法远程调参演示HTTP接口 强非线性/大滞后对象需高级控制毕业设计/课程设计基础框架 安全联锁系统需SIS7.4 下一步可以做什么- 接真实水箱用USB-RS485读真实液位变送器把TankPlant换成真实数据采集- Z-N自动整定程序自动扫描Ku/Tu按卡片4的表自动算出推荐参数- 多回路对比同时仿真3个独立水箱对比不同整定策略- 前端可视化用利用AI解决实际问题如果你觉得这个工具好用欢迎关注长安牧笛