- 输入模式下控制循环照常运行、原目标继续生效,直到回车确认新值 - 输入期间终端输出整体静默(状态行/性能报告均不打印),文件日志与 CSV 照常写入 - 新增 ConsoleGate 过滤器挂到 console_handler,退出路径统一解除静默 - 新增 PerformanceReporter.reset(),切换目标后重新判稳并再次输出性能报告 - 新增 config.TARGET_SWITCH_KEY 配置项,README 同步说明
13 KiB
气体流量控制与阀门开环标定
本项目基于艾莫迅 MT2-AM8 模拟量采集/输出模块,提供两个可独立运行的入口:
- main.py:以 10 Hz 周期运行单回路气体流量增量式 PID 闭环控制;
- open_loop.py:随机扫描阀门开度,采集阀前/阀后的压力与流量,用于开环标定、动态特性观察和临界压力比分析。
两个入口都会逐周期保存 CSV,并在运行结束时为有效采样数据生成 PNG 曲线图。闭环程序还会持续进行滑动窗口稳态判定,并在首次达到稳态时输出一次控制性能报告。
重要安全说明
本项目会直接控制真实阀门。首次运行前必须核对 IP、站号、AI/AO 通道、传感器量程、阀门行程方向、压力上限和执行机构的断电/失驱位置,并准备独立的机械或电气急停手段。
闭环与开环程序当前采用不同的退出策略:
- 闭环
main.py:启动时不再预先下发关闭位置,PID 内部输出由INITIAL_OPENING_PCT=100%开始;故障或退出时停止控制并断开 MT2-AM8,不主动下发关阀命令。当前系统按“执行机构失驱后回到全开”设计,现场必须确认实际硬件确实如此。 - 开环
open_loop.py:连接成功后先主动设置0%开度,实验结束、异常或Ctrl+C时再次尝试设置0%开度,然后断开设备。
因此,README 中的“关闭”或“全开”均指当前代码定义的逻辑位置,不能代替现场对阀门真实动作方向的确认。
硬件与默认接线
- MT2-AM8:Modbus TCP,默认
192.168.1.12:502,站号1; - AI 输入寄存器:地址
0x00~0x03; - AO 保持寄存器:地址
0x00~0x03; - 模拟量原始范围:
0~4095,传感器物理量换算使用819~4095对应有效量程; - 默认流量量程:
300 SLM;默认压力量程:400 kPa; - 电机行程范围:
0~1000,且行程与阀门开度反向作用。
默认通道如下,通道编号均从 0 开始:
| 用途 | 通道 | 配置位置 |
|---|---|---|
| 闭环/阀后压力 | AI0 |
config.PRESSURE_INPUT_CHANNEL |
| 闭环/阀后流量 | AI1 |
config.FLOW_INPUT_CHANNEL |
| 开环阀前压力 | AI2 |
open_loop.PRESSURE_BEFORE_CHANNEL |
| 开环阀前流量 | AI3 |
open_loop.FLOW_BEFORE_CHANNEL |
| 电机位置指令 | AO1 |
config.MOTOR_OUTPUT_CHANNEL |
开度与行程的默认映射为:
opening = 0% -> motor_position = 1000(关闭)
opening = 100% -> motor_position = 0(全开)
所有闭环通道、量程和行程端值集中在 config.py;开环新增的阀前通道和实验参数位于 open_loop.py 顶部。
环境与依赖
项目使用 Python 3,直接依赖:
pymodbus:Modbus TCP/RTU 通讯;matplotlib:使用Agg后端生成 PNG,无显示器环境也可运行。
示例安装:
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install pymodbus matplotlib
仓库当前没有锁定依赖版本。若 PcControl.py 导入 pymodbus.payload 或调用 slave= 参数时报错,请使用与现有 PcControl.py API 兼容的 pymodbus 版本。
闭环控制
运行
先在 config.py 中完成现场参数核对,再执行:
python main.py --target 50
--target 的单位为 SLM,必须位于 TARGET_FLOW_MIN_SLM~TARGET_FLOW_MAX_SLM(当前为 0~300)范围内。按 Ctrl+C 停止;默认 AUTO_STOP_ON_STEADY=False,所以达到稳态后仍会继续控制。如需首次达到稳态后自动结束,将该配置改为 True。
运行中切换目标流量
闭环运行过程中无需重启即可切换目标流量:在终端按 S(TARGET_SWITCH_KEY)进入输入模式,屏幕会提示当前目标并等待输入,输入数字后按回车生效,按 Esc 取消。输入模式期间:
- 控制循环照常运行,原目标流量继续生效,直到回车确认新值;
- 终端输出整体静默(状态行、性能报告均不打印),避免与输入回显混在一起;
- 逐周期 CSV 与
logs/flow_control.log照常写入,不丢数据。
新目标生效后会重置稳态判定(PerformanceReporter.reset()),因此切换后的目标仍会重新判稳并输出一次性能报告。目标值需位于 TARGET_FLOW_MIN_SLM~TARGET_FLOW_MAX_SLM 范围内,非法或超范围输入会被拒绝并提示,不影响控制。
该热键仅在真实控制台(Windows 的
msvcrt)下可用;Ctrl+C无论是否处于输入模式都会停止控制。
启动流程为:
校验配置 -> 连接 MT2-AM8 -> 读取一次初始流量
-> PID 输出初始化为 INITIAL_OPENING_PCT
-> 进入周期控制(启动阶段不主动写入关闭位置)
单个控制周期为:
读取流量/压力
|
v
IncrementalPID.update()
error = target - measurement
|
v
开度百分比 0~100%(输出限幅 + 变化率限幅)
|
v
opening_to_motor_position()
|
v
反向行程 1000~0 -> MT2-AM8 AO1
增量 PID 的输出直接定义为阀门开度,因此控制器本身不包含电机行程或死区映射。目标流量不高于 ZERO_FLOW_THRESHOLD_SLM(当前 0.5 SLM)时,程序跳过常规 PID 更新并直接命令 0% 开度。
运行输出
每次闭环运行会产生:
- 终端与日志:约每秒输出一次状态;非
OK状态立即输出。日志保存到logs/flow_control.log。 - 逐周期 CSV:默认保存为
data/flow_run_YYYYMMDD_HHMMSS.csv,每行写入后立即刷新到磁盘。现有data/日期/实验说明/子目录是历史数据的人工归档方式,不是程序自动创建的层级。 - 三联曲线图:结束时保存同名 PNG,依次显示目标/实际流量、阀门开度和压力。
- 性能报告:首次达到稳态时写入终端和日志;若整个运行过程未达到稳态,只输出未达到稳态的提示。
闭环 CSV 字段:
| 字段 | 含义 |
|---|---|
time_s / timestamp |
相对运行时间 / Unix 时间戳 |
target_flow_slm / measured_flow_slm |
目标流量 / 实测流量 |
opening_pct / motor_position |
阀门开度 / 电机行程 |
pressure_kpa |
压力;未启用或读取失败时为空 |
error_slm |
目标流量 - 实测流量 |
actual_dt_s |
实际控制周期 |
status |
OK 或传感器读取重试状态 |
稳态判定与性能报告
判稳只使用状态为 OK 的有效流量样本。滑窗至少覆盖 STEADY_STATE_WINDOW_S - CONTROL_PERIOD_S,以容纳真实采样时间戳抖动,并要求下列条件同时成立:
|窗口均值 - 目标流量| <= STEADY_STATE_BAND_PCT / 100 * 目标流量
窗口总体标准差 <= STEADY_STATE_STD_PCT / 100 * 目标流量
当前默认使用 10 秒窗口、±1% 均值误差带和 1% 标准差阈值。报告内容包括 PID 参数、目标与控制范围、调节时间、窗口均值、窗口标准差、稳态误差(目标减窗口均值)、初始流量,以及按初始变化方向计算的峰值/谷值超调量。
开环扫点实验
open_loop.py 不参与闭环反馈,也不会被 main.py 导入。默认将 0%~100%、间隔 10% 的 11 个开度按固定随机种子 42 打乱,然后逐点执行:
写入开度 -> 每 0.1 s 采集阀前/阀后压力与流量
-> 等待阀后流量稳定,或等待满 60 s
-> 切换到下一个开度
运行默认实验或自定义扫描范围:
python open_loop.py
python open_loop.py --seed 7
python open_loop.py --min 0 --max 100 --step 5
--min、--max:扫描开度上下限,必须满足0 <= min < max <= 100;--step:开度间隔,必须大于0;不能整除区间时会额外包含max端点;--seed:打乱顺序的随机种子;相同参数和种子会得到相同顺序。
当前
open_loop.py --help的帮助文本存在%格式化问题,会触发ValueError;上面的正常运行命令及参数解析不受影响。
开环没有目标值,其稳态条件仅依据阀后流量的滑窗总体标准差:
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 包含三张子图:阀前/阀后压力、阀前/阀后流量、阀后绝对压力与阀前绝对压力之比。
压力比按下式计算:
P_abs_ratio = (阀后表压 + 101.325 kPa) / (阀前表压 + 101.325 kPa)
CSV 同时记录 is_ratio_smaller_than_0.528:压力比小于临界值 0.528 时为 Y,否则为 N;任一压力缺失或分母非法时两个压力比字段留空。图中会绘制 0.528 参考线,并标出各开度切换时刻。
安全与故障处理
闭环
- 配置在连接硬件前由
validate_config()校验; - 流量超出
FLOW_VALID_MIN_SLM~FLOW_VALID_MAX_SLM或压力高于MAX_PRESSURE_KPA时停止控制并报故障; - 短暂的流量/压力读取失败保持上一输出,不下发新位置;连续达到各自阈值后停止控制;
- 实际控制周期超过
MAX_CONTROL_DT_S时停止控制; - PID 输出限制在
0~100%,MAX_OPENING_RATE_PCT_S限制每秒最大开度变化; - 电机命令写入异常或返回失败时停止控制;
- 所有退出路径都会尝试断开设备,但当前闭环代码不会主动下发关阀命令。
开环
- 启动和收尾均主动下发
0%开度; - 任一有效流量读数越界、任一有效压力读数超过上限时中止;
- 阀后流量连续读取失败达到阈值时中止;
- 写入开度失败时中止;
- 中止后仍会尽力关阀、断开连接并保留已经写入的 CSV。
关键配置默认值
| 配置 | 当前默认值 | 说明 |
|---|---|---|
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 |
传感器量程 |
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 |
目标周期 / 超时阈值 |
PID_KP / PID_KI / PID_KD |
0.5 / 0.5 / 0.0 |
当前 PI 参数,需按现场继续整定 |
OPENING_MIN_PCT / OPENING_MAX_PCT |
0 / 100 |
PID 输出开度范围 |
MAX_OPENING_RATE_PCT_S |
20 |
每秒最大开度变化百分比 |
MOTOR_CLOSED_POSITION / MOTOR_OPEN_POSITION |
1000 / 0 |
反向行程端值 |
INITIAL_OPENING_PCT |
100 |
闭环 PID 内部初始输出 |
FLOW_VALID_MIN_SLM / FLOW_VALID_MAX_SLM |
0 / 300 |
流量安全范围 |
MAX_PRESSURE_KPA |
400 |
压力上限,须按实际管路额定压力确认 |
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 |
达到稳态后是否自动结束闭环 |
模块职责
| 文件 | 职责 |
|---|---|
| main.py | 闭环入口:参数解析、日志、控制循环、记录器、性能报告与收尾 |
| flow_control.py | 闭环控制层、传感器读取、开度/行程映射和故障处理 |
| controllers.py | 通用增量式 PID,含输出限幅和输出变化率限幅 |
| config.py | 闭环集中配置和启动前校验 |
| data_logger.py | 闭环逐周期 CSV 与三联曲线图 |
| performance_reporter.py | 闭环滑窗判稳和一次性性能报告 |
| open_loop.py | 独立开环扫点、四传感器记录和压力比分析 |
| PcControl.py | Modbus 硬件客户端;本项目两个入口实际使用 MT2AM8Client |
项目结构
flow_control/
├── main.py
├── open_loop.py
├── flow_control.py
├── controllers.py
├── config.py
├── data_logger.py
├── performance_reporter.py
├── PcControl.py
├── README.md
├── data/ # 闭环 CSV / PNG;历史数据可能已人工分组
├── open_loop_data/ # 开环 CSV / PNG(首次运行时创建)
└── logs/ # flow_control.log / open_loop.log