open_loop.py文件的记录数据部分再新加两列,一列是"P_abs_ratio",定义为阀后绝对压力比阀前绝对压力的,绝对压力为传感器读数加大气压值。另一列是"is_ratio_smaller_than_0.528",判断这个比值是否小于0.528(临界压力比),是的话就填Y,不是就填N.

然后再新画一个图,就是"P_abs_ratio"随时间变化的图,并且标出0.528代表的那条直线。这个图与已有的两幅图放在一个窗口中绘制。
This commit is contained in:
2026-08-20 01:36:35 +08:00
parent 9bf9eb4205
commit c9984b1112
+59 -6
View File
@@ -6,8 +6,8 @@
2. 逐个开度:写入电机行程 → 以固定周期采集控流阀前后 4 个传感器 2. 逐个开度:写入电机行程 → 以固定周期采集控流阀前后 4 个传感器
(前压力、前流量、后压力、后流量)→ 等待“控流阀后流量”进入稳态后 (前压力、前流量、后压力、后流量)→ 等待“控流阀后流量”进入稳态后
切换到下一个开度; 切换到下一个开度;
3. 全程逐周期写 CSV,结束后在单个窗口内输出张子图(前后压力、前后流量), 3. 全程逐周期写 CSV,结束后在单个窗口内输出张子图(前后压力、前后流量
保存到工程目录下的 open_loop_data/。 绝对压力比),保存到工程目录下的 open_loop_data/。
示例: 示例:
python open_loop.py python open_loop.py
@@ -71,6 +71,11 @@ PLOT_DPI = config.PLOT_DPI
ANNOTATE_STEPS = True # 曲线上标注开度步 ANNOTATE_STEPS = True # 曲线上标注开度步
# 绝对压力 = 表压读数 + 大气压;临界压力比用于判断是否出现壅塞(choked)流动。
ATMOSPHERIC_PRESSURE_KPA = 101.325 # 标准大气压(kPa
CRITICAL_PRESSURE_RATIO = 0.528 # 临界压力比(阀后绝对压力 / 阀前绝对压力)
CSV_FIELDS = ( CSV_FIELDS = (
"time_s", "time_s",
"step_index", "step_index",
@@ -80,6 +85,8 @@ CSV_FIELDS = (
"flow_after_slm", "flow_after_slm",
"pressure_before_kpa", "pressure_before_kpa",
"pressure_after_kpa", "pressure_after_kpa",
"P_abs_ratio",
"is_ratio_smaller_than_0.528",
) )
@@ -140,7 +147,7 @@ class SteadyStateDetector:
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
class OpenLoopRecorder: class OpenLoopRecorder:
"""逐周期写 CSV,结束时输出张子图(前后压力、前后流量)。""" """逐周期写 CSV,结束时输出张子图(前后压力、前后流量、绝对压力比)。"""
def __init__(self, output_directory, *, plot_dpi=160): def __init__(self, output_directory, *, plot_dpi=160):
output_dir = Path(output_directory) output_dir = Path(output_directory)
@@ -176,6 +183,18 @@ class OpenLoopRecorder:
if self._closed: if self._closed:
raise RuntimeError("记录器已关闭") raise RuntimeError("记录器已关闭")
p_abs_ratio = self._absolute_pressure_ratio(
pressure_before_kpa, pressure_after_kpa
)
if p_abs_ratio is None:
p_abs_ratio_text = ""
is_smaller_text = ""
else:
p_abs_ratio_text = f"{p_abs_ratio:.6f}"
is_smaller_text = (
"Y" if p_abs_ratio < CRITICAL_PRESSURE_RATIO else "N"
)
self._writer.writerow( self._writer.writerow(
{ {
"time_s": self._fmt(time_s), "time_s": self._fmt(time_s),
@@ -186,6 +205,8 @@ class OpenLoopRecorder:
"flow_after_slm": self._fmt(flow_after_slm), "flow_after_slm": self._fmt(flow_after_slm),
"pressure_before_kpa": self._fmt(pressure_before_kpa), "pressure_before_kpa": self._fmt(pressure_before_kpa),
"pressure_after_kpa": self._fmt(pressure_after_kpa), "pressure_after_kpa": self._fmt(pressure_after_kpa),
"P_abs_ratio": p_abs_ratio_text,
"is_ratio_smaller_than_0.528": is_smaller_text,
} }
) )
self._file.flush() self._file.flush()
@@ -195,6 +216,21 @@ class OpenLoopRecorder:
self.steps.append((float(time_s), float(opening_pct))) self.steps.append((float(time_s), float(opening_pct)))
self._last_step_index = step_index self._last_step_index = step_index
@staticmethod
def _absolute_pressure_ratio(pressure_before_kpa, pressure_after_kpa):
"""阀后绝对压力 / 阀前绝对压力;读数缺失或分母非法时返回 None。"""
if pressure_before_kpa is None or pressure_after_kpa is None:
return None
try:
before_abs = float(pressure_before_kpa) + ATMOSPHERIC_PRESSURE_KPA
after_abs = float(pressure_after_kpa) + ATMOSPHERIC_PRESSURE_KPA
except (TypeError, ValueError):
return None
if before_abs <= 0:
return None
ratio = after_abs / before_abs
return ratio if math.isfinite(ratio) else None
def finalize(self): def finalize(self):
"""关闭 CSV 并生成 PNG;无采样点时只保留 CSV。""" """关闭 CSV 并生成 PNG;无采样点时只保留 CSV。"""
self.close() self.close()
@@ -221,6 +257,7 @@ class OpenLoopRecorder:
flow_after = [] flow_after = []
pressure_before = [] pressure_before = []
pressure_after = [] pressure_after = []
p_abs_ratio = []
with self.csv_path.open("r", newline="", encoding="utf-8-sig") as file: with self.csv_path.open("r", newline="", encoding="utf-8-sig") as file:
for row in csv.DictReader(file): for row in csv.DictReader(file):
@@ -233,11 +270,12 @@ class OpenLoopRecorder:
pressure_after.append( pressure_after.append(
self._float_or_nan(row["pressure_after_kpa"]) self._float_or_nan(row["pressure_after_kpa"])
) )
p_abs_ratio.append(self._float_or_nan(row["P_abs_ratio"]))
figure, axes = plt.subplots( figure, axes = plt.subplots(
2, 3,
1, 1,
figsize=(12, 9), figsize=(12, 12),
sharex=True, sharex=True,
constrained_layout=True, constrained_layout=True,
) )
@@ -264,10 +302,25 @@ class OpenLoopRecorder:
"Flow after valve", "#6A1B9A", "Flow after valve", "#6A1B9A",
) )
axes[1].set_ylabel("Flow (SLM)") axes[1].set_ylabel("Flow (SLM)")
axes[1].set_xlabel("Time (s)")
axes[1].set_title("Flow across control valve") axes[1].set_title("Flow across control valve")
axes[1].legend(loc="best") axes[1].legend(loc="best")
self._plot_series(
axes[2], time_s, p_abs_ratio,
"P_abs_ratio (after/before)", "#EF6C00",
)
axes[2].axhline(
CRITICAL_PRESSURE_RATIO,
color="#B71C1C",
linestyle="--",
linewidth=1.2,
label=f"Critical ratio {CRITICAL_PRESSURE_RATIO:.3f}",
)
axes[2].set_ylabel("P_abs_ratio")
axes[2].set_xlabel("Time (s)")
axes[2].set_title("Absolute pressure ratio across control valve")
axes[2].legend(loc="best")
if ANNOTATE_STEPS and self.steps: if ANNOTATE_STEPS and self.steps:
y_top = axes[1].get_ylim()[1] y_top = axes[1].get_ylim()[1]
for step_time, opening in self.steps: for step_time, opening in self.steps: