完善流量控制前馈、稳态判定与阀门标定流程
- 前馈冻结改用可配置的 3 秒流量绝对误差滑窗,修复采样抖动造成的重复解冻,并保留下游扰动后的自动更新 - 支持非单调阀特性反解、最小可测面积以下直接全关,以及闭阀端精细扫点与辨识开关 - 调整双压力判稳、最长等待时间、在线入口全开收尾和闭环四联图 - 更新配置、README、阀模型及离线测试,归档本轮实验数据与诊断产物
This commit is contained in:
+61
-9
@@ -13,8 +13,9 @@ class PerformanceReporter:
|
||||
"""逐周期观测流量,判定稳态并输出控制性能报告。
|
||||
|
||||
稳态判定采用两个条件同时满足(AND):
|
||||
1. 滑窗均值落在目标流量 ±band_pct% 误差带内;
|
||||
2. 滑窗标准差低于 std_pct% 目标流量阈值。
|
||||
1. 流量滑窗均值落在目标流量 ±band_pct% 误差带内;
|
||||
2. 阀前、阀后压力的窗口样本均位于各自窗口均值
|
||||
±pressure_band_kpa 范围内。
|
||||
报告只在首次判定稳态时输出一次。
|
||||
"""
|
||||
|
||||
@@ -25,7 +26,7 @@ class PerformanceReporter:
|
||||
window_s,
|
||||
sample_period_s,
|
||||
band_pct,
|
||||
std_pct,
|
||||
pressure_band_kpa,
|
||||
flow_range_min_slm,
|
||||
flow_range_max_slm,
|
||||
initial_flow_slm=None,
|
||||
@@ -35,7 +36,7 @@ class PerformanceReporter:
|
||||
self.window_s = float(window_s)
|
||||
self.sample_period_s = float(sample_period_s)
|
||||
self.band_pct = float(band_pct)
|
||||
self.std_pct = float(std_pct)
|
||||
self.pressure_band_kpa = float(pressure_band_kpa)
|
||||
self.flow_range_min_slm = float(flow_range_min_slm)
|
||||
self.flow_range_max_slm = float(flow_range_max_slm)
|
||||
self.initial_flow_slm = (
|
||||
@@ -48,10 +49,15 @@ class PerformanceReporter:
|
||||
self.steady_mean = None
|
||||
self.steady_std = None
|
||||
self.steady_error_slm = None
|
||||
self.steady_pressure_before_mean = None
|
||||
self.steady_pressure_after_mean = None
|
||||
self.steady_pressure_before_max_deviation = None
|
||||
self.steady_pressure_after_max_deviation = None
|
||||
self._first_timestamp = None
|
||||
self._peak_flow_slm = None
|
||||
self._min_flow_slm = None
|
||||
self._window = deque() # 元素为 (elapsed_s, flow_slm)
|
||||
# 元素为 (elapsed_s, flow_slm, pressure_before_kpa, pressure_after_kpa)
|
||||
self._window = deque()
|
||||
self._reached = False
|
||||
|
||||
def observe(self, result):
|
||||
@@ -62,7 +68,16 @@ class PerformanceReporter:
|
||||
return
|
||||
|
||||
flow = float(result.measured_flow_slm)
|
||||
if not math.isfinite(flow):
|
||||
pressure_before = result.pressure_before_kpa
|
||||
pressure_after = result.pressure_kpa
|
||||
if pressure_before is None or pressure_after is None:
|
||||
return
|
||||
pressure_before = float(pressure_before)
|
||||
pressure_after = float(pressure_after)
|
||||
if not all(
|
||||
math.isfinite(value)
|
||||
for value in (flow, pressure_before, pressure_after)
|
||||
):
|
||||
return
|
||||
target = float(result.target_flow_slm)
|
||||
if target <= 0.0:
|
||||
@@ -80,7 +95,9 @@ class PerformanceReporter:
|
||||
if self._min_flow_slm is None or flow < self._min_flow_slm:
|
||||
self._min_flow_slm = flow
|
||||
|
||||
self._window.append((elapsed_s, flow))
|
||||
self._window.append(
|
||||
(elapsed_s, flow, pressure_before, pressure_after)
|
||||
)
|
||||
cutoff = elapsed_s - self.window_s
|
||||
while self._window and self._window[0][0] < cutoff:
|
||||
self._window.popleft()
|
||||
@@ -95,17 +112,38 @@ class PerformanceReporter:
|
||||
return
|
||||
|
||||
flows = [item[1] for item in self._window]
|
||||
pressures_before = [item[2] for item in self._window]
|
||||
pressures_after = [item[3] for item in self._window]
|
||||
mean = statistics.mean(flows)
|
||||
std = statistics.pstdev(flows)
|
||||
pressure_before_mean = statistics.mean(pressures_before)
|
||||
pressure_after_mean = statistics.mean(pressures_after)
|
||||
pressure_before_max_deviation = max(
|
||||
abs(value - pressure_before_mean) for value in pressures_before
|
||||
)
|
||||
pressure_after_max_deviation = max(
|
||||
abs(value - pressure_after_mean) for value in pressures_after
|
||||
)
|
||||
|
||||
band = self.band_pct / 100.0 * target
|
||||
std_threshold = self.std_pct / 100.0 * target
|
||||
if abs(mean - target) <= band and std <= std_threshold:
|
||||
pressure_stable = (
|
||||
pressure_before_max_deviation <= self.pressure_band_kpa
|
||||
and pressure_after_max_deviation <= self.pressure_band_kpa
|
||||
)
|
||||
if abs(mean - target) <= band and pressure_stable:
|
||||
self._reached = True
|
||||
self.settling_time_s = elapsed_s
|
||||
self.steady_mean = mean
|
||||
self.steady_std = std
|
||||
self.steady_error_slm = target - mean
|
||||
self.steady_pressure_before_mean = pressure_before_mean
|
||||
self.steady_pressure_after_mean = pressure_after_mean
|
||||
self.steady_pressure_before_max_deviation = (
|
||||
pressure_before_max_deviation
|
||||
)
|
||||
self.steady_pressure_after_max_deviation = (
|
||||
pressure_after_max_deviation
|
||||
)
|
||||
self._report()
|
||||
|
||||
def finalize(self):
|
||||
@@ -125,6 +163,10 @@ class PerformanceReporter:
|
||||
self.steady_mean = None
|
||||
self.steady_std = None
|
||||
self.steady_error_slm = None
|
||||
self.steady_pressure_before_mean = None
|
||||
self.steady_pressure_after_mean = None
|
||||
self.steady_pressure_before_max_deviation = None
|
||||
self.steady_pressure_after_max_deviation = None
|
||||
self._first_timestamp = None
|
||||
self._peak_flow_slm = None
|
||||
self._min_flow_slm = None
|
||||
@@ -171,6 +213,16 @@ class PerformanceReporter:
|
||||
f"调节时间(至稳态): {self.settling_time_s:.3f} s",
|
||||
f"稳态流量(窗口均值): {self.steady_mean:.3f} SLM",
|
||||
f"稳态标准差(窗口): {self.steady_std:.3f} SLM",
|
||||
(
|
||||
"阀前压力(窗口均值/最大偏差): "
|
||||
f"{self.steady_pressure_before_mean:.3f} kPa / "
|
||||
f"±{self.steady_pressure_before_max_deviation:.3f} kPa"
|
||||
),
|
||||
(
|
||||
"阀后压力(窗口均值/最大偏差): "
|
||||
f"{self.steady_pressure_after_mean:.3f} kPa / "
|
||||
f"±{self.steady_pressure_after_max_deviation:.3f} kPa"
|
||||
),
|
||||
(
|
||||
f"稳态误差: {self.steady_error_slm:+.3f} SLM "
|
||||
f"(目标 - 稳态均值)"
|
||||
|
||||
Reference in New Issue
Block a user