Bläddra i källkod

2.95.0 ④10 窗到位(门升至 7)+§5-3 实现(oem_hysteresis_scan/oem_latch; 缺口不作反例; RedHysteresis {3,100})+C02 呈现(fus.迟滞诊断: 33 序列/5 条被迟滞改变, 经 api 门)+置信度复算(中位 34.5/usable 27/107); 流程修正: 门禁不过禁止提交

zhouyang.xie 4 dagar sedan
förälder
incheckning
f549fdea4a

+ 1 - 1
VERSION

@@ -1 +1 @@
-2.94.0
+2.95.0

+ 17 - 0
app_algorithmModel/app_algorithmModel_guanlan/service/fleet_views.py

@@ -581,6 +581,7 @@ def fleet_view(win):
                    纪律=str(fmeta.get('纪律', '')), 盲区=[str(b) for b in fmeta.get('盲区', [])],
                   # ★① 置信度接线(2026-10-06, 诊断式): 只加不改; 缺件时带 caveat, 不可用于判状态
                   置信度=_conf_diag(ftab),
+                  迟滞诊断=_hyst_diag(),
                    open_items=[str(o) for o in fmeta.get('open_items', [])], gap=fmeta.get('gap'))
     except Exception as e:
         fus = dict(err=str(e)[:160])
@@ -1228,3 +1229,19 @@ def _conf_diag(ftab):
                 'per_row': out}
     except Exception as e:
         return {'err': type(e).__name__ + ': ' + str(e)[:120]}
+
+def _hyst_diag():
+    """★C02/§5-3(诊断用,data-added):原厂迟滞锁存 + 逐测量迟滞口径。**不参与任何判级。**"""
+    try:
+        from app_ontology.app_ontology_guanlan.api import sop_hysteresis_wire as _hw
+        lat = _hw.summary()
+        scan = _hw.oem_hysteresis_scan(limit=60)
+        return {'口径': '原厂 Hysteresis:连续 h 窗同向才改级(apply_hysteresis 语义未改);缺口保持、不作反例',
+                '序列数': lat.get('n_seq'), '被迟滞改变': lat.get('n_changed'), '改变清单': lat.get('changed'),
+                'h': lat.get('h'),
+                '逐测量迟滞分布': (scan.get('dist') or {}).get('RedHysteresis'),
+                '扫描文件数': scan.get('n_files'),
+                '用途': '**诊断/显示锁存**:说明"瞬时抬升会被原厂迟滞抑制";不可用于判断机组状态',
+                '来源': 'outputs/rudong/m5_cms_tcm/model_run_l6.parquet(多窗)+ raw decode JSON'}
+    except Exception as e:
+        return {'err': type(e).__name__ + ': ' + str(e)[:120]}

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 4 - 1
app_common/app_common_guanlan/version.py


+ 1 - 0
app_ontology/app_ontology_guanlan/api.py

@@ -44,6 +44,7 @@ _TARGETS: dict[str, str] = {
     'sop_vib_impact': 'app_ontology.app_ontology_guanlan.sop.vib_impact',
     'sop_vib_confidence': 'app_ontology.app_ontology_guanlan.sop.vib_confidence',
     'sop_vib_confidence_wire': 'app_ontology.app_ontology_guanlan.sop.vib_confidence_wire',
+    'sop_hysteresis_wire': 'app_ontology.app_ontology_guanlan.sop.hysteresis_wire',
     'sop_fusion_diag': 'app_ontology.app_ontology_guanlan.sop.fusion_diag',
     'sop_cases': 'app_ontology.app_ontology_guanlan.sop.cases',
     'sop_scenarios': 'app_ontology.app_ontology_guanlan.sop.scenarios',

+ 70 - 0
app_ontology/app_ontology_guanlan/sop/hysteresis_wire.py

@@ -61,3 +61,73 @@ def summary(path=None, h: int = 3) -> dict:
     return {'n_seq': n, 'n_changed': len(ch), 'changed': [('%s/%s' % k) for k in ch[:10]],
             'n_err': len(err), 'h': h,
             '口径': '原厂迟滞 Hysteresis=3:连续 3 窗同向才改级;序列只含实际过闸的窗'}
+
+
+# ── ★§5-3(2026-10-06):原厂"逐测量迟滞"读取 + 状态机 ────────────────────────────────
+# 事实基础(本轮实测):raw decode JSON 内确有数值型 RedHysteresis/YellowHysteresis/BlueHysteresis/
+# TrendHysteresis;抽样 120 文件得 RedHysteresis ∈ {3: 3330, 100: 30} ⇒ **"恒为 3"为假**,
+# 与上游报告(`mask.Hysteresis` 恒 3 为假;`rms_200` 一类上限 100)一致。
+_OEM_KEYS = ('RedHysteresis', 'YellowHysteresis', 'BlueHysteresis', 'TrendHysteresis')
+
+
+def oem_hysteresis_scan(root=None, limit=120) -> dict:
+    """抽样扫描 raw decode JSON,返回 {键: {值: 次数}} 与逐测量分布(只读,不落盘)。"""
+    import collections
+    import json
+    import pathlib as _p
+    import re as _re
+    base = _p.Path(root) if root else _p.Path(__file__).resolve().parents[3] / \
+        'data/raw/如东/windcms/CMS_RuDong_CGN_202603-04/measurement'
+    vals = {k: collections.Counter() for k in _OEM_KEYS}
+    per_meas = {}
+    n = 0
+    if not base.exists():
+        return {'err': 'raw 目录不存在', 'root': str(base)}
+    for f in base.rglob('*_decode.json'):
+        n += 1
+        txt = f.read_text(encoding='utf-8', errors='replace')
+        mname = None
+        mm = _re.search(r'"name"\s*:\s*"([^"]{1,48})"', txt)
+        if mm:
+            mname = mm.group(1)
+        for k in _OEM_KEYS:
+            for m2 in _re.finditer(r'"%s"\s*:\s*"?([^",}\]]{1,12})"?' % k, txt):
+                try:
+                    v = int(float(m2.group(1)))
+                except Exception:
+                    v = m2.group(1)
+                vals[k][v] += 1
+                if mname:
+                    per_meas.setdefault(mname, {}).setdefault(k, set()).add(v)
+        if n >= limit:
+            break
+    return {'n_files': n,
+            'dist': {k: dict(v.most_common(6)) for k, v in vals.items()},
+            'odd': {m: {k: sorted(v) for k, v in d.items() if any(x != 3 for x in v)}
+                    for m, d in per_meas.items() if any(any(x != 3 for x in v) for v in d.values())}}
+
+
+def oem_latch(levels, *, h=3, upper=None):
+    """原厂迟滞状态机(§5-3 口径):以数值 level 序列驱动。
+    · 起报:连续 h 窗同向抬升且达到上限 upper ⇒ 起报;到 0 ⇒ 解除。
+    · **缺口不当反例**:序列里以 None 表示"该窗无记录"(缺口)⇒ **保持当前状态**,不重置、不推进。
+    返回 (state, trace):state 为当前状态(0/起报值),trace 为逐窗状态。
+    """
+    cur = 0
+    up = 0
+    trace = []
+    for lv in levels:
+        if lv is None:                       # 缺口:保持,不计入连续计数
+            trace.append(cur)
+            continue
+        if upper is not None and lv >= upper:
+            up += 1
+            if up >= h:
+                cur = lv
+        elif lv <= 0:
+            cur = 0
+            up = 0
+        else:
+            up = 0
+        trace.append(cur)
+    return cur, trace

+ 1 - 1
docs/detail_页面依赖与重算台账_v0.1.md

@@ -6,7 +6,7 @@
 <!-- DETAIL-DEPS:BEGIN -->
 # /detail 页面依赖与重算台账 (自动生成, 禁手改)
 
-> 生成端: `python scripts/detail_deps.py --write`|场站 `rudong`|产物仓 `outputs/rudong`|盘上 5,933 件
+> 生成端: `python scripts/detail_deps.py --write`|场站 `rudong`|产物仓 `outputs/rudong`|盘上 6,417 件
 >
 > 用户令 (2026-09-18): **/detail 各页面不许用旧版产出补**, 只能参照旧版产物的呈现样式与内容, 数值必须由 `data/raw` 重算。本表把每页的取数接口与产物件逐条列清, 缺的写明怎么补。
 

+ 1 - 1
docs/src/数据要求说明_观澜_2.94.0.md → docs/src/数据要求说明_观澜_2.95.0.md

@@ -1,4 +1,4 @@
-# 数据要求说明 · 观澜 v2 风电场智能分析系统 · 版本 2.94.0
+# 数据要求说明 · 观澜 v2 风电场智能分析系统 · 版本 2.95.0
 
 ## 1 文档说明
 

+ 10 - 10
docs/src/系统设计说明_观澜_2.94.0.md → docs/src/系统设计说明_观澜_2.95.0.md

@@ -1,4 +1,4 @@
-# 系统设计说明 · 观澜 v2 风电场智能分析系统 · 版本 2.94.0
+# 系统设计说明 · 观澜 v2 风电场智能分析系统 · 版本 2.95.0
 
 ## 1 文档说明
 
@@ -6,19 +6,19 @@
 
 ### 1.1 目的与范围
 
-本文是"观澜 v2(风电场智能分析系统)"(海上风电场智能分析离线系统)的设计说明(下称"本系统"),面向版本 2.94.0;内容以样本风电场(下称"本场")为依据,样本场实测日期为 2026-09-22,说明本系统"由哪些部分组成、各部分怎么实现、数据从哪来到哪去、判据写在哪里、怎么验证、边界在哪里"。
+本文是"观澜 v2(风电场智能分析系统)"(海上风电场智能分析离线系统)的设计说明(下称"本系统"),面向版本 2.95.0;内容以样本风电场(下称"本场")为依据,样本场实测日期为 2026-09-22,说明本系统"由哪些部分组成、各部分怎么实现、数据从哪来到哪去、判据写在哪里、怎么验证、边界在哪里"。
 
 本文覆盖十五个设计面:总体架构与分层、目录结构与路径真源、数据接入与重算链、判级与算法、时间窗口径、服务与前端、本体与知识层、本机模型接入、运维控制台与重算编排、安装与服务化与版本管理、质量保证、安全与离线边界、可移植性与资源占用、多场适用性与换场迁移、已知边界与未实现。
 
-本文不重复需求条目本身(那是《需求分析_观澜_2.94.0.docx》的职责),也不重复操作步骤的逐步手册(那是 docs/重算操作手册_v0.1.md 与《使用说明书》v0.2(随包 docs/)的职责);本文只回答"设计上为什么这样、落在哪个文件的哪一处、用什么机器守卫保证它不漂移"。
+本文不重复需求条目本身(那是《需求分析_观澜_2.95.0.docx》的职责),也不重复操作步骤的逐步手册(那是 docs/重算操作手册_v0.1.md 与《使用说明书》v0.2(随包 docs/)的职责);本文只回答"设计上为什么这样、落在哪个文件的哪一处、用什么机器守卫保证它不漂移"。
 
 ### 1.2 读者与用法
 
 现场运维与检修人员可看第 3 章、第 7 章、第 8 章、第 11 章,了解自己能点到的页面背后读的是什么口径;场站管理人员与换场交付人员可看第 6 章、第 7 章、第 16 章、第 17 章,了解判级与可靠性指标的口径与边界,以及换场时要重新标定哪些参数;研发与交付人员应通读全文,重点是第 4 章、第 5 章、第 12 章、第 13 章;验收方可直接按第 13 章的质量门与附录 A 的编写依据逐条复核。
 
-### 1.3 与《需求分析_观澜_2.94.0.docx》的对应关系
+### 1.3 与《需求分析_观澜_2.95.0.docx》的对应关系
 
-需求分析写"要什么、为谁、优先级与验收门",设计说明写"怎么实现、落在哪、如何自证"。两文的章节对应关系如表 1-1 所示;与《数据要求说明_观澜_2.94.0.docx》的数据侧口径去向见 16.6 节。
+需求分析写"要什么、为谁、优先级与验收门",设计说明写"怎么实现、落在哪、如何自证"。两文的章节对应关系如表 1-1 所示;与《数据要求说明_观澜_2.95.0.docx》的数据侧口径去向见 16.6 节。
 
 | 本文章节 | 需求分析对应章 | 对应关系说明 |
 |---|---|---|
@@ -41,7 +41,7 @@
 
 ### 1.4 口径与依据
 
-本文所有数字来自仓库文件或命令的实跑输出,不采用估算与推测;查不到、未实现的,一律写"未取证"或"未实现",并在第 17 章汇总。本文中"本次实测"与各表"实测"列一律指样本场实测(2026-09-22):即在样本风电场的一套实例上的一次实跑,换场后这些数字会变、方法与口径不变。版本号的唯一真源是 src/version.py 的 VERSION 常量,本版为 2.94.0;打包文件名由 src/version.py 的 package_name() 给出,为 app_guanlang_v2.94.0.zip。
+本文所有数字来自仓库文件或命令的实跑输出,不采用估算与推测;查不到、未实现的,一律写"未取证"或"未实现",并在第 17 章汇总。本文中"本次实测"与各表"实测"列一律指样本场实测(2026-09-22):即在样本风电场的一套实例上的一次实跑,换场后这些数字会变、方法与口径不变。版本号的唯一真源是 src/version.py 的 VERSION 常量,本版为 2.95.0;打包文件名由 src/version.py 的 package_name() 给出,为 app_guanlang_v2.95.0.zip。
 
 本文遵循四条写作口径:含"窗"且确实指时间窗口的,一律写全"时间窗"(天气窗、作业窗、预览窗、观测窗属领域词,保持原样);影响的是风电机组时写"影响机组"或"影响机组数";使用英文简写时必须写成"中文(英文简写)"形式,如平均无故障间隔(MTBF)、平均停机间隔(MTBO)、单次停机时长(MDT);全文用简体中文与半角数字与单位。
 
@@ -863,7 +863,7 @@ Windows 安装入口是 install.bat 与 install.ps1,步骤号写死在输出
 
 ### 12.3 安装记录与版本三守卫
 
-安装记录 install-info.json 是"这台机器装的是哪一版"的唯一凭据,字段如表 12-3 所示。装完写、卸载时删(删掉等于这台机器回到"没装过")。需要如实指出:本机该文件记录的版本是 2.5.0(装于 2026-09-17),落后于当前代码版本 2.94.0,因此它正是"安装前检查会提示版本差异"的活样本;重装或升级后会随之更新。
+安装记录 install-info.json 是"这台机器装的是哪一版"的唯一凭据,字段如表 12-3 所示。装完写、卸载时删(删掉等于这台机器回到"没装过")。需要如实指出:本机该文件记录的版本是 2.5.0(装于 2026-09-17),落后于当前代码版本 2.95.0,因此它正是"安装前检查会提示版本差异"的活样本;重装或升级后会随之更新。
 
 | 字段 | 含义 |
 |---|---|
@@ -1030,7 +1030,7 @@ Windows 安装入口是 install.bat 与 install.ps1,步骤号写死在输出
 
 ### 15.2 Python 与依赖 wheel
 
-解释器要求是 3.11 及以上(依赖 pandas 3,3.10 及以下没有轮子);机器上没有 3.11 时使用包内便携运行时(3.12.14,三个平台各一份)。依赖清单共 175 条固定版本:polars 1.42.0、pandas 3.0.3、pyarrow 24.0.0、numpy 2.5.0、pyyaml 6.0.3、python-frontmatter 1.3.0、matplotlib 3.11.0、plotly 6.8.0、jinja2 3.1.6、python-docx 1.2.0、docxtpl 0.20.2、python-dotenv 1.2.2、requests 2.34.2、rich 15.0.0、tqdm 4.68.3、openpyxl 3.1.5、scipy 1.18.0、xlrd 2.0.2,另有一条不锁版本的 tzdata(Windows 无系统时区库,而 pandas 3 硬依赖它)。离线件如表 15-2 所示(件数与体积为本次实测)。
+解释器要求是 3.11 及以上(依赖 pandas 3,3.10 及以下没有轮子);机器上没有 3.11 时使用包内便携运行时(3.12.14,三个平台各一份)。依赖清单共 176 条固定版本:polars 1.42.0、pandas 3.0.3、pyarrow 24.0.0、numpy 2.5.0、pyyaml 6.0.3、python-frontmatter 1.3.0、matplotlib 3.11.0、plotly 6.8.0、jinja2 3.1.6、python-docx 1.2.0、docxtpl 0.20.2、python-dotenv 1.2.2、requests 2.34.2、rich 15.0.0、tqdm 4.68.3、openpyxl 3.1.5、scipy 1.18.0、xlrd 2.0.2,另有一条不锁版本的 tzdata(Windows 无系统时区库,而 pandas 3 硬依赖它)。离线件如表 15-2 所示(件数与体积为本次实测)。
 
 | 离线件目录 | 件数(实测) | 体积(实测) | 覆盖平台 |
 |---|---|---|---|
@@ -1224,7 +1224,7 @@ Linux 侧的适配程度如表 15-4 所示,全部为"已有实现但在本次
 
 ### 16.6 与同批交付文档的对应关系
 
-本章对应《需求分析_观澜_2.94.0.docx》第 11 章(场配置化、机组与机型可替换、数据源形态可适配、阈值按场标定、术语与单位可配、跨场统一口径、按场裁剪收资、换场验收检查表)与《数据要求说明_观澜_2.94.0.docx》第 12 章(通用必选与可选的判定规则、场配置字段对照、数据源形态适配、换场收资差异清单、按场裁剪步骤);本章给的是设计侧的落点、换场作业单与检查表,数据侧的收资口径与字段要求以数据要求说明为准,需求侧的验收项以需求分析为准。
+本章对应《需求分析_观澜_2.95.0.docx》第 11 章(场配置化、机组与机型可替换、数据源形态可适配、阈值按场标定、术语与单位可配、跨场统一口径、按场裁剪收资、换场验收检查表)与《数据要求说明_观澜_2.95.0.docx》第 12 章(通用必选与可选的判定规则、场配置字段对照、数据源形态适配、换场收资差异清单、按场裁剪步骤);本章给的是设计侧的落点、换场作业单与检查表,数据侧的收资口径与字段要求以数据要求说明为准,需求侧的验收项以需求分析为准。
 
 ***
 
@@ -1290,7 +1290,7 @@ Linux 侧的适配程度如表 15-4 所示,全部为"已有实现但在本次
 
 | 章节 | 来源文件 |
 |---|---|
-| 1 文档说明 | src/version.py(VERSION 与 HISTORY 的 2.59.0 条目)、docs/需求分析_观澜_2.94.0.docx、scripts/delivery_docs_figures.py |
+| 1 文档说明 | src/version.py(VERSION 与 HISTORY 的 2.59.0 条目)、docs/需求分析_观澜_2.95.0.docx、scripts/delivery_docs_figures.py |
 | 2 设计目标与原则 | docs/系统设计说明.md(四条设计铁律)、app_ontology/.../ontology/mcp_server.py 头部、src/windscada/subsys/fusion.py 头部、src/windscada/perf/reliability.py |
 | 3 总体架构 | configs/serve.json、scripts/guanlan_gateway.py、guanlan.py(组件启动表)、run/pids.json、docs/系统设计说明.md(产物全景) |
 | 4 目录结构与路径真源 | src/paths.py、configs/registry.yaml、docs/系统设计说明.md(路径约定与统一记录)、本次目录实测 |

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 9 - 8
docs/src/需求分析_观澜_2.95.0.md


BIN
docs/数据要求说明_观澜_2.94.0.docx


BIN
docs/数据要求说明_观澜_2.95.0.docx


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 3 - 3
docs/版本记录.md


BIN
docs/系统设计说明_观澜_2.94.0.docx → docs/系统设计说明_观澜_2.95.0.docx


BIN
docs/需求分析_观澜_2.94.0.docx → docs/需求分析_观澜_2.95.0.docx


Vissa filer visades inte eftersom för många filer har ändrats