修改控流阀死区为800,优化切换目标流量时PID模式切换逻辑,优化open_loop.py的--help显示,修改模式切换观察周期为10,更新了README.md

This commit is contained in:
2026-08-25 14:42:07 +08:00
parent 5476dbf9cd
commit bec4c0ead1
22 changed files with 11960 additions and 27 deletions
+69 -13
View File
@@ -1,20 +1,22 @@
# 气体流量控制与阀门开环标定
本项目基于艾莫迅 **MT2-AM8 模拟量采集/输出模块**,提供个可独立运行的入口:
本项目基于艾莫迅 **MT2-AM8 模拟量采集/输出模块**,提供个可独立运行的入口:
- [main.py](main.py):以 10 Hz 周期运行单回路气体流量增量式 PID 闭环控制;
- [open_loop.py](open_loop.py):随机扫描阀门开度,采集阀前/阀后的压力与流量,用于开环标定、动态特性观察和临界压力比分析。
- [test_valve.py](test_valve.py):在 Windows 终端中手动切换阀门开度,同时观察并记录流量、压力和电机行程。
个入口都会逐周期保存 CSV,并在运行结束时为有效采样数据生成 PNG 曲线图。闭环程序还会持续进行滑动窗口稳态判定,并在首次达到稳态时输出一次控制性能报告。
个入口都会持续保存 CSV,并在运行结束时为有效采样数据生成 PNG 曲线图。闭环程序还会持续进行滑动窗口稳态判定,并在首次达到稳态时输出一次控制性能报告。
## 重要安全说明
> 本项目会直接控制真实阀门。首次运行前必须核对 IP、站号、AI/AO 通道、传感器量程、阀门行程方向、压力上限和执行机构的断电/失驱位置,并准备独立的机械或电气急停手段。
闭环与开环程序当前采用不同的退出策略:
三个入口当前采用不同的阀门初始化与退出策略:
- **闭环 `main.py`**:启动时不再预先下发关闭位置,PID 内部输出由 `INITIAL_OPENING_PCT=100%` 开始;故障或退出时停止控制并断开 MT2-AM8,不主动下发关阀命令。当前系统按“执行机构失驱后回到全开”设计,现场必须确认实际硬件确实如此。
- **开环 `open_loop.py`**:连接成功后先主动设置 `0%` 开度,实验结束、异常或 `Ctrl+C` 时再次尝试设置 `0%` 开度,然后断开设备。
- **手动测试 `test_valve.py`**:连接时仅按已知状态记录 `100%` 开度,不向电机写入初始位置;退出时不主动下发新开度,仅断开设备。该脚本不执行流量/压力越限和连续读取失败保护,只适合在具备独立安全措施的受控测试中使用。
因此,README 中的“关闭”或“全开”均指当前代码定义的逻辑位置,不能代替现场对阀门真实动作方向的确认。
@@ -24,7 +26,7 @@
- AI 输入寄存器:地址 `0x00~0x03`
- AO 保持寄存器:地址 `0x00~0x03`
- 模拟量原始范围:`0~4095`,传感器物理量换算使用 `819~4095` 对应有效量程;
- 默认流量量程:`300 SLM`;默认压力量程:`400 kPa`
- 默认流量量程:`300 SLM`;默认压力量程:`1600 kPa`
- 电机行程范围:`0~1000`,且行程与阀门开度反向作用。
默认通道如下,通道编号均从 `0` 开始:
@@ -41,9 +43,11 @@
```text
opening = 0% -> motor_position = 1000(关闭)
opening = 100% -> motor_position = 0(全开
opening = 100% -> motor_position = 800(当前打开端/机械死区边界
```
虽然 `MT2AM8Client` 接受的物理行程仍为 `0~1000`,当前控制映射只使用 `800~1000`。这是近期根据阀门有效调节区间设置的打开端边界;逻辑 `100%` 不再对应物理行程 `0`
所有闭环通道、量程和行程端值集中在 [config.py](config.py);开环新增的阀前通道和实验参数位于 [open_loop.py](open_loop.py) 顶部。
## 环境与依赖
@@ -111,11 +115,34 @@ error = target - measurement
opening_to_motor_position()
|
v
反向行程 1000~0 -> MT2-AM8 AO1
反向行程 1000~800 -> MT2-AM8 AO1
```
增量 PID 的输出直接定义为阀门开度,因此控制器本身不包含电机行程或死区映射。目标流量不高于 `ZERO_FLOW_THRESHOLD_SLM`(当前 `0.5 SLM`)时,程序跳过常规 PID 更新并直接命令 `0%` 开度。
### FAR/NEAR 两档 PID
闭环启动时进入 `FAR` 模式。两档模式分别使用不同的 PID 参数和开度变化速度:
| 模式 | 用途 | Kp / Ki / Kd | 最大开度速度 |
| --- | --- | --- | ---: |
| `FAR` | 大误差时快速接近目标 | `0.5 / 0.5 / 0.0` | `20%/s` |
| `NEAR` | 小误差时抑制振荡和稳态误差 | `0.05 / 0.01 / 0.0` | `2%/s` |
切换阈值同时考虑绝对误差下限和目标流量比例:
```text
near_threshold = max(3 SLM, 5% * target)
far_threshold = max(12 SLM, 20% * target)
FAR -> NEAR|error| <= near_threshold,连续满足 10 个采样周期
NEAR -> FAR |error| >= far_threshold,连续满足 10 个采样周期
```
两个阈值构成滞回区间,可避免误差位于边界附近时逐周期反复切换。按当前 `0.1 s` 控制周期,连续 10 个采样周期约为 1 秒;期间只要切换条件有一个周期不成立,确认计数便清零。只有模式真正改变时才更新 PID 参数和输出变化率,切换原因会写入日志。
运行中修改目标后,模式确认计数会清零。如果尚无有效流量,或新目标相对最后有效流量的误差大于 `near_threshold`,控制器立即回到 `FAR`;若误差仍处于 NEAR 阈值内,则保持当前模式。PID 的累计输出和误差历史不会因修改目标而整体重置,性能报告器则会重置并从新目标重新计时、判稳和统计超调。
### 运行输出
每次闭环运行会产生:
@@ -146,7 +173,7 @@ opening_to_motor_position()
窗口总体标准差 <= STEADY_STATE_STD_PCT / 100 * 目标流量
```
当前默认使用 10 秒窗口、±1% 均值误差带和 1% 标准差阈值。报告内容包括 PID 参数、目标与控制范围、调节时间、窗口均值、窗口标准差、稳态误差(目标减窗口均值)、初始流量,以及按初始变化方向计算的峰值/谷值超调量。
当前默认使用 10 秒窗口、±1% 均值误差带和 1% 标准差阈值。报告内容包括判稳时当前模式的 PID 参数、目标与控制范围、调节时间、窗口均值、窗口标准差、稳态误差(目标减窗口均值)、初始流量,以及按初始变化方向计算的峰值/谷值超调量。
## 开环扫点实验
@@ -170,7 +197,7 @@ python open_loop.py --min 0 --max 100 --step 5
- `--step`:开度间隔,必须大于 `0`;不能整除区间时会额外包含 `max` 端点;
- `--seed`:打乱顺序的随机种子;相同参数和种子会得到相同顺序。
> 当前 `open_loop.py --help` 的帮助文本存在 `%` 格式化问题,会触发 `ValueError`;上面的正常运行命令及参数解析不受影响
可通过 `python open_loop.py --help` 查看完整参数帮助
开环没有目标值,其稳态条件仅依据阀后流量的滑窗总体标准差:
@@ -190,6 +217,25 @@ P_abs_ratio = (阀后表压 + 101.325 kPa) / (阀前表压 + 101.325 kPa)
CSV 同时记录 `is_ratio_smaller_than_0.528`:压力比小于临界值 `0.528` 时为 `Y`,否则为 `N`;任一压力缺失或分母非法时两个压力比字段留空。图中会绘制 `0.528` 参考线,并标出各开度切换时刻。
## 手动阀门测试
[test_valve.py](test_valve.py) 用于绕过 PID,人工设置单个阀门开度并观察传感器响应。该交互依赖 Windows 的 `msvcrt`,请在真实 Windows 终端中运行:
```powershell
python test_valve.py
```
连接成功后,脚本把当前已知状态记为 `100%` 开度、行程 `800`,但不会立即向电机写入该位置。运行期间:
- 每秒读取并显示一次流量、压力、逻辑开度和映射后的电机行程;
-`S` 进入输入模式,输入 `0~100` 的新开度后按回车下发,按 `Esc` 取消;
- 输入期间暂停终端状态显示,但传感器采样和 CSV 写入继续;
-`Ctrl+C` 保存数据并退出,不主动下发新的阀门开度。
数据保存为 `test_valve_data/test_valve_YYYYMMDD_HHMMSS.csv`,字段包含相对时间、ISO 时间戳、流量、开度、压力和电机行程;结束时生成同名三联图,依次显示流量、开度和压力。
> 此脚本不会调用 `config.validate_config()`,也没有闭环/开环程序中的流量越限、压力越限或连续读取失败保护。运行前应人工完成配置核对,并确保测试人员能够立即切断气源或执行急停。
## 安全与故障处理
### 闭环
@@ -210,6 +256,13 @@ CSV 同时记录 `is_ratio_smaller_than_0.528`:压力比小于临界值 `0.528
- 写入开度失败时中止;
- 中止后仍会尽力关阀、断开连接并保留已经写入的 CSV。
### 手动测试
- 只校验输入开度是否为 `0~100` 的有限数值以及电机写入是否成功;
- 传感器读取失败时 CSV 对应字段留空,终端显示 `--`,不会自动中止;
- 不检查流量和压力安全阈值;
- `Ctrl+C`、异常和正常收尾均不会主动关阀,只会断开连接并保存已有数据。
## 关键配置默认值
| 配置 | 当前默认值 | 说明 |
@@ -217,7 +270,7 @@ CSV 同时记录 `is_ratio_smaller_than_0.528`:压力比小于临界值 `0.528
| `MT2AM8_HOST` / `MT2AM8_PORT` / `MT2AM8_SLAVE_ID` | `192.168.1.12` / `502` / `1` | 通讯参数 |
| `FLOW_INPUT_CHANNEL` / `PRESSURE_INPUT_CHANNEL` | `1` / `0` | 闭环 AI 通道;压力可设为 `None` |
| `MOTOR_OUTPUT_CHANNEL` | `1` | 电机 AO 通道 |
| `FLOW_METER_RANGE_SLM` / `PRESSURE_RANGE_KPA` | `300` / `400` | 传感器量程 |
| `FLOW_METER_RANGE_SLM` / `PRESSURE_RANGE_KPA` | `300` / `1600` | 传感器量程 |
| `TARGET_FLOW_MIN_SLM` / `TARGET_FLOW_MAX_SLM` | `0` / `300` | 允许的目标范围 |
| `TARGET_SWITCH_KEY` | `s` | 运行中按此键进入"输入新目标流量"模式 |
| `CONTROL_PERIOD_S` / `MAX_CONTROL_DT_S` | `0.1` / `0.3` | 目标周期 / 超时阈值 |
@@ -227,11 +280,11 @@ CSV 同时记录 `is_ratio_smaller_than_0.528`:压力比小于临界值 `0.528
| `MAX_OPENING_RATE_FAR_PCT_S` / `MAX_OPENING_RATE_NEAR_PCT_S` | `20` / `2` | FAR/NEAR 每秒最大开度变化百分比 |
| `PID_NEAR_ERROR_MIN_SLM` / `PID_NEAR_ERROR_TARGET_RATIO` | `3` / `0.05` | FAR 进入 NEAR 的绝对/相对误差阈值 |
| `PID_FAR_ERROR_MIN_SLM` / `PID_FAR_ERROR_TARGET_RATIO` | `12` / `0.20` | NEAR 返回 FAR 的绝对/相对误差阈值 |
| `PID_MODE_SWITCH_CONFIRM_CYCLES` | `3` | 模式切换条件需连续满足的周期数 |
| `MOTOR_CLOSED_POSITION` / `MOTOR_OPEN_POSITION` | `1000` / `0` | 反向行程端值 |
| `PID_MODE_SWITCH_CONFIRM_CYCLES` | `10` | 模式切换条件需连续满足的采样周期数(当前约 1 秒) |
| `MOTOR_CLOSED_POSITION` / `MOTOR_OPEN_POSITION` | `1000` / `800` | 当前反向控制区间;打开端为机械死区边界 |
| `INITIAL_OPENING_PCT` | `100` | 闭环 PID 内部初始输出 |
| `FLOW_VALID_MIN_SLM` / `FLOW_VALID_MAX_SLM` | `0` / `300` | 流量安全范围 |
| `MAX_PRESSURE_KPA` | `400` | 压力上限,须按实际管路额定压力确认 |
| `MAX_PRESSURE_KPA` | `500` | 压力安全上限,须按实际管路额定压力确认 |
| `MAX_CONSECUTIVE_FLOW_FAILURES` / `MAX_CONSECUTIVE_PRESSURE_FAILURES` | `3` / `3` | 闭环连续读取失败阈值 |
| `STEADY_STATE_WINDOW_S` / `STEADY_STATE_BAND_PCT` / `STEADY_STATE_STD_PCT` | `10` / `1` / `1` | 闭环稳态判定参数 |
| `AUTO_STOP_ON_STEADY` | `False` | 达到稳态后是否自动结束闭环 |
@@ -247,7 +300,8 @@ CSV 同时记录 `is_ratio_smaller_than_0.528`:压力比小于临界值 `0.528
| [data_logger.py](data_logger.py) | 闭环逐周期 CSV 与三联曲线图 |
| [performance_reporter.py](performance_reporter.py) | 闭环滑窗判稳和一次性性能报告 |
| [open_loop.py](open_loop.py) | 独立开环扫点、四传感器记录和压力比分析 |
| [PcControl.py](PcControl.py) | Modbus 硬件客户端;本项目两个入口实际使用 `MT2AM8Client` |
| [test_valve.py](test_valve.py) | Windows 终端手动开度测试、每秒采样、CSV 与三联图 |
| [PcControl.py](PcControl.py) | Modbus 硬件客户端;本项目三个入口实际使用 `MT2AM8Client` |
## 项目结构
@@ -255,6 +309,7 @@ CSV 同时记录 `is_ratio_smaller_than_0.528`:压力比小于临界值 `0.528
flow_control/
├── main.py
├── open_loop.py
├── test_valve.py
├── flow_control.py
├── controllers.py
├── config.py
@@ -264,5 +319,6 @@ flow_control/
├── README.md
├── data/ # 闭环 CSV / PNG;历史数据可能已人工分组
├── open_loop_data/ # 开环 CSV / PNG(首次运行时创建)
├── test_valve_data/ # 手动阀门测试 CSV / PNG
└── logs/ # flow_control.log / open_loop.log
```