日期: 2026-09-12 · 适用:
<安装目录>(安装目录) 本文回答: ①振动侧的现场件长什么样、放哪;②谁把它变成系统能用的东西;③改了哪些代码、怎么验收; ④哪些还做不到(如实列,不假装)。 相关:docs\数据目录结构与落位约定_v0.2.md(§2b 落位速查)·docs\重算操作手册_v0.1.md(一键重算)
用户令原文(路径按本包文档约定写成占位符): 「数据层里的「CMS 振动评估报告」应遵循
<安装目录>\data\raw\如东\windcms、「振动线 handoff」应遵循 <安装目录>\data\raw\如东\m5_cms_tcm
存放; 要求 1. 修改 <安装目录> 下的观澜系统, 支持振动数据参与系统运行、重算等;
<现场包目录> 提取相应振动数据存放至上述目录」;随后用户把 CMS_RuDong_CGN_202603-04.zip
放进现场包 —— 那正是此前缺的原始件。现场包(<现场包目录>)里的振动相关件共三类:
| # | 件 | 形态 | 能不能算 |
|---|---|---|---|
| ① | CMS_RuDong_CGN_202603-04.zip(38.8 GB 压缩 / 150 GB 解压 / 25,679 件) |
Brande TCM Enterprise 导出: measurement\<年>\<月>\<WTGxx>\<WTGxx>_<uuid>_decode.json;每件是一次 API 响应 {body:{body:{"<时间戳>":[{"Record":{…}}]}}} |
能(索引/谱/报告全部由它算) |
| ② | 12 份月度「振动分析报告(用印版)」PDF(2025-06…2026-05) | 纯扫描件 | 不能 |
| ③ | 上海电气 2026年07月报告 docx(4.87 MB)· 大生科技传动链报告 docx(20.81 MB) | Word, 有文本层 | 能(逐台判级转录) |
②为什么不能算(实测, 不是推测): 用 pypdf 打开 2026年5月那份 → len(pages)=12,
每页 len(images)=1, page.extract_text() 长度 0(12 页全 0)。字节面也印证: /Font 0 处、
FlateDecode 0 处、/Image 24 处、DCTDecode 12 处 = 每页一张 JPEG。
⇒ 没有 OCR 就取不出任何数值。处理方式: 只登记归档(_扫描件清单.json 记 sha256/大小/无文本层),
不参与判级、不假装读过。要它们的数值只有两条路: 现场给电子件(docx/xlsx),或上 OCR(本包不装)。
顺带核过的一条旧判断: v0.2.0 初版把「(8)…\振动分析报告\」列在"故意不落"里,理由是
"成品牌报告而非可再加工的测量数据, 且 windcms 要的测点索引包里没有"。该判断在 2026-09-12 被推翻
(①到货后索引源件具备),故改为落位。现场包里的同件副本(根目录 …2026年5月…(2).pdf、
嵌套包 如东海上振动报告11份.zip)不重复落 —— 落三遍会得到 3 份同名报告。
data\raw\如东\
├─ windcms\ ← 数据层「CMS 振动评估报告」
│ ├─ CMS_RuDong_CGN_202603-04\
│ │ └─ measurement\2026\{03,04}\WTGxx\*_decode.json 25,679 件 / 150 GB
│ └─ 厂家报告\上海电气_月度\
│ ├─ 中广核如东海上风电场2025年06月…2026年05月振动分析报告用印版.pdf 12 件(扫描件)
│ ├─ 中广核如东海上风电场2026年07月振动分析报告_上海电气.docx
│ └─ _扫描件清单.json
└─ m5_cms_tcm\ ← 数据层「振动线 handoff」
└─ 厂家报告\
└─ 中广核如东海上风电场传动链振动分析报告_大生科技_20260311(1).docx
src\windscada\config.py 的 STATION_SUBDIRS(扫描/落位/维护页从此认它们;
改目录名 = 换接口,要同步维护页与本文)。measurement\ 这一层(来源可追溯);摄入按 rglob 找 *_decode.json,
套不套这层都能吃。handoff_vibration_v2.json / component_history.json 正本,放 m5_cms_tcm\ 下即被优先采用
(包内那两份目前仍是随包快照 —— 振动线分支的产物没随包,见 §7)。落位命令(映射表可复核、可重跑,同尺寸文件自动跳过):
.venv\Scripts\python.exe scripts\place_raw_data.py --src <现场包目录> --scope vib --dry-run
.venv\Scripts\python.exe scripts\place_raw_data.py --src <现场包目录> --scope vib
data/raw/如东/windcms/…/*_decode.json
│ scripts/rudong_tcm_index.py → outputs/rudong/m5_cms_tcm/windows/<窗>/index.parquet (54 列)
│ scripts/rudong_tcm_spectra.py → outputs/rudong/m5_cms_tcm/windows/<窗>/spectra/*.npz
│ + <窗>/spectra_meta.parquet(谱库目录内另存一份, 兼顾两种读取路径)
│ [可选] scripts/windcms.py report / kb → outputs/rudong/windcms/*(★默认不跑, 见 §3b)
▼
data/raw/如东/{windcms,m5_cms_tcm}/…/*.docx
│ scripts/vib_reports_build.py → outputs/rudong/windcms/厂家报告提取_<报告期>.json
│ + 报告_CMS振动状态评估报告_<报告期>.md(与自产报告同构)
│ + outputs/rudong/m5_cms_tcm/报告_TCM传动链振动分析_<报告期>.md
一键: scripts/vib_raw_build.py(索引→谱;--skip-spectra 可关;--with-report 才跑报告/知识库)。
它也写 outputs/rudong/m5_cms_tcm/vib_raw_manifest.json(源件路径、窗名、行数、谱数、时间窗、
各步耗时/rc,以及 missing_chain)。
跑一次 scripts/windcms.py report 在本包会让产物变差:
| 件 | 随包快照 | 本包重生成后 | 变化 |
|---|---|---|---|
windcms/report.md |
16,857 B(含逐台融合级表 + L4 过闸谱线) | 467 B(融合级表空、L4 写"无") | −97.2% |
windcms/overview.html |
646,218 B | 548,466 B | −15.1% |
windcms/index_eng.html |
443,841 B | 408,112 B | −8.0% |
windcms/index.html |
389,997 B | 382,544 B | −1.9%(逐台页仍 38 个) |
根因不在数据,在缺件:src/windcms/data.py::load_model() 要读 m5/model_run_l6.parquet 与
m5/fusion_38.csv,而这两件属六层链的 model_run / fusion 两步 —— 那四步脚本没随包(§7),产物也不在。
于是"重生成"= 用残缺输入覆盖完整快照。
处置: 摄入默认只做索引/谱(加性、不覆盖任何随包件);报告/知识库改为 --with-report 显式开启,
且要求先备份 outputs/<场>/windcms/。本次实测后已把 outputs/rudong/windcms 逐字节还原为随包快照
(56 件,哈希比对 0 差异),只保留厂家报告转录那两件。六层链补齐后这个默认值应当翻过来。
来源登记: 摄入与转录产出的每一件都由构建脚本自登记进 outputs/<场>/_derived_manifest.json
(src/derived_manifest.py),_provenance.json 生成时据此把它们记成 raw-derived ——
避免"新造的件因不在随包快照里而整条不进台账"。
窗名口径: wMMDD = 数据起始日(与既有 w0127/w0707/w0811 同口径)。
src\windcms\pipeline.py::window_year_gate 会拦"窗名无年份 + 数据过老"的误用(w1226 事故的护栏)。
重复摄入同一批数据时,已存在的窗自动改名为 <窗>_reimport_<时分>,而 data.EXCLUDE_DEFAULT
把带 _reimport 的窗排除在生产集外 —— 重复摄入不会污染分析集。
消费者(无需改一行代码,窗是自动发现的):
| 消费者 | 拿什么 |
|---|---|
src\windcms\data.py::windows() |
扫 m5\windows\w????\index.parquet → 新窗进分析集 |
src\windcms\data.py::load_scalars() |
各窗标量(ds_size==1 行)拼接 → CMS 报告/页面 |
src\windcms\data.py::spectrum() |
spectra_meta.parquet + npz['values'][shard_row] → 谱图能取到 |
src\windscada\taxonomy.py / subsys\fusion.py::windcms_grades() |
最新 报告_CMS振动状态评估报告_*.md 的 ## 附录 A 表 → 设备状态转录 |
★
spectra这一环此前是死的: 包内m5\spectra\、m5\windows\两个目录整个不在,data.spectrum()只能返回 None。本次摄入让谱图第一次有数据可画。
摄入产物与包内既有产物是同构关系,基准就是包内那份 outputs\rudong\m5_cms_tcm\tcm_index.parquet
(330,308 行 × 54 列,2026-01-27~02-03 窗,同一摄取逻辑的产物):
| 检查 | 结果 |
|---|---|
| 列名与列序 | 完全一致(54 列,逐字抄自基准,含列序) |
| dtype | 差异 3 列: rec_i(float64/int64)、ds_dim(float64/str)、parse_error(str/object)—— 消费者按列名取数,不受影响 |
| 取值(FFT 行) | x_offset=0.0 x_delta=0.9375 x_unit='Hz' y_unit='m/s²' 与基准同行逐格一致 |
| 内部一致性 | ds_size == lines+1 比例 1.000 |
TCM 导出里踩过的两个坑(写在这里防复发):
Measurement.DataSets 层,不在 DataSet 里。Size/Dimension/Values 在
DataSets.DataSet,而 X-axisOffset/X-axisDelta/X-axisUnit/Y-axisUnit 在上一层。
第一版两层取错 → 四列整列为空,内部一致性检查算出 0.000(本该 1.000)才暴露。先看一致性数再信列。DataSets.DataSet.Values 是空格分隔的数值字符串(不是数组)。谱: Size=Lines+1;
X-axisDelta = 带宽/Lines(例: 6000/6400 = 0.9375)。标量: Size==1 时 Values 本身就是标量值。
另有少数测量(FFT_250/2000/10000_Tr, Lines=400)的 x_delta = 带宽/800 = 半带宽口径 ——
源数据自己的约定,摄入原样转录,不做"修正"。scripts\vib_reports_build.py 只做转录,不做判级:
tc 恒等还原:python-docx 对合并区会把同一个 tc 在相邻列/行重复给出,
照抄会把 优秀 | 优秀 | 优秀 压成一格(第一版手工 dump 就吃了这个亏: 表里 WTG-01 行显示成
WTG-01 | 优秀 | 无,实际是 主轴承=优秀 齿轮箱=优秀 发电机=优秀 结论=无)。规则: 同行 tc 与左邻
相同 = 横向合并(沿用左值);与上行同列相同 = 纵向合并(沿用上值)。{优秀34, 良好3, 不可判1} —— 逐项一致("无数据"记 不可判: 没测到 ≠ 正常)。—。报告_TCM传动链振动分析_*.md,不冒充 handoff 判级。.venv\Scripts\python.exe scripts\place_raw_data.py --src <现场包目录> --scope vib --dry-run # 先看计划
.venv\Scripts\python.exe scripts\place_raw_data.py --src <现场包目录> --scope vib # 落位 (150 GB)
.venv\Scripts\python.exe scripts\vib_raw_build.py --jobs 10 # 摄入 (索引+谱)
.venv\Scripts\python.exe scripts\vib_reports_build.py --dump # 只打印转录, 人工核对
.venv\Scripts\python.exe scripts\vib_reports_build.py # 写产物
.venv\Scripts\python.exe scripts\scan_stations.py # 两个新目录是否被认到
落位(实测): windcms\CMS_RuDong_CGN_202603-04 25,679 件 150.1 GB +
windcms\厂家报告\上海电气_月度 13 件 51.4 MB + m5_cms_tcm\厂家报告 1 件 20.8 MB = 25,693 件 / 150.2 GB
(rc=0;余量要求: F: 需 ≥ 165 GB)。重跑幂等(同尺寸跳过;实测第二次跳过 2 件已存在的 docx)。
摄入(实测, 10 并行): 索引步 392.8 s → windows\w0316\index.parquet 2,066,686 行 × 54 列
(标量行 861,917 · 谱行 1,204,769;38 台;时间 2026-03-16 17:27:22 → 2026-04-21 10:18:33);
谱步 477.2 s → 420,742 条谱 / 1,712 个 npz 分片(只转 FFT_,故小于"谱行"数;
Size>1 行里另有 Time_* 波形 78 万行未转)。窗体合计 3.27 GB。全链 875 s(15 分钟)。
消费端(实测, 改代码前后都是同一套消费者):
| 环节 | 实测结果 |
|---|---|
data.windows() |
发现 ['w0127', 'w0316'] —— 新窗自动进分析集 |
data.load_scalars() |
193,902 行 × 11 列(w0316 贡献 168,880;7 个关键标量齐) |
data.spectra_meta() |
420,742 行 × 18 列,8 个测点全 |
data.spectrum() |
✅ 取到真实谱: WTG01 / Gear_IMS / FFT_6000_Tr → 6,401 点,x 0→6000 Hz,y 单位 m/s²(此前 m5/spectra 缺失 ⇒ 只能返回 None) |
| 索引列契约 | data._read_index() 要的 10 列齐;无缺列 |
厂商报告转录: 上海电气 2026-07 → 38 台,取严 {优秀34, 良好3, 不可判1} 与报告原文总览句
优秀34/良好3/预警0/无数据1/测点异常1 逐项一致;大生科技 2026-03-11 → 38 台
{优秀29, 良好7, 预警1, 数据异常1}(与其正文"WTG02 未取到数据"一致);
消费端解析器(取 ## 附录 A 后 | WTG 行第 6 列)读到 38 台不缺台。
来源台账(outputs/rudong/_provenance.json): 改造前 17 raw-derived / 572 shipped;
本次摄入+转录后 1,740 / 571(m5_cms_tcm 由 0/90 变 1,718/90、windcms 由 0/56 变 2/54)。
逐件登记由 src/derived_manifest.py 承载(谁算的谁登记),products_restore_missing.py 读它;
已存在的窗若漏登记,用 python scripts/vib_raw_build.py --register-only 幂等补登记。
页面侧(http://127.0.0.1:28084/detail/v2#tab=system 的数据层表,接口 /detail/api/maint_survey):
两行位置已改为 <安装目录>\data\raw\如东\windcms\ 与 <安装目录>\data\raw\如东\m5_cms_tcm\。
★ 组件服务启动时会把这张表烘进缓存,改完 src/ontology/maintenance.py 必须重启组件才生效
(本次用运营台同一套脚本: _ops_stop_keep_gateway.py + _ops_start_and_open.py --no-open)。
其余闸门: 全库 183 个 py 在 -W error::SyntaxWarning 下编译 0 失败;本体审计 rc=0;
check_transferable.py 命中数 350 → 344(data\raw 已排除出文本扫描;我的产出 0 处,
manifest 里的源件路径已改为相对安装根)。
rudong_tcm_oem_scan.py / rudong_line_energy_share.py / rudong_model_run.py /
rudong_fusion_run.py(原在振动线分支 claude/vibration-data-diagnosis-32b69e)。
因此扫描线/能量占比/模型层/融合层那几类 parquet(oem_frequency_scan、gear_freq_scan、
blade_1p_*、model_run_l6、fusion_38.csv 等)仍走包内随包快照,不由 data\raw 重算;
连带的后果是 CMS 报告/页面不能重生成(§3b 实测 −97%)。vib_raw_manifest.json 的
missing_chain 字段如实列着这四项;缺口台账里对应 B5。handoff_vibration_v2.json / component_history.json 目前是随包快照:它们含大量人工裁决、
校准更新与开放项,不是能从测量数据直接算出来的东西 —— 现场给正本才改由现场件驱动。--meas ALL)会显著吃盘(含 Time_* 波形, 单点 65,536/200,000);
默认只转 FFT_ 谱(本轮 42 万条谱 = 3.2 GB)。pypdf 轮子并入 wheels\,让 vib_reports_build.py 能离线
逐件核验扫描件页数/有无文本层(本轮是靠临时装的 pypdf 抽检一件得出的结论,清单里记了这一点)。