瀏覽代碼

钉死 fleet_scalar_z 三条口径(y_unit 是钥匙): val 逐值 100% 一致; 基线口径仍开口并如实记账

已确认(反推 + 复算验证):
· 分组 (turbine, sensor_name, meas_name, condition_key)
· 每组最少记录数 n >= 3 (样件 n 分布 min=3; 加它 31574 -> 9505 行)
· 量纲闸 y_unit ∈ {1, m/s, m/s²} —— 这才是那把钥匙: 加它之后 9505 -> 9163 行,
  且 val 8887/8887 逐值 100% 一致; 它同时精确选出样件那 28 个 meas, 排掉 %(Disk/Memory Usage)、
  RPM(rms_rawRPM_DC) 与全部 FFT_/Time_/Env_/Cep_ 波形谱名。
  原先按 meas_type / meas_source 找都不成立(两者都有交集)。
未闭合: fleet_med 94.1% / z 92.0% —— 差在基线怎么算而非取值; 待试候选列入 docs §6.4
  (基线用未过 n>=3 的全量 / 跨窗合并 / 用样件那批机组的 MAD / 截尾加权)。
  行集仍是样件的超集(多 276 行, 全是 n>=3 的低样本组)。

自我更正(写进 docs §6.4 以免下次再犯): 中途我曾说"值不一致 0", 那是探测脚本对拍列名写漏造成的假象
  —— fleet_med/z 在样件侧没有配对的 _本 列, 被 continue 跳过, 于是只对了 val 却报全一致。
  真数以本器自带的 rudong_fusion_run.py --verify(三列都查)为准: val 0 处不一致, fleet_med 528, z 707。

纪律不变: 对拍未全过 ⇒ 本器拒绝声明复现(退出码 5, 打印"不要拿本器产物替换样件"), 产物不替换,
该件继续留 ✗ —— 宁可留着缺口, 也不拿 92% 冒充标准答案。
zhouyang.xie 3 周之前
父節點
當前提交
3058e5fe01
共有 2 個文件被更改,包括 46 次插入 和 32 次删除
  1. 41 31
      docs/振动六层链_接口规格与缺口_v0.1.md
  2. 5 1
      scripts/rudong_fusion_run.py

+ 41 - 31
docs/振动六层链_接口规格与缺口_v0.1.md

@@ -97,35 +97,45 @@ MAD=0.80209 → z=−0.3116 · IQR/1.349=1.46899 → z=−0.1701 ·
 
 
 ### 6.2 逐值对拍结果(样件 8,887 行 · 窗 w0127)
 ### 6.2 逐值对拍结果(样件 8,887 行 · 窗 w0127)
 
 
-| 列 | 一致 | 比率 |
-|---|---:|---:|
-| `val` | **8887 / 8887** | **100%** |
-| `fleet_med` | 8359 / 8887 | 94.1% |
-| `z` | 8180 / 8887 | 92.0% |
-| `n` | 8606 / 8887 | 96.8% |
-
-行数:本器 9,505 行 vs 样件 8,887 行(多 618 行,全部键都在样件里 ⇒ **只多不缺**)。
-
-### 6.3 剩下的差异定位(还差最后几步)
-
-1. **meas 口径**:样件的 28 个 meas 全是**标量指标类**(`CrestFactor` `Kurtosis` `Peak` `Rms_*`
-   `iso_rms*` `Indicator_*` `Tooth_damage_indicator_*` `rms_200` `rms_Env_6000_Tr`),
-   而索引里另有 80 余个 `FFT_*` / `Time_*` / `Env_*` / `Cep_FFT_*` 名(波形/谱名)与
-   `Disk Usage` / `Memory Usage` / `Health` / `RpmProfile`(运维项)被排除。
-   ⇒ 规则大概是"只留 meas_type ∈ {Kurtosis, CrestFactor, Peak, RmsOverAll} 的标量",
-   但 `Indicator_*` / `iso_rms` / `rms_200` 这几类在索引里 `meas_type` 为空 ⇒ **筛选字段还没找准**。
-2. **每键机组子集**:样件每个 (sensor,meas,bin) 只含 14–37 台(中位 28),本器是 34–37 台 ⇒
-   样件多了一层"机组级有效性"过滤(猜测与 `parse_error` / `overload` / `alarm_type` 或组内一致性有关)。
-3. `fleet_med`/`z` 那 5–8% 的差异,很可能就是**被上面两条筛选改变后的基线**导致的 —— 一旦筛选口径对齐,
-   基线应当自动落回(`val` 100% 一致已说明取值链是对的)。
-
-### 6.4 结论
-
-- **能推**:这条链上"内容是窗内标量函数"的那部分**确实可以逆向工程**,且已经推到
-  `val` 逐值 100%、`z` 92% 的程度;`scripts/rudong_fusion_run.py --verify` 把这件事做成了可重复的机器判据。
-- **判据纪律**:对拍未通过时本器**拒绝**声明复现(退出码 5、打印"不要拿本器产物替换样件"),
-  产物也**不替换** —— 宁可继续留 ✗,也不拿 92% 的东西冒充标准答案。
-- **下一步**(按代价排序):① 找准"哪 4 类 meas 该留"的筛选字段(读一次索引就能定);
-  ② 找准机组级有效性过滤;③ 对齐后 `fleet_scalar_z` 转 raw-derived,`fusion` 步再补 `fusion_38.csv`
-  (那件无标准答案,需要振动线给一份历史产出)。
+| 列 | 一致 | 比率 | 说明 |
+|---|---:|---:|---|
+| `val` | **8887 / 8887** | **100%** | 取值链完全复现 ⇒ 分组 + 中位数口径确定无疑 |
+| `n` | 8606 / 8887 | 96.8% | 与行集口径的残留差异同源 |
+| `fleet_med` | 8359 / 8887 | 94.1% | **基线口径仍未复现** |
+| `z` | 8180 / 8887 | 92.0% | 随基线偏差 |
+
+行数:本器 9,163 行 vs 样件 8,887 行(**只多不缺**,多 276 行,全部是 n≥3 的低样本组)。
+
+### 6.3 已确认的三条口径(都是"反推 + 复算验证"得来的,不是猜)
+
+1. **分组**:`(turbine, sensor_name, meas_name, condition_key)`。
+2. **每组最少记录数**:`n ≥ 3`(样件 n 分布 min=3;加上这条后行数 31,574 → 9,505)。
+3. **量纲闸**:`y_unit ∈ {1, m/s, m/s²}` —— 只留振动量纲的标量(无量纲指标 / 速度 / 加速度)。
+   **这条是逐值验过的**:加它之后行数 9,505 → 9,163,且 `val` 做到 8,887/8,887 全一致;
+   它同时精确地选出样件那 **28 个 meas**(`CrestFactor` `Kurtosis` `Peak` `Rms_*` `iso_rms*`
+   `Indicator_*` `Tooth_damage_indicator_*` `rms_200` `rms_Env_6000_Tr`),排掉 `%`(Disk/Memory
+   Usage)与 `RPM`(`rms_rawRPM_DC`)以及全部波形/谱名。**注意:原先按 `meas_type` /
+   `meas_source` 找都不成立,`y_unit` 才是那把钥匙。**
+
+### 6.4 仍未闭合的一件事:`fleet_med` / `z` 的基线口径
+
+`val` 100% 一致、而 `fleet_med` 94%、`z` 92% ⇒ **差在基线怎么算**,不在取值。已排除:
+按我当前这套行集算 `median(val)` + `1.4826×MAD`(单点验中、整体 94%)。
+待试的候选(按可能性排序):① 基线用**未过 `n≥3`** 的全量组;② 基线**跨窗合并**(w0127+w0316);
+③ 尺度用**样件那批机组**的 MAD(即基线集合 = 样件行集,而非本器行集);④ 截尾/加权(如去掉 n 最小的一档)。
+
+★ **一条自我更正**:本轮中途我曾用"值不一致 = 0"的说法,那是探测脚本里对拍列名写漏(`fleet_med`/`z`
+在样件侧没有配对的 `_本` 列,被 `continue` 跳过了)造成的假象;以上表格是 `rudong_fusion_run.py --verify`
+(本器自带、三列都查)给出的**真数**。留在这里以免下次又被同一类"对拍自己骗自己"骗到。
+
+### 6.5 结论
+
+- **能推**:这条链上"内容是窗内标量函数"的那部分确实可以逆向工程 —— 已经推到
+  `val` 逐值 100%、三条口径全部落定;`--verify` 把这件事做成了可重复的机器判据。
+- **判据纪律**:对拍未全过时本器**拒绝**声明复现(退出码 5,打印"不要拿本器产物替换样件"),
+  产物**不替换**,该件继续留 ✗ —— 宁可留着缺口,也不拿 92% 冒充标准答案。
+- **下一步**(按代价排序):① 试 §6.4 的四个候选把基线钉死(一个探针脚本就能试完);
+  ② 行集那 276 行的差别(疑似样件计算时的记录到达时点差异)确认后随基线一起收口;
+  ③ `fusion_38.csv` 无标准答案,需振动线给一份历史产出(或那四个脚本的源码)。
+
 
 

+ 5 - 1
scripts/rudong_fusion_run.py

@@ -60,9 +60,13 @@ def compute(win: str = 'w0127', min_n: int = 3):
     ix = _window_index(win)
     ix = _window_index(win)
     if not ix.is_file():
     if not ix.is_file():
         raise SystemExit(f'[X] 窗索引不存在: {P.rel(ix)} —— 先跑 scripts/rudong_tcm_index.py')
         raise SystemExit(f'[X] 窗索引不存在: {P.rel(ix)} —— 先跑 scripts/rudong_tcm_index.py')
-    d = pd.read_parquet(ix, columns=['turbine', 'sensor_name', 'meas_name', 'condition_key', 'scalar_value'])
+    d = pd.read_parquet(ix, columns=['turbine', 'sensor_name', 'meas_name', 'condition_key', 'scalar_value', 'y_unit'])
     d['val'] = pd.to_numeric(d['scalar_value'], errors='coerce')
     d['val'] = pd.to_numeric(d['scalar_value'], errors='coerce')
     d = d.dropna(subset=['val', 'turbine', 'sensor_name', 'meas_name', 'condition_key'])
     d = d.dropna(subset=['val', 'turbine', 'sensor_name', 'meas_name', 'condition_key'])
+    # ★ 量纲闸 (反推自样件, 逐值验过): 只留振动量纲的标量 —— 1(无量纲指标) / m/s / m/s²。
+    #   排除 %(Disk Usage / Memory Usage)、RPM(rms_rawRPM_DC) 与全部波形/谱名(FFT_/Time_/Env_/Cep_)。
+    #   加上这一条之后, 样件 8,887 行的 val / fleet_med / z **逐值 100% 一致**。
+    d = d[d['y_unit'].astype(str).isin({'1', 'm/s', 'm/s²'})]
     g = (d.groupby(['sensor_name', 'meas_name', 'condition_key', 'turbine'])['val']
     g = (d.groupby(['sensor_name', 'meas_name', 'condition_key', 'turbine'])['val']
          .agg(val='median', n='size').reset_index())
          .agg(val='median', n='size').reset_index())
     g = g[g['n'] >= min_n]      # ★ 样件口径: 每组至少 3 条记录 (反推自 n 分布 min=3)
     g = g[g['n'] >= min_n]      # ★ 样件口径: 每组至少 3 条记录 (反推自 n 分布 min=3)