完善流量控制前馈、稳态判定与阀门标定流程
- 前馈冻结改用可配置的 3 秒流量绝对误差滑窗,修复采样抖动造成的重复解冻,并保留下游扰动后的自动更新 - 支持非单调阀特性反解、最小可测面积以下直接全关,以及闭阀端精细扫点与辨识开关 - 调整双压力判稳、最长等待时间、在线入口全开收尾和闭环四联图 - 更新配置、README、阀模型及离线测试,归档本轮实验数据与诊断产物
This commit is contained in:
+99
-16
@@ -2,7 +2,8 @@
|
||||
|
||||
本模块可独立运行,用于阀门开度—流量特性的开环标定/扫点。程序会:
|
||||
|
||||
1. 生成 0%~100%(默认 5% 间隔)共 21 个开度值并随机打乱;
|
||||
1. 生成 0%~100%(默认 5% 间隔)的开度值并随机打乱、转换为行程,
|
||||
然后在序列末尾追加配置指定的闭阀端精细行程点;
|
||||
2. 逐个开度:写入电机行程 → 以固定周期采集控流阀前后 4 个传感器
|
||||
(前压力、前流量、后压力、后流量)→ 等待“控流阀后流量”进入稳态后
|
||||
切换到下一个开度;
|
||||
@@ -56,7 +57,7 @@ RANDOM_SEED = 42 # 设为整数可复现同一打乱顺序
|
||||
SAMPLE_PERIOD_S = 0.1 # 采样周期(秒)
|
||||
STEADY_STATE_WINDOW_S = config.STEADY_STATE_WINDOW_S # 滑窗长度,复用 config
|
||||
STEADY_STATE_STD_PCT = config.STEADY_STATE_STD_PCT # 相对标准差阈值(%)
|
||||
MAX_WAIT_S = 60.0 # 单个开度的最长等待时间
|
||||
MAX_WAIT_S = config.STEADY_STATE_MAX_WAIT_S # 单个扫点的最长等待时间
|
||||
MIN_ABS_STD_SLM = 0.05 # 近零流量时的绝对标准差下限
|
||||
MAX_CONSECUTIVE_READ_FAILURES = 5 # 后流量连续读取失败判定设备断开
|
||||
|
||||
@@ -453,6 +454,71 @@ def generate_openings(min_pct, max_pct, step_pct, seed):
|
||||
return openings
|
||||
|
||||
|
||||
def motor_position_to_opening(position, motor_open_position, motor_closed_position):
|
||||
"""把反向作用的电机行程换算为 0~100% 阀门开度。"""
|
||||
position = float(position)
|
||||
open_position = float(motor_open_position)
|
||||
closed_position = float(motor_closed_position)
|
||||
if open_position >= closed_position:
|
||||
raise ValueError("打开端行程必须小于关闭端行程")
|
||||
if not open_position <= position <= closed_position:
|
||||
raise ValueError("电机行程超出打开端/关闭端范围")
|
||||
return 100.0 * (closed_position - position) / (
|
||||
closed_position - open_position
|
||||
)
|
||||
|
||||
|
||||
def generate_fine_strokes(start, end, step):
|
||||
"""生成包含起点和终点的闭阀端精细行程序列。"""
|
||||
start = float(start)
|
||||
end = float(end)
|
||||
step = float(step)
|
||||
if step <= 0.0:
|
||||
raise ValueError("精细行程间隔必须大于 0")
|
||||
if start >= end:
|
||||
raise ValueError("精细行程起点必须小于终点")
|
||||
|
||||
count = int(math.floor((end - start) / step))
|
||||
strokes = [round(start + i * step, 6) for i in range(count + 1)]
|
||||
if not strokes or abs(strokes[-1] - end) > 1e-6:
|
||||
strokes.append(end)
|
||||
return strokes
|
||||
|
||||
|
||||
def generate_scan_points(min_pct, max_pct, step_pct, seed):
|
||||
"""先生成并打乱开度点、转换为行程,再追加闭阀端精细行程点。"""
|
||||
openings = generate_openings(min_pct, max_pct, step_pct, seed)
|
||||
points = [
|
||||
(
|
||||
opening,
|
||||
opening_to_motor_position(
|
||||
opening,
|
||||
config.MOTOR_OPEN_POSITION,
|
||||
config.MOTOR_CLOSED_POSITION,
|
||||
),
|
||||
)
|
||||
for opening in openings
|
||||
]
|
||||
|
||||
fine_strokes = generate_fine_strokes(
|
||||
config.OPEN_LOOP_FINE_STROKE_START,
|
||||
config.MOTOR_CLOSED_POSITION,
|
||||
config.OPEN_LOOP_FINE_STROKE_STEP,
|
||||
)
|
||||
points.extend(
|
||||
(
|
||||
motor_position_to_opening(
|
||||
stroke,
|
||||
config.MOTOR_OPEN_POSITION,
|
||||
config.MOTOR_CLOSED_POSITION,
|
||||
),
|
||||
stroke,
|
||||
)
|
||||
for stroke in fine_strokes
|
||||
)
|
||||
return points
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 日志
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -530,12 +596,15 @@ def run(args):
|
||||
motor_output_addr=config.MOTOR_OUTPUT_ADDR,
|
||||
)
|
||||
|
||||
openings = generate_openings(
|
||||
scan_points = generate_scan_points(
|
||||
args.min, args.max, args.step, args.seed
|
||||
)
|
||||
logger.info(
|
||||
"开度扫描顺序(已打乱): %s",
|
||||
", ".join(f"{o:.1f}%" for o in openings),
|
||||
"最终扫描顺序(随机开度转行程后追加精细行程): %s",
|
||||
", ".join(
|
||||
f"{opening:.2f}%/x={position:.1f}"
|
||||
for opening, position in scan_points
|
||||
),
|
||||
)
|
||||
|
||||
connected = False
|
||||
@@ -550,12 +619,16 @@ def run(args):
|
||||
exit_code = 2
|
||||
return exit_code
|
||||
|
||||
# 启动前先关阀。
|
||||
ok, _ = set_opening(hardware, 0.0)
|
||||
# 连接后的全开动作发生在记录器及实验计时开始之前。
|
||||
ok, position = set_opening(hardware, 100.0)
|
||||
if not ok:
|
||||
logger.critical("启动前关阀失败,实验中止")
|
||||
logger.critical("连接后设置阀门 100%% 开度失败,实验中止")
|
||||
exit_code = 2
|
||||
return exit_code
|
||||
logger.info(
|
||||
"PLC 已连接;阀门已设置为 100%% 开度(行程 %.1f),不计入实验计时",
|
||||
position,
|
||||
)
|
||||
|
||||
recorder = OpenLoopRecorder(
|
||||
Path(__file__).resolve().parent / OUTPUT_DIRECTORY,
|
||||
@@ -573,8 +646,10 @@ def run(args):
|
||||
run_start = time.perf_counter()
|
||||
read_failures = 0
|
||||
|
||||
for step_index, opening in enumerate(openings):
|
||||
ok, position = set_opening(hardware, opening)
|
||||
for step_index, (opening, position) in enumerate(scan_points):
|
||||
ok = bool(
|
||||
hardware.set_motor_position(position, channel=MOTOR_CHANNEL)
|
||||
)
|
||||
if not ok:
|
||||
logger.critical(
|
||||
"写入开度 %.1f%% 对应行程 %.1f 失败,实验中止", opening, position
|
||||
@@ -584,7 +659,7 @@ def run(args):
|
||||
|
||||
logger.info(
|
||||
"步 %d/%d:设置开度 %.1f%%(行程 %.1f),等待后流量稳定…",
|
||||
step_index + 1, len(openings), opening, position,
|
||||
step_index + 1, len(scan_points), opening, position,
|
||||
)
|
||||
|
||||
detector.reset()
|
||||
@@ -614,7 +689,10 @@ def run(args):
|
||||
pressure_before, flow_before, pressure_after, flow_after
|
||||
)
|
||||
if fault is not None:
|
||||
logger.critical("安全阈值触发:%s,实验中止并关阀", fault)
|
||||
logger.critical(
|
||||
"安全阈值触发:%s,实验中止并在断开前恢复全开",
|
||||
fault,
|
||||
)
|
||||
exit_code = 2
|
||||
break
|
||||
|
||||
@@ -665,13 +743,18 @@ def run(args):
|
||||
finally:
|
||||
if connected:
|
||||
try:
|
||||
close_ok, _ = set_opening(hardware, 0.0)
|
||||
if not close_ok:
|
||||
open_ok, position = set_opening(hardware, 100.0)
|
||||
if open_ok:
|
||||
logger.info(
|
||||
"断开 PLC 前已设置阀门为 100%% 开度(行程 %.1f),不计入实验计时",
|
||||
position,
|
||||
)
|
||||
else:
|
||||
exit_code = max(exit_code, 4)
|
||||
logger.critical("收尾安全关阀失败,请立即人工检查")
|
||||
logger.critical("断开 PLC 前设置阀门 100%% 开度失败,请立即人工检查")
|
||||
except Exception:
|
||||
exit_code = max(exit_code, 4)
|
||||
logger.exception("收尾安全关阀时发生异常")
|
||||
logger.exception("断开 PLC 前设置阀门 100%% 开度时发生异常")
|
||||
try:
|
||||
hardware.disconnect()
|
||||
except Exception:
|
||||
|
||||
Reference in New Issue
Block a user