- 前馈冻结改用可配置的 3 秒流量绝对误差滑窗,修复采样抖动造成的重复解冻,并保留下游扰动后的自动更新 - 支持非单调阀特性反解、最小可测面积以下直接全关,以及闭阀端精细扫点与辨识开关 - 调整双压力判稳、最长等待时间、在线入口全开收尾和闭环四联图 - 更新配置、README、阀模型及离线测试,归档本轮实验数据与诊断产物
28 KiB
气体流量控制与阀门开环标定
本项目基于信捷 Easy521 PLC(Modbus TCP)提供三个可独立运行的在线入口和两个离线工具:
- main.py:以 10 Hz 周期运行单回路气体流量闭环控制,支持增量式 PID,并可选“前馈反解打底 + PI 修残差”与按阀前压力缩放增益的增益调度;
- open_loop.py:随机扫描阀门开度,并在末尾追加闭阀端精细行程扫描;采集阀前/阀后的压力与阀后流量,用于开环标定、动态特性观察和临界压力比分析。
- test_valve.py:在 Windows 终端中手动切换阀门开度,同时观察并记录阀后流量、阀前/阀后压力和电机行程。
- identify_valve.py:离线从开环扫点 CSV 拟合阀特性表,产出供前馈使用的
valve_model.json。 - test_valve_model.py:阀特性模型与前馈反解的离线自测,不接触硬件。
三个在线入口都会持续保存 CSV,并在运行结束时为有效采样数据生成 PNG 曲线图。闭环程序还会持续进行滑动窗口稳态判定,并在首次达到稳态时输出一次控制性能报告。
重要安全说明
本项目会直接控制真实阀门。首次运行前必须核对 IP、站号、寄存器地址、传感器量程、阀门行程方向、压力上限和执行机构的断电/失驱位置,并准备独立的机械或电气急停手段。
三个入口当前的阀门初始化与退出策略如下:
- 闭环
main.py:连接成功后先主动设置100%开度,再开始初始采样、性能报告和控制计时;故障、正常退出或Ctrl+C时再次尝试设置100%开度,然后断开 PLC。 - 开环
open_loop.py:连接成功后先主动设置100%开度,再创建记录器并开始实验计时;实验结束、异常或Ctrl+C时再次尝试设置100%开度,然后断开设备。 - 手动测试
test_valve.py:连接成功后先主动设置100%开度,再创建记录器并开始采样;退出时再次尝试设置100%开度,然后断开设备。该脚本不执行流量/压力越限和连续读取失败保护,只适合在具备独立安全措施的受控测试中使用。
因此,README 中的“关闭”或“全开”均指当前代码定义的逻辑位置,不能代替现场对阀门真实动作方向的确认。
硬件与默认接线
- PLC(Easy521):Modbus TCP,默认
192.168.1.88:502,站号1; - D 寄存器为直接 Modbus 地址:读用功能码
03(保持寄存器),写用功能码06; - 模拟量标称原始范围:
0~32000,线性对应各量程满量程;读取时先把 Modbus 的0~65535解码为 16 位有符号值,因此传感器负偏差会换算为负物理量,并由上层有效范围检查处理; - 默认流量量程:
300 SLM;阀后压力量程:400 kPa;阀前压力量程:300 kPa; - 电机行程范围:
0~1000,且行程与阀门开度反向作用。
默认寄存器地址与量程如下:
| 用途 | 地址 | 量程 | 配置位置 |
|---|---|---|---|
| 阀后流量 | D700 |
300 SLM |
config.FLOW_AFTER_ADDR |
| 阀后压力 | D710 |
400 kPa |
config.PRESSURE_AFTER_ADDR |
| 阀前压力(前馈/增益调度/开环共用) | D720 |
300 kPa |
config.PRESSURE_BEFORE_ADDR / open_loop.PRESSURE_BEFORE_CHANNEL |
| 电机位置指令(0~10V) | D730 |
行程 0~1000 |
config.MOTOR_OUTPUT_ADDR |
控流阀前的流量传感器已删除,
open_loop.FLOW_BEFORE_CHANNEL现为None:开环 CSV 的flow_before_slm列与 PNG 中的 “Flow before valve” 曲线将保持为空。
开度与行程的默认映射为:
opening = 0% -> motor_position = 1000(关闭)
opening = 100% -> motor_position = 800(当前打开端/机械死区边界)
虽然硬件层行程坐标仍为 0~1000,当前控制映射只使用 800~1000。这是近期根据阀门有效调节区间设置的打开端边界;逻辑 100% 不再对应物理行程 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无论是否处于输入模式都会停止控制。
启动流程为:
校验配置 -> 连接 PLC -> 主动设置 100% 开度(不计时)-> 读取一次初始流量
-> PID 输出初始化为 INITIAL_OPENING_PCT
-> 进入周期控制
单个控制周期为:
读取流量/压力
|
v
IncrementalPID.update()
error = target - measurement
|
v
开度百分比 0~100%(输出限幅 + 变化率限幅)
|
v
opening_to_motor_position()
|
v
反向行程 1000~800 -> PLC D730
增量 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 |
200%/s |
NEAR |
小误差时抑制振荡和稳态误差 | 0.05 / 0.01 / 0.0 |
2%/s |
切换阈值同时考虑绝对误差下限和目标流量比例:
near_threshold = min(3 SLM, max(1 SLM, 5% * target))
far_threshold = min(12 SLM, max(4 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 的累计输出和误差历史不会因修改目标而整体重置,性能报告器则会重置并从新目标重新计时、判稳和统计超调。
前馈 + 增益调度(MFC 结构)
闭环当前默认启用“前馈反解打底 + PI 修残差”的 MFC 结构,并加载仓库根目录的 valve_model.json;按阀前压力缩放 Kp/Ki 的增益调度仍默认关闭。投用前必须确认阀前/阀后压力接线和阀特性表与当前硬件一致;不满足时应关闭前馈或重新辨识。
静态阀特性建模为:
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。
开启前馈后,控制周期内的输出计算变为:
前馈开度 opening_ff = 反解(目标流量, 阀前压 P1, 阀后压 P2)
PI 修正量 correction = PI(目标流量 - 实测流量) # 输出限幅改为对称 ±带
开度 = clamp(opening_ff + correction, 0, 100)
即前馈把开度送到稳态工作点附近,PI 只负责修正模型残差和动态偏差;PI 输出不再是 0~100% 的全行程,而是围绕前馈的修正量(限幅由 FEEDFORWARD_CORRECTION_BAND_PCT 控制,当前默认 ±50%)。
为避免接近目标后压力噪声持续改写前馈,同时又能响应下游负载变化,控制器维护一个 FEEDFORWARD_UPDATE_WINDOW_S=3 s 的流量绝对误差滑动窗口。窗口首次积满后,程序在每个控制周期都重新计算最近 3 秒的平均绝对误差,并与 FEEDFORWARD_UPDATE_ERROR_THRESHOLD_SLM=5 SLM 比较:均值不大于阈值时冻结上一次前馈开度,只让 PI correction 逐周期更新;均值超过阈值时重新根据当前目标流量和阀前/阀后压力反解前馈。因此,下游扰动持续影响流量并使 3 秒误差均值越过阈值后,前馈会自动解除冻结。
窗口未首次积满或尚无缓存前馈时,每个周期都尝试反解前馈。窗口一旦积满,其“已就绪”状态不会因采样抖动和旧样本淘汰而反复失效;但滑动均值仍会持续更新,冻结状态并不会锁死。目标改变、控制器重启或进入零流量分支会清空窗口并重新累计 3 秒。当前周期反解失败时继续复用上次有效前馈;如果从未得到有效前馈,则以 0% 为基值并由 correction 调整。
增益调度把 FAR/NEAR 的 Kp、Ki 按阀前绝对压力缩放,摊平 K_x ∝ P1 的非线性:
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,避免每个周期都更新增益。
相关配置的当前默认值为:
| 开关 | 默认 | 说明 |
|---|---|---|
FEEDFORWARD_ENABLED |
True |
启用前馈反解打底 + PI 修残差 |
GAIN_SCHEDULE_ENABLED |
False |
启用按阀前压力缩放 Kp/Ki |
VALVE_MODEL_PATH |
"valve_model.json" |
阀特性表 JSON 路径(空串 = 关闭前馈) |
PRESSURE_BEFORE_ADDR |
720 |
阀前压力 P1 的寄存器地址(D720) |
前馈生效需同时满足:FEEDFORWARD_ENABLED=True、VALVE_MODEL_PATH 指向有效 JSON、PRESSURE_BEFORE_ADDR 与 PRESSURE_AFTER_ADDR 均已配置。任一条件缺失时自动退化为纯 PID,并在启动日志中提示。
运行输出
每次闭环运行会产生:
- 终端与日志:约每秒输出一次状态;非
OK状态立即输出。日志保存到logs/flow_control.log。 - 逐周期 CSV:默认保存为
data/flow_run_YYYYMMDD_HHMMSS.csv,每行写入后立即刷新到磁盘。现有data/日期/实验说明/子目录是历史数据的人工归档方式,不是程序自动创建的层级。 - 四联曲线图:结束时保存同名 PNG,依次显示目标/实际流量、阀门开度、阀前/阀后压力和绝对压力比;启用前馈时,开度子图会叠加虚线显示前馈开度,压力比子图绘制
0.528临界参考线。 - 性能报告:首次达到稳态时写入终端和日志;若整个运行过程未达到稳态,只输出未达到稳态的提示。
闭环 CSV 字段:
| 字段 | 含义 |
|---|---|
time_s / timestamp |
相对运行时间 / Unix 时间戳 |
target_flow_slm / measured_flow_slm |
目标流量 / 实测流量 |
opening_pct / motor_position |
阀门开度 / 电机行程 |
pressure_kpa |
阀后压力;未启用或读取失败时为空 |
pressure_before_kpa |
阀前压力 P1;未启用或读取失败时为空 |
P_abs_ratio |
(阀后表压 + 101.325) / (阀前表压 + 101.325);压力缺失或分母非法时为空 |
feedforward_pct |
前馈开度;未启用前馈时为空 |
correction_pct |
PI 修正量(±带内);未启用前馈时为空 |
gain_scale |
增益调度缩放系数;未启用调度时为 1.0 |
error_slm |
目标流量 - 实测流量 |
actual_dt_s |
实际控制周期 |
status |
OK 或传感器读取重试状态 |
稳态判定与性能报告
判稳只使用状态为 OK 且流量、阀前压力、阀后压力均有效的样本。滑窗至少覆盖 STEADY_STATE_WINDOW_S - CONTROL_PERIOD_S,以容纳真实采样时间戳抖动,并要求下列条件同时成立:
|窗口均值 - 目标流量| <= STEADY_STATE_BAND_PCT / 100 * 目标流量
阀前压力每个样本均位于阀前压力窗口均值 ± STEADY_STATE_PRESSURE_BAND_KPA
阀后压力每个样本均位于阀后压力窗口均值 ± STEADY_STATE_PRESSURE_BAND_KPA
当前默认使用 5 秒窗口、±1% 流量均值误差带和阀前/阀后各 ±1 kPa 压力带。流量标准差仍会计算并写入报告,但不再作为闭环判稳条件。报告内容还包括两侧压力的窗口均值/最大偏差、判稳时当前模式的 PID 参数、目标与控制范围、调节时间、稳态误差(目标减窗口均值)、初始流量,以及按初始变化方向计算的峰值/谷值超调量。
开环扫点实验
open_loop.py 不参与闭环反馈,也不会被 main.py 导入。默认先将 0%~100%、间隔 5% 的 21 个开度按固定随机种子 42 打乱并换算为行程,再在序列末尾追加 970~1000、间隔 3 的闭阀端精细行程点(末端不足一个步长时仍包含 1000)。精细段直接按行程下发,并反算逻辑开度用于记录。
写入随机开度/精细行程 -> 每 0.1 s 采集阀前/阀后压力与阀后流量
-> 等待阀后流量稳定,或等待满 30 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:打乱顺序的随机种子;相同参数和种子会得到相同顺序。
可通过 python open_loop.py --help 查看完整参数帮助。
开环没有目标值,其稳态条件仅依据阀后流量的滑窗总体标准差:
std <= max(STEADY_STATE_STD_PCT / 100 * |窗口均值|, MIN_ABS_STD_SLM)
默认窗口为 5 秒,绝对标准差下限为 0.05 SLM,单点最长等待时间为 30 秒。阀后流量连续 5 次读取失败会中止实验;其他通道读取失败会在对应 CSV 字段中留空。
输出保存到 open_loop_data/open_loop_YYYYMMDD_HHMMSS.csv/.png,日志保存到 logs/open_loop.log。PNG 包含三张子图:阀前/阀后压力、阀前/阀后流量、阀后绝对压力与阀前绝对压力之比。由于阀前流量传感器已删除,“阀前流量”曲线与 flow_before_slm 列保持为空。
压力比按下式计算:
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 用于绕过 PID,人工设置单个阀门开度并观察传感器响应。该交互依赖 Windows 的 msvcrt,请在真实 Windows 终端中运行:
python test_valve.py
连接成功后,脚本主动写入 100% 开度、行程 800,完成后才创建记录器并开始采样。运行期间:
- 每秒读取并显示一次阀后流量、阀前/阀后压力、各传感器反算模拟量原始值、逻辑开度和映射后的电机行程;
- 按
S进入输入模式,输入0~100的新开度后按回车下发,按Esc取消; - 输入期间暂停终端状态显示,但传感器采样和 CSV 写入继续;
- 按
Ctrl+C保存数据并退出;断开前会再次尝试下发100%开度。
数据保存为 test_valve_data/test_valve_YYYYMMDD_HHMMSS.csv,字段包含相对时间、ISO 时间戳、flow_after_slm、开度、pressure_before_kpa、pressure_after_kpa 和电机行程;结束时生成同名三联图,依次显示阀后流量、开度以及叠加的阀前/阀后压力。
此脚本不会调用
config.validate_config(),也没有闭环/开环程序中的流量越限、压力越限或连续读取失败保护。运行前应人工完成配置核对,并确保测试人员能够立即切断气源或执行急停。
阀特性辨识与离线自测
前馈需要一张 A_eff(x) 阀特性表。先用 open_loop.py 扫点得到开环 CSV(时间戳命名、从不覆盖),再用 identify_valve.py 离线拟合。--csv 支持多个路径与 glob 模式,可把多次实验合并重拟合,数据越多表越稳:
python identify_valve.py --csv open_loop_data/open_loop_YYYYMMDD_HHMMSS.csv --out valve_model.json
python identify_valve.py --csv "open_loop_data/*.csv" --out valve_model.json --plot
python identify_valve.py --plot # 省略 --csv 时默认合并 open_loop_data/ 下全部 CSV
- 每个 CSV 按
step_index分组,每组取末尾--tail个采样点平均,得到稳态(行程 x, 流量 Q, 阀前压 P1, 阀后压 P2),并按开度访问顺序标记逼近方向(上升 / 下降 / 该文件起始步); - 对每个稳态点反解
A_eff = Q / (P1_abs · F(r));同一行程 x 的多个点(来自不同次实验)先取平均再构表; - 按行程升序构表。
IDENTIFY_VALVE_MONOTONIC_CHECK_ENABLED=False(当前默认)时保留所有按行程平均后的点,并在 JSON 记录"enforce_monotonic": false;设为True时检查单调性,整体非单调则只保留最长单调连续段并警告其余点被丢弃; - 用 valve_model.py 存成 JSON,并打印合并文件数、稳态点数与阻塞/亚声速点统计等摘要;加
--plot额外生成诊断图,实测点按逼近方向着色:同一行程下上升/下降两团点明显分离说明阀门迟滞显著,前馈表应考虑分方向处理;完全重叠则迟滞可忽略。
非单调表可能让同一个有效面积对应多个行程,反解时选择数值更大的行程,即更靠近关闭端的交点。目标有效面积小于表中最小实测值时直接返回机械全关行程 MOTOR_CLOSED_POSITION;恰好等于最小值时仍返回对应实测行程。
将 config.VALVE_MODEL_PATH 指到该 JSON、确认 PRESSURE_BEFORE_ADDR 接线无误、并把 FEEDFORWARD_ENABLED 设为 True 后,闭环即可启用前馈。当前配置已指向 valve_model.json 并默认启用,重新标定后应覆盖该文件或同步修改配置路径。
test_valve_model.py 是纯计算离线自测,不接触硬件,可在任意环境运行:
python test_valve_model.py
它校验压比函数 F(r)、绝对压力换算、A_eff 插值与前馈反解互逆、单调/非单调表反解、闭阀端精细扫描点生成,以及 identify_valve 端到端辨识。test_flow_control.py 校验前馈误差滑窗在采样抖动下保持就绪、同时持续响应新误差;test_performance_reporter.py 另行校验闭环的流量均值与压力带判稳逻辑。可一次运行全部离线测试:
python -m pytest -q
安全与故障处理
闭环
- 配置在连接硬件前由
validate_config()校验; - 流量超出
FLOW_VALID_MIN_SLM~FLOW_VALID_MAX_SLM或压力高于MAX_PRESSURE_KPA时停止控制并报故障; - 短暂的流量/压力读取失败保持上一输出,不下发新位置;连续达到各自阈值后停止控制;
- 实际控制周期超过
MAX_CONTROL_DT_S时停止控制; - PID 输出限制在
0~100%;FAR/NEAR 两档分别限制每秒最大开度变化; - 电机命令写入异常或返回失败时停止控制;
- 所有退出路径都会在断开设备前尝试下发
100%开度;下发失败会记录严重错误并返回非零退出码。
开环
- 启动和收尾均主动下发
100%开度; - 任一有效流量读数越界、任一有效压力读数超过上限时中止;
- 阀后流量连续读取失败达到阈值时中止;
- 写入开度失败时中止;
- 中止后仍会尽力恢复
100%开度、断开连接并保留已经写入的 CSV。
手动测试
- 只校验输入开度是否为
0~100的有限数值以及电机写入是否成功; - 传感器读取失败时 CSV 对应字段留空,终端显示
--,不会自动中止; - 不检查流量和压力安全阈值;
Ctrl+C、异常和正常收尾都会在保存已有数据、断开连接前尝试恢复100%开度。
关键配置默认值
| 配置 | 当前默认值 | 说明 |
|---|---|---|
PLC_HOST / PLC_PORT / PLC_SLAVE_ID |
192.168.1.88 / 502 / 1 |
PLC 通讯参数 |
FLOW_AFTER_ADDR / FLOW_AFTER_RANGE_SLM |
700 / 300 |
阀后流量 D700 与量程 |
PRESSURE_AFTER_ADDR / PRESSURE_AFTER_RANGE_KPA |
710 / 400 |
阀后压力 D710 与量程 |
PRESSURE_BEFORE_ADDR / PRESSURE_BEFORE_RANGE_KPA |
720 / 300 |
阀前压力 D720 与量程 |
MOTOR_OUTPUT_ADDR |
730 |
电机输出 D730(0 |
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_FAR_KP / PID_FAR_KI / PID_FAR_KD |
0.5 / 0.5 / 0.0 |
大误差快速模式 PID 参数 |
PID_NEAR_KP / PID_NEAR_KI / PID_NEAR_KD |
0.05 / 0.01 / 0.0 |
小误差稳定模式 PID 参数 |
OPENING_MIN_PCT / OPENING_MAX_PCT |
0 / 100 |
PID 输出开度范围 |
MAX_OPENING_RATE_FAR_PCT_S / MAX_OPENING_RATE_NEAR_PCT_S |
200 / 2 |
FAR/NEAR 每秒最大开度变化百分比 |
PID_NEAR_ERROR_MIN_SLM / PID_NEAR_ERROR_MAX_SLM / PID_NEAR_ERROR_TARGET_RATIO |
1 / 3 / 0.05 |
FAR 进入 NEAR 的误差阈值下限、上限和目标比例 |
PID_FAR_ERROR_MIN_SLM / PID_FAR_ERROR_MAX_SLM / PID_FAR_ERROR_TARGET_RATIO |
4 / 12 / 0.20 |
NEAR 返回 FAR 的误差阈值下限、上限和目标比例 |
PID_MODE_SWITCH_CONFIRM_CYCLES |
10 |
模式切换条件需连续满足的采样周期数(当前约 1 秒) |
MOTOR_CLOSED_POSITION / MOTOR_OPEN_POSITION |
1000 / 800 |
当前反向控制区间;打开端为机械死区边界 |
INITIAL_OPENING_PCT |
100 |
闭环 PID 内部初始输出 |
PRESSURE_BEFORE_ADDR |
720 |
阀前压力 P1 的寄存器地址(前馈/增益调度/开环共用) |
VALVE_MODEL_PATH |
"valve_model.json" |
阀特性表 JSON 路径;空串关闭前馈 |
FEEDFORWARD_ENABLED |
True |
是否启用前馈反解打底 + PI 修残差 |
FEEDFORWARD_CORRECTION_BAND_PCT |
50 |
前馈开启时 PI 修正量的对称限幅(±%) |
FEEDFORWARD_UPDATE_ERROR_THRESHOLD_SLM / FEEDFORWARD_UPDATE_WINDOW_S |
5 / 3 |
前馈冻结/更新的流量绝对误差均值阈值与窗口长度 |
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 |
闭环连续读取失败阈值 |
STEADY_STATE_WINDOW_S / STEADY_STATE_BAND_PCT / STEADY_STATE_PRESSURE_BAND_KPA |
5 / 1 / 1 |
闭环窗口、流量均值误差带和压力稳定带 |
STEADY_STATE_MAX_WAIT_S / STEADY_STATE_STD_PCT |
30 / 1 |
开环单点最长等待时间 / 流量稳定标准差比例 |
OPEN_LOOP_FINE_STROKE_START / OPEN_LOOP_FINE_STROKE_STEP |
970 / 3 |
开环闭阀端精细行程扫描起点 / 步长 |
IDENTIFY_VALVE_MONOTONIC_CHECK_ENABLED |
False |
辨识时是否只保留最长单调连续段 |
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 | 独立开环扫点、传感器记录和压力比分析 |
| test_valve.py | Windows 终端手动开度测试、每秒采样、CSV 与三联图 |
| valve_model.py | 静态阀特性模型 Q_ss = A_eff(x)·P1_abs·F(r) 与前馈反解(纯计算) |
| identify_valve.py | 从一份或多份开环扫点 CSV(支持 glob 合并)拟合 A_eff(x) 表,输出 valve_model.json |
| test_valve_model.py | 阀特性模型与前馈反解的离线自测 |
| test_flow_control.py | 前馈误差滑窗、采样抖动与复位逻辑的离线测试 |
| test_performance_reporter.py | 闭环性能报告器与压力带判稳的离线测试 |
| PcControl.py | Modbus 硬件客户端;本项目三个入口实际使用 Easy521ModbusClient |
项目结构
flow_control/
├── main.py
├── open_loop.py
├── test_valve.py
├── flow_control.py
├── controllers.py
├── config.py
├── data_logger.py
├── performance_reporter.py
├── valve_model.py # 静态阀特性模型与前馈反解
├── identify_valve.py # 从开环 CSV 拟合阀特性表
├── test_valve_model.py # 阀特性模型离线自测
├── test_flow_control.py # 前馈误差滑窗离线测试
├── test_performance_reporter.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