make_table.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. #!/usr/bin/env python3
  2. """生成规范的多值总表与事件前后对照表(中文表头)。
  3. - 特征总表.csv:机组,缸,腔,角度箱,时间,压力幅度,极差,粗糙度,水平,波动次数,极值数
  4. (每个 测点×角度箱×日 取当日中位数)
  5. - 事件前后对照表.csv:机组,事件,故障类型,缸,腔,角度箱,指标,停机前,开机后,变化
  6. (5 个指标各一行,方便按"波动次数"筛角度)
  7. 只用现成的 `angle_bins.py` 输出,不重算数据库。
  8. """
  9. from __future__ import annotations
  10. import argparse
  11. import csv
  12. import sys
  13. from collections import defaultdict
  14. from datetime import datetime
  15. from pathlib import Path
  16. import numpy as np
  17. BACKEND = Path(__file__).resolve().parents[1]
  18. sys.path.insert(0, str(BACKEND))
  19. from event_bins import EVENTS, collect_after, collect_before, cycle_count, load # noqa: E402
  20. from run_segments import unit_segments # noqa: E402
  21. # 输出列 -> 原始列
  22. METRICS = [
  23. ("极差", "range"), ("粗糙度", "roughness"), ("水平", "mean"),
  24. ("波动次数", "zero_cross"), ("极值数", "n_extrema"),
  25. ]
  26. META = ["机组", "缸", "腔", "角度箱", "时间", "压力幅度"]
  27. def write_total(unit: str, rows: list[dict], out: Path) -> None:
  28. buckets = defaultdict(lambda: defaultdict(list))
  29. for r in rows:
  30. key = (r["cylinder"], r["side"], r["bin_start"], r["time"].date())
  31. buckets[key]["压力幅度"].append(r["p_span"])
  32. for cn, en in METRICS:
  33. if r[en] is not None:
  34. buckets[key][cn].append(r[en])
  35. with out.open("w", encoding="utf-8-sig", newline="") as fh:
  36. w = csv.writer(fh)
  37. w.writerow(META + [cn for cn, _ in METRICS])
  38. for (cyl, side, binstart, day) in sorted(buckets, key=lambda k: (k[0], k[1], k[2], k[3])):
  39. b = buckets[(cyl, side, binstart, day)]
  40. med = lambda k: (f"{np.median(b[k]):.4g}" if b.get(k) else "")
  41. w.writerow([unit, cyl, side, f"{binstart:g}", day.isoformat(), med("压力幅度")]
  42. + [med(cn) for cn, _ in METRICS])
  43. def write_event_table(unit: str, rows: list[dict], out: Path) -> None:
  44. segments = unit_segments(unit, 2)
  45. out_rows = []
  46. for eu, date, kind in EVENTS:
  47. if eu != unit:
  48. continue
  49. t0 = datetime.fromisoformat(date)
  50. for cyl, side in sorted({(r["cylinder"], r["side"]) for r in rows}):
  51. point_rows = [r for r in rows if r["cylinder"] == cyl and r["side"] == side]
  52. pre, _ = collect_before(point_rows, t0, segments, 6)
  53. post, _ = collect_after(point_rows, t0, segments, 30, 45)
  54. if cycle_count(pre) < 3 or cycle_count(post) < 3:
  55. continue
  56. for b in range(36):
  57. pr = [r for r in pre if r["bin"] == b]
  58. po = [r for r in post if r["bin"] == b]
  59. if len(pr) < 3 or len(po) < 3:
  60. continue
  61. for cn, en in METRICS:
  62. a = [r[en] for r in pr if r[en] is not None]
  63. c = [r[en] for r in po if r[en] is not None]
  64. if len(a) < 3 or len(c) < 3:
  65. continue
  66. am, cm = float(np.median(a)), float(np.median(c))
  67. out_rows.append({
  68. "机组": unit, "事件": date, "故障类型": kind, "缸": cyl, "腔": side,
  69. "角度箱": f"{b * 10}-{b * 10 + 10}", "指标": cn,
  70. "停机前": f"{am:.4g}", "开机后": f"{cm:.4g}", "变化": f"{cm - am:+.4g}",
  71. })
  72. with out.open("w", encoding="utf-8-sig", newline="") as fh:
  73. w = csv.DictWriter(fh, fieldnames=["机组", "事件", "故障类型", "缸", "腔", "角度箱", "指标",
  74. "停机前", "开机后", "变化"])
  75. w.writeheader()
  76. w.writerows(out_rows)
  77. def main() -> None:
  78. parser = argparse.ArgumentParser(description="生成规范多值总表")
  79. parser.add_argument("--csv", nargs="+", required=True, help="一个或多个 angle_bins CSV")
  80. parser.add_argument("--unit", nargs="+", required=True, help="与 --csv 对应的机组号")
  81. parser.add_argument("--outdir", required=True)
  82. args = parser.parse_args()
  83. outdir = Path(args.outdir)
  84. outdir.mkdir(parents=True, exist_ok=True)
  85. for unit, path in zip(args.unit, args.csv):
  86. print(f"读 {path} ...", flush=True)
  87. rows = load(path)
  88. write_total(unit, rows, outdir / f"特征总表_{unit}号.csv")
  89. write_event_table(unit, rows, outdir / f"事件前后对照_{unit}号.csv")
  90. print(f" {unit}号:特征总表 + 事件前后对照 已生成")
  91. if __name__ == "__main__":
  92. main()