Files
MapLibreParticleLab/docs/50_Step记录/STEP-054_真实WeatherV2风数据提取与Canonical测试数据生成_v1.md
2026-09-04 21:08:07 +08:00

5.1 KiB
Raw Blame History

STEP-054 真实 WeatherV2 风数据提取与 Canonical 测试数据生成

  • 状态:IMPLEMENTED / WAITING_NEXT_ANDROID_INTEGRATION_VALIDATION
  • Starting HEAD:5fc922785d8ec007127d48cd3ab5dadce270b947
  • 分支:particle/main
  • 目标:将 WeatherV2 ECMWF HRES 的真实 WVECBIN1 风场无损转换为已冻结的 maplibre-particle-field/v1 Android 测试 asset;不实现网络、Provider、React Native Binding 或 Android 综合绘制。

实际数据与格式依据

读取 WeatherV2 源目录:

/root/sourceserver/weatherV2/src/dev/_runtime/dev_pipeline_data/datasets/ecmwf-hres/wind/2026080600

按既定时次生成 T0~T3:2026080700、2026080706、2026080712、2026080718。四帧均实际存在,均为日本及周边的完整区域 grid:513×769、bounds 112.5, 0.0, 157.5, 55.77657301866769,单源文件 5,128,989 bytes。

WeatherV2 src/dev/core/bin_export.py 的 _export_vector_target() 先以 decode_wind() 从原 Windy wm_grid_257 tile 解码 U/V,再按 WVECBIN1 + uint32-le header length + JSON header + U float32-le plane + V float32-le plane + speed float32-le plane + valid uint8 plane 写入 wind_vectors.bin。数组 row-major;Web Mercator tile y 向南增加,因此 row 是 north-to-south、column 是 west-to-east。

src/dev/layers/wind.py 明确读取 decoded_r 为 U、decoded_g 为 V;writer metadata 说明 U eastward-positive、V northward-positive、screen y 使用 -v。QBIN exporter 和 NSFT exporter 都重新使用同一 decode_wind() Field:QBIN u_q/v_q 的 quantization metadata 明确为 m/s(scale=0.01),NSFT wind 也从该 Field 量化。因此本次原始 U/V 单位已由 writer/下游 decoder 确认为 m/s,没有 kt 换算、scale/offset 还原或额外量化。

wind_vectors.bin 是 WeatherV2 pipeline 对完整已拼接 U/V grid 的 particle/vector export;QBIN 是同源单 tile量化分发格式,NSFT 是同源单 tile量化 PMTiles 格式。三者共享 decoded U/V、valid 和 grid/bounds 语义,但本任务直接读取完整 WVECBIN1,不经 QBIN/NSFT 拼瓦片。

转换工具与输出

新增独立工具:

  • tools/weatherv2_wind_canonical/convert_weatherv2_wind.py
  • tools/weatherv2_wind_canonical/README.md

工具参数为 --run-dir、--valid-time、--output;源文件仅只读。它严格校验 magic、embedded header 与 sidecar 一致性、fields/dtype、长度、bounds 和有效 U/V,再输出既有 maplibre-particle-field/v1 metadata 与 float32-le interleaved-uv payload。输出 validTime 是真实 UTC epoch milliseconds;generation 和 dataVersion 同为 producer-owned epoch milliseconds,四帧严格递增。

输出目录:

platform/android/MapLibreAndroidTestApp/src/main/assets/integration/particle-weatherv2/ecmwf-hres-wind-20260807/

其中 dataset.json 只是开发期四帧索引,不是 Weather Manifest,也不进入 Snapshot。每个 validTime 子目录包含 metadata.json、field.f32、conversion_summary.json。

未重采样、未裁剪;每个 canonical payload 保留原完整 513×769 范围,3,155,976 bytes。有效 U/V 逐 float32 bit-exact 复制;source valid=0 或非有限 U/V 会映射为既有 noData=-9999 的 U/V pair,绝不写成 (0,0)。当前四个实际 frame 均为 394,497 valid、0 invalid,但转换器仍保留该 fail-closed mapping。

生成结果与验证

validTime SHA-256 U min/max (m/s) V min/max (m/s) speed min/max (m/s)
2026080700 363e2cd2e77501f6bceecbb4aaa68c4f9ef46998a60319ae5b7aba3548995283 -35.1724 / 22.5011 -25.4723 / 28.2009 0.0037 / 35.2783
2026080706 ef7a8e4b1c47f652f8f7012de16a87c16e3b25556a8f4686629f80514426c451 -37.1826 / 24.1255 -28.2276 / 25.0581 0.0105 / 37.7632
2026080712 d86a6a51fd5216cf9368756962a5366fd32a627afd40cfde235ba7358c02c5a0 -37.3931 / 24.7693 -28.2666 / 27.8099 0.0244 / 37.4291
2026080718 970785b0334a9d1511b8897874a81f681814a32b1e0b90e37cf64b77ca9fa39b -31.9560 / 28.5575 -26.1394 / 27.1316 0.0210 / 33.6781
  • 四帧 metadata 可解析、payload length 与 width×height×8 一致,validTime 严格递增,四个 SHA-256 均不同:PASS。
  • 每帧中心、四角附近和内部有效样本 source→canonical U/V 的最大绝对误差均为 0.0:PASS。
  • T0 重复转换的 SHA-256 与已生成 payload 相同:PASS。
  • 转换器 Python syntax、正常转换和无效 source 的非零失败路径:PASS。
  • 既有 Core canonical/Adapter/Host ingress 定向测试:5/5 PASS。

冻结边界与未执行项

未修改 ParticleFieldDescriptor、ParticleFieldSnapshot、ParticleFieldDataAdapter、Timeline、Playback、Runtime Field Window、Renderer、Android Kotlin/JNI 或 WeatherV2 原始数据。未将 Weather Service、HTTP、Provider、QBIN/NSFT 网络、缓存或目录扫描加入 MapLibre Runtime。

未执行 Android Gradle、APK、ADB、设备/模拟器测试或 Jest。下一阶段才使用本 asset 做 MapLibre map + WeatherColorLayer + RasterParticleLayer 综合 Android 验收;本 Step 不提前进入该范围。