补充前馈+增益调度(MFC 结构)的 README 文档
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
# 气体流量控制与阀门开环标定
|
||||
|
||||
本项目基于艾莫迅 **MT2-AM8 模拟量采集/输出模块**,提供三个可独立运行的入口:
|
||||
本项目基于艾莫迅 **MT2-AM8 模拟量采集/输出模块**,提供三个可独立运行的在线入口和两个离线工具:
|
||||
|
||||
- [main.py](main.py):以 10 Hz 周期运行单回路气体流量增量式 PID 闭环控制;
|
||||
- [open_loop.py](open_loop.py):随机扫描阀门开度,采集阀前/阀后的压力与流量,用于开环标定、动态特性观察和临界压力比分析。
|
||||
- [main.py](main.py):以 10 Hz 周期运行单回路气体流量闭环控制,支持增量式 PID,并可选“前馈反解打底 + PI 修残差”与按阀前压力缩放增益的增益调度;
|
||||
- [open_loop.py](open_loop.py):随机扫描阀门开度,采集阀前/阀后的压力与阀后流量,用于开环标定、动态特性观察和临界压力比分析。
|
||||
- [test_valve.py](test_valve.py):在 Windows 终端中手动切换阀门开度,同时观察并记录流量、压力和电机行程。
|
||||
- [identify_valve.py](identify_valve.py):离线从开环扫点 CSV 拟合阀特性表,产出供前馈使用的 `valve_model.json`。
|
||||
- [test_valve_model.py](test_valve_model.py):阀特性模型与前馈反解的离线自测,不接触硬件。
|
||||
|
||||
三个入口都会持续保存 CSV,并在运行结束时为有效采样数据生成 PNG 曲线图。闭环程序还会持续进行滑动窗口稳态判定,并在首次达到稳态时输出一次控制性能报告。
|
||||
三个在线入口都会持续保存 CSV,并在运行结束时为有效采样数据生成 PNG 曲线图。闭环程序还会持续进行滑动窗口稳态判定,并在首次达到稳态时输出一次控制性能报告。
|
||||
|
||||
## 重要安全说明
|
||||
|
||||
@@ -35,10 +37,11 @@
|
||||
| --- | ---: | --- |
|
||||
| 闭环/阀后压力 | `AI0` | `config.PRESSURE_INPUT_CHANNEL` |
|
||||
| 闭环/阀后流量 | `AI1` | `config.FLOW_INPUT_CHANNEL` |
|
||||
| 开环阀前压力 | `AI2` | `open_loop.PRESSURE_BEFORE_CHANNEL` |
|
||||
| 开环阀前流量 | `AI3` | `open_loop.FLOW_BEFORE_CHANNEL` |
|
||||
| 阀前压力(前馈/增益调度/开环共用) | `AI2` | `config.PRESSURE_BEFORE_CHANNEL` / `open_loop.PRESSURE_BEFORE_CHANNEL` |
|
||||
| 电机位置指令 | `AO1` | `config.MOTOR_OUTPUT_CHANNEL` |
|
||||
|
||||
> 控流阀前的流量传感器(原 `AI3`)已删除,`open_loop.FLOW_BEFORE_CHANNEL` 现为 `None`:开环 CSV 的 `flow_before_slm` 列与 PNG 中的 “Flow before valve” 曲线将保持为空。
|
||||
|
||||
开度与行程的默认映射为:
|
||||
|
||||
```text
|
||||
@@ -143,13 +146,58 @@ NEAR -> FAR :|error| >= far_threshold,连续满足 10 个采样周期
|
||||
|
||||
运行中修改目标后,模式确认计数会清零。如果尚无有效流量,或新目标相对最后有效流量的误差大于 `near_threshold`,控制器立即回到 `FAR`;若误差仍处于 NEAR 阈值内,则保持当前模式。PID 的累计输出和误差历史不会因修改目标而整体重置,性能报告器则会重置并从新目标重新计时、判稳和统计超调。
|
||||
|
||||
### 前馈 + 增益调度(MFC 结构)
|
||||
|
||||
闭环默认仍为纯增量式 PID;在确认阀前压力接线、并用 [identify_valve.py](identify_valve.py) 拟合出阀特性表后,可切换到“前馈反解打底 + PI 修残差”的市面 MFC 结构,并可叠加按阀前压力缩放增益的增益调度。
|
||||
|
||||
静态阀特性建模为:
|
||||
|
||||
```text
|
||||
Q_ss = A_eff(x) · P1_abs · F(r)
|
||||
|
||||
F(r) 为压比函数,r = P2_abs / P1_abs:
|
||||
阻塞流(r <= 0.528)时 F = 1;
|
||||
亚声速(0.528 < r < 1)时按 ISO 6358 椭圆平滑衰减;
|
||||
r >= 1 时无正向流,F = 0。
|
||||
```
|
||||
|
||||
开启前馈后,控制周期内的输出计算变为:
|
||||
|
||||
```text
|
||||
前馈开度 opening_ff = 反解(目标流量, 阀前压 P1, 阀后压 P2)
|
||||
PI 修正量 correction = PI(目标流量 - 实测流量) # 输出限幅改为对称 ±带
|
||||
开度 = clamp(opening_ff + correction, 0, 100)
|
||||
```
|
||||
|
||||
即前馈把开度送到稳态工作点附近,PI 只负责修正模型残差和动态偏差;PI 输出不再是 `0~100%` 的全行程,而是围绕前馈的小幅修正(限幅由 `FEEDFORWARD_CORRECTION_BAND_PCT` 控制,默认 ±20%)。前馈无法反解时(例如压比下无正向流、压力缺失)会自动退化为纯 PID。
|
||||
|
||||
增益调度把 FAR/NEAR 的 Kp、Ki 按阀前绝对压力缩放,摊平 K_x ∝ P1 的非线性:
|
||||
|
||||
```text
|
||||
scale = GAIN_SCHEDULE_REF_ABS_KPA / max(P1_abs, GAIN_SCHEDULE_FLOOR_ABS_KPA)
|
||||
Kp_eff = scale · Kp_base,Ki_eff = scale · Ki_base # Kd 不调度
|
||||
```
|
||||
|
||||
`scale` 相对变化超过 `GAIN_SCHEDULE_SCALE_CHANGE_THRESHOLD`(默认 5%)才重算并写入 PID,避免每个周期都更新增益。
|
||||
|
||||
三项均通过 `config.py` 中的开关启用,默认全部关闭:
|
||||
|
||||
| 开关 | 默认 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `FEEDFORWARD_ENABLED` | `False` | 启用前馈反解打底 + PI 修残差 |
|
||||
| `GAIN_SCHEDULE_ENABLED` | `False` | 启用按阀前压力缩放 Kp/Ki |
|
||||
| `VALVE_MODEL_PATH` | `""` | 阀特性表 JSON 路径(空串 = 关闭前馈) |
|
||||
| `PRESSURE_BEFORE_CHANNEL` | `2` | 阀前压力 P1 的 AI 通道 |
|
||||
|
||||
前馈生效需同时满足:`FEEDFORWARD_ENABLED=True`、`VALVE_MODEL_PATH` 指向有效 JSON、`PRESSURE_BEFORE_CHANNEL` 与 `PRESSURE_INPUT_CHANNEL` 均已配置。任一条件缺失时自动退化为纯 PID,并在启动日志中提示。
|
||||
|
||||
### 运行输出
|
||||
|
||||
每次闭环运行会产生:
|
||||
|
||||
1. **终端与日志**:约每秒输出一次状态;非 `OK` 状态立即输出。日志保存到 `logs/flow_control.log`。
|
||||
2. **逐周期 CSV**:默认保存为 `data/flow_run_YYYYMMDD_HHMMSS.csv`,每行写入后立即刷新到磁盘。现有 `data/日期/实验说明/` 子目录是历史数据的人工归档方式,不是程序自动创建的层级。
|
||||
3. **三联曲线图**:结束时保存同名 PNG,依次显示目标/实际流量、阀门开度和压力。
|
||||
3. **三联曲线图**:结束时保存同名 PNG,依次显示目标/实际流量、阀门开度和压力;启用前馈时,开度子图会叠加虚线显示前馈开度。
|
||||
4. **性能报告**:首次达到稳态时写入终端和日志;若整个运行过程未达到稳态,只输出未达到稳态的提示。
|
||||
|
||||
闭环 CSV 字段:
|
||||
@@ -159,7 +207,11 @@ NEAR -> FAR :|error| >= far_threshold,连续满足 10 个采样周期
|
||||
| `time_s` / `timestamp` | 相对运行时间 / Unix 时间戳 |
|
||||
| `target_flow_slm` / `measured_flow_slm` | 目标流量 / 实测流量 |
|
||||
| `opening_pct` / `motor_position` | 阀门开度 / 电机行程 |
|
||||
| `pressure_kpa` | 压力;未启用或读取失败时为空 |
|
||||
| `pressure_kpa` | 阀后压力;未启用或读取失败时为空 |
|
||||
| `pressure_before_kpa` | 阀前压力 P1;未启用或读取失败时为空 |
|
||||
| `feedforward_pct` | 前馈开度;未启用前馈时为空 |
|
||||
| `correction_pct` | PI 修正量(±带内);未启用前馈时为空 |
|
||||
| `gain_scale` | 增益调度缩放系数;未启用调度时为 `1.0` |
|
||||
| `error_slm` | `目标流量 - 实测流量` |
|
||||
| `actual_dt_s` | 实际控制周期 |
|
||||
| `status` | `OK` 或传感器读取重试状态 |
|
||||
@@ -177,10 +229,10 @@ NEAR -> FAR :|error| >= far_threshold,连续满足 10 个采样周期
|
||||
|
||||
## 开环扫点实验
|
||||
|
||||
[open_loop.py](open_loop.py) 不参与闭环反馈,也不会被 `main.py` 导入。默认将 `0%~100%`、间隔 `10%` 的 11 个开度按固定随机种子 `42` 打乱,然后逐点执行:
|
||||
[open_loop.py](open_loop.py) 不参与闭环反馈,也不会被 `main.py` 导入。默认将 `0%~100%`、间隔 `5%` 的 21 个开度按固定随机种子 `42` 打乱,然后逐点执行:
|
||||
|
||||
```text
|
||||
写入开度 -> 每 0.1 s 采集阀前/阀后压力与流量
|
||||
写入开度 -> 每 0.1 s 采集阀前/阀后压力与阀后流量
|
||||
-> 等待阀后流量稳定,或等待满 60 s
|
||||
-> 切换到下一个开度
|
||||
```
|
||||
@@ -207,7 +259,7 @@ std <= max(STEADY_STATE_STD_PCT / 100 * |窗口均值|, MIN_ABS_STD_SLM)
|
||||
|
||||
默认窗口为 10 秒,绝对标准差下限为 `0.05 SLM`。阀后流量连续 5 次读取失败会中止实验;其他通道读取失败会在对应 CSV 字段中留空。
|
||||
|
||||
输出保存到 `open_loop_data/open_loop_YYYYMMDD_HHMMSS.csv/.png`,日志保存到 `logs/open_loop.log`。PNG 包含三张子图:阀前/阀后压力、阀前/阀后流量、阀后绝对压力与阀前绝对压力之比。
|
||||
输出保存到 `open_loop_data/open_loop_YYYYMMDD_HHMMSS.csv/.png`,日志保存到 `logs/open_loop.log`。PNG 包含三张子图:阀前/阀后压力、阀前/阀后流量、阀后绝对压力与阀前绝对压力之比。由于阀前流量传感器已删除,“阀前流量”曲线与 `flow_before_slm` 列保持为空。
|
||||
|
||||
压力比按下式计算:
|
||||
|
||||
@@ -236,6 +288,29 @@ python test_valve.py
|
||||
|
||||
> 此脚本不会调用 `config.validate_config()`,也没有闭环/开环程序中的流量越限、压力越限或连续读取失败保护。运行前应人工完成配置核对,并确保测试人员能够立即切断气源或执行急停。
|
||||
|
||||
## 阀特性辨识与离线自测
|
||||
|
||||
前馈需要一张 `A_eff(x)` 阀特性表。先用 [open_loop.py](open_loop.py) 扫点得到开环 CSV,再用 [identify_valve.py](identify_valve.py) 离线拟合:
|
||||
|
||||
```powershell
|
||||
python identify_valve.py --csv open_loop_data/open_loop_YYYYMMDD_HHMMSS.csv --out valve_model.json [--tail 20] [--plot]
|
||||
```
|
||||
|
||||
- 按 `step_index` 分组,每组取末尾 `--tail` 个采样点平均,得到稳态 `(行程 x, 流量 Q, 阀前压 P1, 阀后压 P2)`;
|
||||
- 对每个稳态点反解 `A_eff = Q / (P1_abs · F(r))`;
|
||||
- 按行程升序构表并做单调性检查;若整体非单调,只保留最长单调连续段,其余点丢弃并给出警告;
|
||||
- 用 [valve_model.py](valve_model.py) 存成 JSON,并打印阻塞/亚声速点数等摘要;加 `--plot` 额外生成诊断图。
|
||||
|
||||
将 `config.VALVE_MODEL_PATH` 指到该 JSON、确认 `PRESSURE_BEFORE_CHANNEL` 接线无误、并把 `FEEDFORWARD_ENABLED` 设为 `True` 后,闭环即可启用前馈。
|
||||
|
||||
[test_valve_model.py](test_valve_model.py) 是纯计算离线自测,不接触硬件,可在任意环境运行:
|
||||
|
||||
```powershell
|
||||
python test_valve_model.py
|
||||
```
|
||||
|
||||
它校验压比函数 `F(r)`、绝对压力换算、`A_eff` 插值与前馈反解互逆,以及 `identify_valve` 端到端辨识。
|
||||
|
||||
## 安全与故障处理
|
||||
|
||||
### 闭环
|
||||
@@ -283,6 +358,14 @@ python test_valve.py
|
||||
| `PID_MODE_SWITCH_CONFIRM_CYCLES` | `10` | 模式切换条件需连续满足的采样周期数(当前约 1 秒) |
|
||||
| `MOTOR_CLOSED_POSITION` / `MOTOR_OPEN_POSITION` | `1000` / `800` | 当前反向控制区间;打开端为机械死区边界 |
|
||||
| `INITIAL_OPENING_PCT` | `100` | 闭环 PID 内部初始输出 |
|
||||
| `PRESSURE_BEFORE_CHANNEL` | `2` | 阀前压力 P1 的 AI 通道(前馈/增益调度/开环共用);可设为 `None` |
|
||||
| `VALVE_MODEL_PATH` | `""` | 阀特性表 JSON 路径;空串关闭前馈 |
|
||||
| `FEEDFORWARD_ENABLED` | `False` | 是否启用前馈反解打底 + PI 修残差 |
|
||||
| `FEEDFORWARD_CORRECTION_BAND_PCT` | `20` | 前馈开启时 PI 修正量的对称限幅(±%) |
|
||||
| `GAIN_SCHEDULE_ENABLED` | `False` | 是否启用按阀前压力缩放 Kp/Ki |
|
||||
| `GAIN_SCHEDULE_REF_ABS_KPA` | `501.325` | 满压调好基准增益对应的绝对压力(400 + 101.325) |
|
||||
| `GAIN_SCHEDULE_FLOOR_ABS_KPA` | `60` | 绝对压力下限,防止 P1 很低时增益爆炸 |
|
||||
| `GAIN_SCHEDULE_SCALE_CHANGE_THRESHOLD` | `0.05` | scale 相对变化超过此值才重算增益 |
|
||||
| `FLOW_VALID_MIN_SLM` / `FLOW_VALID_MAX_SLM` | `0` / `300` | 流量安全范围 |
|
||||
| `MAX_PRESSURE_KPA` | `500` | 压力安全上限,须按实际管路额定压力确认 |
|
||||
| `MAX_CONSECUTIVE_FLOW_FAILURES` / `MAX_CONSECUTIVE_PRESSURE_FAILURES` | `3` / `3` | 闭环连续读取失败阈值 |
|
||||
@@ -294,13 +377,16 @@ python test_valve.py
|
||||
| 文件 | 职责 |
|
||||
| --- | --- |
|
||||
| [main.py](main.py) | 闭环入口:参数解析、日志、控制循环、记录器、性能报告与收尾 |
|
||||
| [flow_control.py](flow_control.py) | 闭环控制层、传感器读取、开度/行程映射和故障处理 |
|
||||
| [flow_control.py](flow_control.py) | 闭环控制层、传感器读取、开度/行程映射、前馈与增益调度、故障处理 |
|
||||
| [controllers.py](controllers.py) | 通用增量式 PID,含输出限幅和输出变化率限幅 |
|
||||
| [config.py](config.py) | 闭环集中配置和启动前校验 |
|
||||
| [data_logger.py](data_logger.py) | 闭环逐周期 CSV 与三联曲线图 |
|
||||
| [data_logger.py](data_logger.py) | 闭环逐周期 CSV 与三联曲线图(含前馈/修正/增益调度列) |
|
||||
| [performance_reporter.py](performance_reporter.py) | 闭环滑窗判稳和一次性性能报告 |
|
||||
| [open_loop.py](open_loop.py) | 独立开环扫点、四传感器记录和压力比分析 |
|
||||
| [open_loop.py](open_loop.py) | 独立开环扫点、传感器记录和压力比分析 |
|
||||
| [test_valve.py](test_valve.py) | Windows 终端手动开度测试、每秒采样、CSV 与三联图 |
|
||||
| [valve_model.py](valve_model.py) | 静态阀特性模型 `Q_ss = A_eff(x)·P1_abs·F(r)` 与前馈反解(纯计算) |
|
||||
| [identify_valve.py](identify_valve.py) | 从开环扫点 CSV 拟合 `A_eff(x)` 表,输出 `valve_model.json` |
|
||||
| [test_valve_model.py](test_valve_model.py) | 阀特性模型与前馈反解的离线自测 |
|
||||
| [PcControl.py](PcControl.py) | Modbus 硬件客户端;本项目三个入口实际使用 `MT2AM8Client` |
|
||||
|
||||
## 项目结构
|
||||
@@ -315,10 +401,14 @@ flow_control/
|
||||
├── config.py
|
||||
├── data_logger.py
|
||||
├── performance_reporter.py
|
||||
├── valve_model.py # 静态阀特性模型与前馈反解
|
||||
├── identify_valve.py # 从开环 CSV 拟合阀特性表
|
||||
├── test_valve_model.py # 阀特性模型离线自测
|
||||
├── PcControl.py
|
||||
├── README.md
|
||||
├── data/ # 闭环 CSV / PNG;历史数据可能已人工分组
|
||||
├── open_loop_data/ # 开环 CSV / PNG(首次运行时创建)
|
||||
├── test_valve_data/ # 手动阀门测试 CSV / PNG
|
||||
├── valve_model.json # identify_valve.py 产出的阀特性表(供前馈使用)
|
||||
└── logs/ # flow_control.log / open_loop.log
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user