# -*- coding: utf-8 -*- """生成「运行形态塌陷 · 动态三维」交互页。 数据源: 如东 obs_sprt / mset_sprt 的 morphology_health_margin_grid.csv (各 1080 行 = 4 台 x 18 月 x 15 风速档)。 已脱敏: 台号重编为 机组 A-D, 不含场名与厂商。 边界(引自 method_metadata.json, 原文照搬, 不得删): - 本通道只用运行形态, 不含轴承/齿轮温度与振动特征 - 1 分钟源数据止于 2026-06-30 - 合格的 SPRT 候选是**审计条目, 不是部件故障结论** """ import csv, json, pathlib, collections SRC = pathlib.Path("/Users/yuanying/wind-analytics/outputs/rudong/integrated_diagnostic_report") SIM = pathlib.Path("/Users/yuanying/guanlan-rudong-v2/outputs/rudong/windscada/_demo/sim") def load(algo): rows = list(csv.DictReader(open(SRC/algo/"morphology_health_margin_grid.csv", encoding="utf-8-sig"))) meta = json.load(open(SRC/algo/"method_metadata.json", encoding="utf-8")) tids = sorted({r["tid"] for r in rows}) months = sorted({r["month"] for r in rows}) bins = sorted({int(float(r["wind_bin"])) for r in rows}) alias = {t: f"机组 {chr(65+i)}" for i, t in enumerate(tids)} # 脱敏: 台号重编 grid = {} for t in tids: z = [[None]*len(bins) for _ in months] for r in rows: if r["tid"] != t: continue v = r["health_margin"] if v in ("", "nan"): continue z[months.index(r["month"])][bins.index(int(float(r["wind_bin"])))] = round(float(v), 4) grid[alias[t]] = z return {"turbines": [alias[t] for t in tids], "months": months, "bins": bins, "grid": grid, "thr": next((meta[k] for k in ("obs_threshold_95","mset_threshold_95","threshold_95") if k in meta), None), "full_mset": not meta.get("not_true_mset", False), "limits": meta.get("limitations", []), "nfeat": len(meta.get("features", []))} DATA = {"简化记忆矩阵法": load("obs_sprt"), "完整相似算子法": load("mset_sprt")} J = json.dumps(DATA, ensure_ascii=False) HTML = f'''
横轴风速档、纵轴月份、高度是健康裕度。绿色平面是正常, 裕度掉到零平面以下就是形态塌陷 —— 在图上表现为从曲面往下扎的一口井。 拖动可旋转、滚轮可缩放、悬停看具体数值。