# WeatherV2 QBIN V3 通用天气场二进制格式与 React 独立 Render Binding 设计 文档修订:v2.2 QBIN Container Version:3 Magic:`QBV3` 日期:2026-09-20 状态:设计冻结候选 / 可进入 Writer + C++ Decoder Prototype;正式发布前仍需冻结 Block Geometry、完成 Round-trip 与 Native 性能验证 适用范围:WeatherV2 → NavSea → MapLibreParticle 上一代权威基线:`WeatherV2_QBIN_V2通用天气场二进制格式与React独立Render_Binding设计_v4.4.md` 实施前补充依据:`WeatherV2 QBIN V3 实施前补充要求(给 Weather 生产方) v1.0` v2.2 相对 v2.1 的最终文档清理: ```text 1. 修正验收表对 non-finite physical sample 的表述: validity=1 时 physical MUST finite; validity=0 时 numeric physical value 不参与 Quantizer, 可为 NaN / Inf / missing。 2. 将 Corruption / Fail-closed 验收拆分为: Binary Reject Cases Binary Accept Cases Writer Validation Cases 避免把 MUST accept / Writer-only 行为误写成统一 fail-closed。 3. 不再新增任何 QBV3 Binary ABI 设计项。 除最终 BLOCK_WIDTH / BLOCK_HEIGHT 仍需 benchmark 后冻结外, v2.2 作为进入 Writer + Decoder Prototype 的最终设计冻结稿。 ``` v2.1 相对 v2.0 的最终收口重点: ```text 1. Rice canonicality 正式冻结为 Writer-canonical / Decoder-permissive: Writer MUST 计算并写入最优 k*; Decoder 只验证 riceK∈[0,31] 与 bitstream / symbolCount / padding / residual / raw range 等合法性,不为 canonicality 重算 32 个候选 k。 非最优但可合法解码的 riceK 不属于 QBV3 binary corruption。 2. WEB_MERCATOR + NODE 的数学定义补全: 直接冻结 dimensionless spherical Web Mercator X=λ,Y=ln(tan(π/4+φ/2)), 并给出 inverse 公式,消除“Mercator”实现歧义。 3. VALIDITY semantic 增加双向约束: semantic==3 ⇔ valueClass==VALIDITY ⇔ dtype==BITSET; semantic=3 不得被 Numeric Plane 复用。 4. Quantizer 增加 intermediate finite 要求: delta64 / normalized64 / normalizedDirection64 MUST finite; 否则 Writer FAIL。 5. fieldType=0 明确冻结为 UNKNOWN / UNSPECIFIED opaque hint, binary-valid,不得单独导致 reject。 6. 清理正文中遗留的 v1.9 / v2.0 临时字样,并连续整理后半部章节编号。 7. v2.1 之后,除最终 BLOCK_WIDTH / BLOCK_HEIGHT 仍需通过 16×16 / 32×32 C++ benchmark 实测选择外, 不再保留其他核心 QBV3 Binary ABI 未决语义。 ``` v2.0 相对 v1.9 的最终收口重点: ```text 1. Invalid-cell Writer 语义冻结: validity=1 的 physical sample MUST finite; validity=0 的 physical payload value 被忽略,可为 NaN/Inf/missing, 不参与 Quantizer、不产生 Rice symbol,decoded canonical raw 固定为 0。 Writer 不得通过 NaN/Inf 自动推导 validity=0。 2. ZigZag / inverse ZigZag 冻结为精确数学公式, 不再依赖“标准 ZigZag”约定或实现自行解释。 3. Quantizer binary64 计算语义收口: Descriptor binary32 scale/offset 先提升为 binary64; subtraction / division 使用 IEEE-754 binary64 round-to-nearest, ties-to-even 语义后,再执行 round_half_away_from_zero。 Direction Writer 要求 canonical input 已归一化到 [0,360), QBV3 Writer 不承担天气输入清洗。 4. unknown fieldType 的 Binary 行为冻结: fieldType 是 opaque uint16 hint; 未知值 MUST NOT solely cause binary rejection, 保证所有 conforming Decoder 对同一文件得到一致 Accept/Reject。 5. Numeric offset canonical zero 规则全局化: 任意 Numeric Plane 若 offset 数值等于 0, MUST 使用 binary32 +0.0;-0.0 MUST reject。 6. Validity BITSET 增加精确索引公式: byteIndex=index>>3, bitIndex=index&7, valid=(byte>>bitIndex)&1。 7. 修正文档遗留: §17 的 v1.8 字样统一为 v2.0; v2.0 之后,除 BLOCK_WIDTH/BLOCK_HEIGHT benchmark freeze 外, 不再保留其他核心 Binary ABI 未决语义。 ``` v1.9 相对 v1.8 的收口重点: ```text 1. round_half_away_from_zero 冻结为明确数学公式; Quantizer 使用 Descriptor 已确定的 binary32 scale/offset 提升到 binary64 计算, non-finite physical sample Writer MUST reject。 2. 补齐 Descriptor byte-level structural invariants 与必要机器值: valueClass / component / core unit / VALIDITY semantic 的 Container 约束集中定义。 3. referenceTimeUtc / validTimeUtc 只要求各自为正 Unix UTC seconds; QBV3 Container 不规定 validTimeUtc 与 referenceTimeUtc 的相对大小。 4. CRC32 参数完全展开: CRC-32/ISO-HDLC,poly=0x04C11DB7、reflected poly=0xEDB88320、 init=0xFFFFFFFF、refin/refout=true、xorout=0xFFFFFFFF。 5. Block partition 数学公式冻结; 最终只需在 16×16 / 32×32 benchmark 后回填 BLOCK_WIDTH / BLOCK_HEIGHT。 6. 当前 Parser conformance limits 继续作为 QBV3 Version 3 normative acceptance limits; 现阶段容量确认够用。未来如需扩大,不在已发布 Version 3 上静默放宽, 应通过后续 Container Version / successor spec 明确升级。 7. 将 ContentIdentity、QBV2 legacy validator、Manifest、Distribution、 Runtime/Binding 等非 Binary ABI 内容进一步移出 normative 主体, 只保留为 Non-normative Appendix。 8. v1.9 之后,Block Geometry 是正式发布前唯一尚未通过实测冻结的核心 Binary ABI 参数。 ``` v1.8 相对 v1.7 的收口重点: ```text 1. 明确 QBV3 binary-valid 与外部 Profile-valid 是两层: QbinV3Decoder 只负责 Container / byte-level validation; Profile Contract validation 属于 Encoded Field Ingress, 不属于 QBV3 Binary ABI,也不得被称为 binary corruption。 2. 在 normative 主体补全 DType byte-level enum: 1=INT16, 2=UINT16, 3=UINT8, 4=INT8, 5=FLOAT32, 6=BITSET; QBV3 Numeric 仅允许 1/2/3/4,Validity 固定 6,FLOAT32 在 V3 第一版 reject。 3. 补全 fieldType byte-level machine hint 语义与已知值; fieldType 不得决定 Plane layout / Profile completeness / Rice 解释。 4. 补全 WEB_MERCATOR + NODE Grid 的精确空间含义: Header bounds 为 WGS84 lon/lat degrees, Grid sample 在 Web Mercator projected space 等间距; row0=north,col0=west,index=row×width+col。 5. 冻结 QBV3 Parser conformance limits: MAX_PLANE_COUNT=32、 MAX_CELL_COUNT=2,097,152、 MAX_QBIN_BYTES=64 MiB、 MAX_DECODED_BYTES_PER_FRAME=32 MiB。 6. Header float64 Bounds 增加 canonical zero: 数值为 0 时 MUST serialize 为 IEEE-754 binary64 +0.0, 禁止 -0.0,保证 byte-for-byte deterministic Writer。 7. Block Geometry 仍是唯一尚未冻结的核心 Binary ABI 参数; v1.8 不擅自选择 16×16/32×32,正式 production QBV3/version=3 仍必须等 C++ benchmark 后回填唯一尺寸。 ``` v1.7 相对 v1.6 的收口重点: ```text 1. 文档规范范围重新收口到 QBIN V3 Binary Container 本身; NavSea / React / Store / Binding / Renderer / 平台 Bridge / Contract JSON 等消费与集成内容移出 normative 主体,仅保留为 Non-normative Integration Notes。 2. Quantization 冻结为“先序列化 float32,再用该 float32 值量化”: Descriptor 中 scale / offset 的 IEEE-754 binary32 bit-pattern 是 Quantizer 的唯一参数来源,禁止使用序列化前更高精度配置值直接量化。 3. Shared Validity 明确采用两阶段逻辑解析: 先解析全部 Descriptor 并定位唯一 Validity Plane, 再验证/读取 Validity,最后解 Numeric Rice Plane; 不要求 Validity 在 payload 中物理排在 Numeric Plane 前面。 4. Numeric Plane byteLength 精确定义为所有 non-empty block 的 `1-byte riceK + ceil(RiceSymbolBits/8)` 之和, 不包含 Plane 间 align16 padding、Descriptor 或其他 Plane。 5. Rice k 的 deterministic 选择公式正式冻结: `bits(k)=Σ((z_i>>k)+1+k)`,k∈[0,31]; 只按 Rice symbol bit count 比较,tie 选较小 k, 不把 1-byte riceK 与 byte-boundary padding 纳入优化目标。 6. QBV3 Header 的 FRAME 固定值直接写入本规范: layout=1、projection=1、sampleOrder=1、gridRegistration=1、 tileZ=0xffff、tileX=0、tileY=0; referenceTimeUtc / validTimeUtc 明确为正 int64 Unix UTC seconds。 7. Descriptor canonical float 增加 +0.0 规则: 语义要求 offset=0 时 MUST 写 binary32 +0.0 (0x00000000), Validity 固定 scale=+1.0、offset=+0.0,禁止 -0.0。 8. 第一阶段验收表同步收口为 Binary ABI / Writer / Parser / Round-trip / Codec Benchmark,不再把消费侧行为作为 QBV3 冻结条件。 ``` v1.6 相对 v1.5 的收口重点: ```text 1. Field Profile Contract Schema 升级方向明确: 为 required Plane 增加 expectedDType / expectedScaleBits / expectedOffsetBits, 使 wind/2、wave/2、rain/2、current/2 的量化参数由 Profile Contract data-driven 校验,而不是只依赖 Container 或 Generic Unit 验证。 2. MAX_DECODED_BYTES_PER_FRAME 口径补齐 Validity: decodedFrameBytes = decodedNumericBytes + decodedValidityBytes, validityPlane.storage / validityBits 同一 storage 只计一次。 3. Direction N 固定为 floor(ratioToN + 0.5),不依赖 host FPU rounding mode。 4. QBV2 frozen behavior 定义为 authoritative ingress acceptance 不变。 5. MAX_RETAINED_DECODED_BYTES 仅约束 EncodedFieldStore 当前 retained Frames 可达的 canonical decoded storage。 6. Validity ContentIdentity 冻结为与 Numeric Plane 相同的 hash algorithm / input order,并调用同一 identity helper。 ``` v1.5 相对 v1.4 的收口重点: ```text 1. QBV2 Direction legacy acceptance 精确对齐当前 C++: 保留 canonical=360/65536 与 4×float epsilon tolerance; QBV3 继续使用 canonical float32(360/N) bit-pattern,二者不互相放宽或收紧。 2. Plane ContentIdentity 进一步冻结当前 QBV2 的实际 hash 常数、 uint64 wrap 语义、逐 byte XOR→multiply 顺序与最终 hex 输出格式; 禁止“顺手修正”为标准 FNV-1a offset basis。 3. EncodedFieldIngress::decodeAndValidate() 升级为正式运行时唯一 authoritative decode + contract validation 入口;RasterArraySource::submitEncodedField() 不得继续直接调用 QbinV2Decoder。 4. MAX_RETAINED_DECODED_BYTES 明确为 V3 实施阶段新增 Store safety policy, 不是当前 v4.4 已存在行为;按唯一 retained storage 计数, shared_ptr alias / validityPlane.storage 与 validityBits 不重复计费。 5. 补齐 v1.3 revision history,并把当前版本引用统一更新为 v1.5。 ``` v1.4 相对 v1.3 的收口重点: ```text 1. Direction validation 分为 Container-specific + Generic 两层: QBV2 保留 legacy 360/65536° frozen acceptance; QBV3 使用 Generic Circular Contract,不反向放宽 V2。 2. Plane ContentIdentity 冻结为与当前 QBV2 完全相同的 hash algorithm、 input byte order 与 field order。 3. MAX_DECODED_BYTES_PER_FRAME 由 Decoder 在 allocation 前检查; MAX_RETAINED_DECODED_BYTES 由 EncodedFieldStore / owning Store layer 在接受 Frame 前检查。 4. all-invalid 下 zero-length Numeric Plane 的 canonical packing 明确允许 相邻 zero-length Plane / 下一 non-empty Plane 共享 byteOffset。 5. Direction canonical scale 的 float64→float32 转换固定为 IEEE-754 round-to-nearest, ties-to-even; 计算 N 前先验证 ratio finite 且处于允许范围。 ``` v1.3 相对 v1.2 的收口重点: ```text 1. 明确 FieldSeries::submit() 遇到不兼容 Frame 时返回 RejectedIncompatibleFrame;V2→V3 / schema 切换由上层 clear + rebuild, 不假设 Store 自动 replacement/reset。 2. Direction decode 除 UINT16 dtype range 外,额外要求 0 <= rawDirection < N;超出 Circular Contract 必须 fail-closed。 3. 修正 Rice bitstream 章节引用,并统一文档状态/版本号为 v1.3。 ``` v1.2 相对 v1.1 的收口重点: ```text 1. Direction scale 改为 canonical float32(360/N) bit-pattern 校验;固定 half-circle tie=-N/2,并给出整数 circular 参考公式。 2. Plane / Validity ContentIdentity 精确对齐当前 QBV2 C++ hash input;Grid identity 保持独立。 3. 不新增 FieldSeriesCompatibilityKey;继续以 DecodedFieldFrame::isInterpolationCompatibleWith() 的 canonical schema + grid 为权威。 4. 固定 Parser 顺序:结构+Budget → CRC → Validity → Rice decode。 5. 增加 dtype/circular logical residual 上界与 unary MAX_Q hardening。 6. Block Geometry 未冻结的实验文件禁止进入 production Manifest/CDN qbin_v3;V2/V3 benchmark 使用同一 CRC 实现。 ``` --- # 0. 与 QBIN V2 / v4.4 的关系 本文是 **QBIN V3 Container 的第一版设计文档修订版**。 上一代权威设计基线为: ```text WeatherV2_QBIN_V2通用天气场二进制格式与React独立Render_Binding设计_v4.4.md ``` 其中: ```text 文档设计版本:v4.4 QBIN Container Version:2 Magic:QBV2 ``` 本文中的 **QBIN V3** 是上述 QBIN V2 / v4.4 基线的直接后继版本。 ## 0.1 继承关系 QBIN V3 不重新设计 WeatherV2 → NavSea → MapLibreParticle 的整体架构。 除本文明确修改的 Container / Encoded Plane 编码规则外,QBIN V2 v4.4 已冻结的下列架构原则继续有效: ```text WeatherV2 负责 Provider 获取、物理语义归一化、Canonical Unit、 Quantization、QBIN Writer、Manifest 和协议数据。 NavSea / React 负责 Manifest / Registry / Field Profile Contract Resolve、 fieldKey、下载、缓存、预取、requestedForecastTime、 Color Binding 和 Particle Binding。 MapLibreParticle Encoded Field Ingress 负责 QBIN Parser / Decoder、CRC、Generic Field Profile Validator, 并输出格式无关的 DecodedFieldFrame / Plane Registry。 Runtime / Renderer 继续只处理通用 Scalar / Velocity / Direction / Validity, 不认识 Weather Provider、Manifest 或具体天气业务类型。 ``` 以下 v4.4 原则继续冻结: ```text Semantic Registry Unit Registry Field Profile Contract ResolvedFieldProfileContract Canonical Unit Value Class Component / groupId REQUIRED 完整性规则 Unknown Profile / Unknown Scalar Semantic 通用处理 Color Binding 与 Particle Binding 独立 Color Projection 与 Particle Projection 独立 Core-owned Forecast Clock / Playback 每个 fieldKey 独立 Runtime Field Window Native Core 自行解析 T0 / T1 / mix FrameContentIdentity generation / dataVersion 修订识别 Renderer 不增加: if WIND if WAVE if RAIN 等天气业务分支 ``` 因此: ```text QBIN V2 Decoder ↓ DecodedFieldFrame ↓ Runtime / Binding / Renderer ``` 升级为: ```text QBIN V3 Decoder ↓ DecodedFieldFrame ↓ Runtime / Binding / Renderer ``` **Decoder 之后的公共架构原则保持不变。** ## 0.2 V3 为什么需要新的 Container Version QBIN V2 将 Numeric Plane 定义为固定宽度的直接量化整数数组,例如: ```text INT16 → byteLength = count × 2 UINT16 → byteLength = count × 2 ``` Numeric Plane 的 `byteLength` 可以直接由: ```text count × dtype size ``` 推导。 QBIN V3 引入新的 Numeric Plane 编码: ```text Physical Value ↓ Quantization ↓ Integer Grid ↓ 2D Spatial Predictor ↓ Signed Residual ↓ ZigZag ↓ 固定 Block Geometry 的 adaptive Rice Coding ↓ Variable-length Encoded Plane ``` 因此 Numeric Plane 的编码长度不再等于: ```text count × dtype size ``` 而成为真正的: ```text variable-length encoded payload ``` 这改变了 QBIN V2 的二进制 Plane Contract,因此不能继续标记为 Container Version 2。 正式升级为: ```text QBIN Container Version:3 Magic:QBV3 Version:3 ``` ## 0.3 V3 不代表业务协议重做 Container Version 升级只表示: ```text Encoded Binary Representation ``` 发生不兼容变化。 它不意味着以下协议重新开始: ```text Semantic ID Unit ID Value Class Component groupId Field Profile Render Binding Forecast Runtime Renderer ``` 这些仍继承 v4.4 的长期通用设计。 因此: ```text Container Version ``` 和: ```text Field Profile Version ``` 必须继续独立管理。 第一阶段建议: ```text QBIN V3 wind / 2 wave / 2 rain / 2 current / 2 ``` 表示: ```text Container 使用 QBIN V3 + 各天气 Field 使用自己的 Profile Version ``` 而不是把天气业务规则硬编码进 Container Version。 ## 0.4 v4.4 文档的历史地位 `WeatherV2_QBIN_V2通用天气场二进制格式与React独立Render_Binding设计_v4.4.md` 从 QBIN V3 生效后仍永久保留,作为: ```text QBIN V2 最终冻结规范 QBIN V3 架构来源基线 旧 QBV2 文件解释依据 V2/V3 兼容与迁移依据 ``` 不得覆盖、改名或修改其已经冻结的历史定义。 本文只定义: ```text QBIN V3 ``` 以后对 V3 的小幅修订使用本文自身的: ```text Document Revision ``` 管理,例如: ```text v1.0 v1.1 v1.2 ``` 不得再用文档修订号代替 Container Version。 因此版本体系统一为: ```text QBIN V2 └── 最终设计基线:v4.4 QBIN V3 └── 本文初始设计版本:v1.0 ``` ## 0.5 本文的 Normative Scope 从 v1.7 开始,本文的 normative 主体只定义: ```text QBV3 Header Plane Descriptor Endian / canonical float Quantization Shared Validity 2D Predictor Direction Circular Predictor ZigZag Rice Block / bitstream Numeric Plane byteLength Plane Packing / Alignment CRC32 Parser Safety / Fail-closed Deterministic Writer Golden Binary / bit-exact Round-trip Codec encode/decode benchmark ``` 下列内容**不属于 QBV3 Binary ABI**: ```text NavSea 如何选择 / 下载 / 缓存 QBV3 React / RN API Profile Contract JSON 的 wire schema EncodedFieldStore / FieldSeries T0 / T1 / mix Binding / Projection / Renderer Android / iOS Bridge transport Store retained-memory policy 业务层 V2→V3 切换流程 ``` 这些内容只可作为 Non-normative Integration Notes 保存,不能反向改变同一个: ```text magic = QBV3 version = 3 ``` 的文件解释。 目标是: > Weather 生产方只阅读本文 normative 主体,就能生成 byte-for-byte deterministic、跨平台可解码、可严格校验的 QBV3 文件;消费方实现细节不属于 Container 语义。 --- # 1. V3 设计目标 QBIN V3 的核心目标只有一个: > **在保持 v4.4 通用天气场架构不变的前提下,大幅降低每个时间 Frame 的网络与缓存体积,并保持 Native 解码简单、确定、可校验。** 设计目标: ```text 1. 一个 targetTime 仍对应一个独立 Frame 文件。 2. 不把多个时间点打成一个大归档。 3. NavSea 可只下载当前 T0/T1 和必要预取 Frame。 4. 数值误差只来自明确的 Quantization Profile。 5. Predictor / ZigZag / Rice 全部可逆,不增加额外物理误差。 6. Decoder 之后仍输出既有 DecodedFieldFrame / Plane Registry。 7. Runtime / Renderer 不感知 QBIN V2/V3 差异。 8. Wind / Wave / Rain / Current 共用同一 Container 与编码方法。 9. 不为每种天气增加独立二进制格式。 10. Writer 必须 deterministic;相同输入与同一 Profile 产生 byte-for-byte 相同文件。 ``` --- # 2. 不在 V3 中解决的问题 V3 不负责: ```text 颜色表 粒子颜色 粒子数量 Trail UI Provider 网络请求 Route / ETA 业务 Forecast 下载调度 缓存淘汰策略 ``` V3 也不改变: ```text ColorBinding / ParticleBinding Core Forecast Clock FieldSeries T0 / T1 / mix GPU Renderer ``` --- # 3. 最终数据链 ```text Provider ↓ WeatherV2 Normalizer ↓ Server Canonical Field ↓ Unified Quantizer / Field Profile ↓ QBIN V3 Writer ↓ 2D Predictor ↓ ZigZag ↓ 固定 Block Geometry 的 adaptive Rice ↓ QBV3 Frame ↓ HTTP Distribution Encoding(可 gzip) ↓ NavSea Download / Cache ↓ MapLibreParticle Encoded Field Ingress ↓ QbinV3Decoder ↓ DecodedFieldFrame / Plane Registry ↓ EncodedFieldStore / FieldSeries ↓ Binding Resolver ├── Color Projection └── Particle Projection ↓ Core-owned Forecast Clock / Runtime Field Window ↓ WeatherColorLayer / RasterParticleLayer ``` QBIN V2 与 V3 的分界只允许存在于 Encoded Field Ingress: ```text QBV2 → QbinV2Decoder ┐ ├→ DecodedFieldFrame QBV3 → QbinV3Decoder ┘ ``` 不得把 V3 编码细节泄漏到 Runtime/Renderer。 --- # 4. 文件总体结构 V3 第一版继续采用简单固定结构: ```text ┌──────────────────────────────┐ │ Fixed Header │ 112 bytes ├──────────────────────────────┤ │ Plane Descriptor Table │ 32 bytes × planeCount ├──────────────────────────────┤ │ Payload │ variable └──────────────────────────────┘ ``` 继续不保存: ```text headerSize descriptorSize descriptorOffset payloadOffset totalLength ``` 固定: ```text HEADER_SIZE = 112 DESCRIPTOR_SIZE = 32 descriptorOffset = 112 payloadOffset = 112 + planeCount × 32 expectedTotalLength = payloadOffset + payloadLength ``` V3 第一版不利用 Header/Descriptor 的 reserved 字段承载新业务信息。 所有 reserved 字段仍必须: ```text 0 ``` 这样保留二进制结构的简单性。 --- # 5. Magic / Version / Endian ```text magic = ASCII "QBV3" version = 3 ``` 未知 Version: ```text fail-closed ``` 所有 multi-byte integer 与 IEEE-754 floating point: ```text Little Endian ``` Rice bitstream 的 bit order 由本文第 18 节单独定义,不使用 host-native bitfield。 ## 5.1 QBV3 第一版 FRAME 固定 Header ABI QBV3 第一版只定义: ```text layout = FRAME ``` 对应 Header 固定值: ```text layout = 1 projection = 1 # WEB_MERCATOR sampleOrder = 1 # NORTH_TO_SOUTH_WEST_TO_EAST gridRegistration = 1 # NODE tileZ = 0xffff tileX = 0 tileY = 0 ``` 以下时间字段: ```text referenceTimeUtc validTimeUtc ``` 固定为: ```text int64 Unix UTC seconds MUST > 0 ``` 不得在 Header 中直接写毫秒。 QBV3 Container **不规定**二者的相对大小: ```text 不得在 Binary Parser 中强制: validTimeUtc >= referenceTimeUtc ``` 以下情况都可以由外部 Profile / Dataset 语义决定: ```text Forecast Analysis Observation Reanalysis / Hindcast ``` 因此 Binary-valid 只要求两个时间字段各自满足格式与范围要求, 不因 `validTimeUtc < referenceTimeUtc` 自动判定 corruption。 Bounds: ```text west / south / east / north ``` 必须是 finite `float64`,第一版 WEB_MERCATOR FRAME 至少满足: ```text -180 <= west < east <= 180 -85.0511287798066 <= south < north <= 85.0511287798066 ``` 未知 layout / projection / sampleOrder / gridRegistration: ```text fail-closed ``` 这些值直接属于 QBV3 Container ABI,不要求 Writer 通过查阅 QBIN V2 文档才能生成合法 Header。 ## 5.2 WEB_MERCATOR + NODE Grid 的精确空间语义 Header: ```text west / south / east / north ``` 是: ```text WGS84 longitude / latitude degrees ``` 但 Grid node 在南北方向的等间距不是按 latitude degree 线性插值, 而是在 Web Mercator projected space 中等间距。 定义数学上的 dimensionless spherical Web Mercator: ```text λ = longitudeDeg × π / 180 φ = latitudeDeg × π / 180 mercatorX(longitudeDeg) = λ mercatorY(latitudeDeg) = ln( tan( π/4 + φ/2 ) ) ``` 其 inverse: ```text longitudeDeg = X × 180 / π latitudeDeg = ( 2 × atan(exp(Y)) - π/2 ) × 180 / π ``` 由于 Header 已限制: ```text -85.0511287798066 <= latitude <= 85.0511287798066 ``` 正文不再额外定义 latitude clamp。 若某实现使用 EPSG:3857 meter coordinate: ```text X_meter = 6378137 × X Y_meter = 6378137 × Y ``` 其 Grid node 位置与本文 dimensionless 公式完全等价; 规范语义以本文 dimensionless 公式为准。 实现用于 Grid sample 定位时应采用 IEEE-754 binary64 计算。 因此: ```text xWest = mercatorX(west) xEast = mercatorX(east) yNorth = mercatorY(north) ySouth = mercatorY(south) ``` 对于 NODE grid: ```text dx = (xEast - xWest) / (width - 1) dy = (yNorth - ySouth) / (height - 1) ``` 逻辑 sample `(row, col)`: ```text x = xWest + col * dx y = yNorth - row * dy ``` 因此: ```text row = 0 → north edge row = height - 1 → south edge col = 0 → west edge col = width - 1 → east edge ``` flattened cell index: ```text index = row * width + col ``` sample order: ```text NORTH_TO_SOUTH_WEST_TO_EAST ``` 等价于: ```text row-major 每一 row 内 west → east rows north → south ``` Writer / Decoder / Golden Fixture 不得把 `south..north` latitude degree 直接做线性 sample spacing 来替代上述 Web Mercator projected-space 语义。 --- # 6. Fixed Header V3 第一版继续沿用 v4.4 的 112-byte Header 字段位置,只修改 Magic / Version: | Offset | Size | Type | Field | |---:|---:|---|---| | 0 | 4 | char[4] | magic=`QBV3` | | 4 | 1 | uint8 | version=3 | | 5 | 1 | uint8 | layout | | 6 | 2 | uint16 | fieldType | | 8 | 1 | uint8 | projection | | 9 | 1 | uint8 | sampleOrder | | 10 | 1 | uint8 | gridRegistration | | 11 | 1 | uint8 | reserved0=0 | | 12 | 2 | uint16 | planeCount | | 14 | 2 | uint16 | reserved1=0 | | 16 | 4 | uint32 | width | | 20 | 4 | uint32 | height | | 24 | 8 | int64 | referenceTimeUtc | | 32 | 8 | int64 | validTimeUtc | | 40 | 8 | float64 | west | | 48 | 8 | float64 | south | | 56 | 8 | float64 | east | | 64 | 8 | float64 | north | | 72 | 4 | uint32 | payloadLength | | 76 | 4 | uint32 | fileCrc32 | | 80 | 2 | uint16 | tileZ | | 82 | 2 | uint16 | reserved2=0 | | 84 | 4 | uint32 | tileX | | 88 | 4 | uint32 | tileY | | 92 | 4 | uint32 | reserved3=0 | | 96 | 4 | uint32 | reserved4=0 | | 100 | 4 | uint32 | reserved5=0 | | 104 | 4 | uint32 | reserved6=0 | | 108 | 4 | uint32 | reserved7=0 | 时间、Bounds、Projection、Sample Order、Grid Registration 的语义继续继承 v4.4。 ## 6.1 fieldType:Machine Hint,不是 Layout Authority `fieldType` 是 `uint16` machine-readable hint,沿用上一代已知值: ```text 1 = WIND 2 = WAVE 3 = CURRENT 4 = RAIN 5 = AIR_TEMPERATURE 6 = SEA_TEMPERATURE 7 = AIR_PRESSURE 8 = HUMIDITY 9 = VISIBILITY ``` 未知 `fieldType`: ```text MUST NOT solely cause binary rejection ``` 只要 Header / Descriptor / Plane / CRC 等其他 QBV3 Binary Contract 全部合法, Generic QBV3 Parser 必须继续按 binary-valid 处理。 也就是说 `fieldType` 是: ```text opaque uint16 machine hint ``` 已知值具有当前约定含义,未知值仍保持 forward-compatible hint 语义。 特别冻结: ```text fieldType = 0 = UNKNOWN / UNSPECIFIED = binary-valid opaque hint ``` `fieldType=0` 或其他未知 `uint16` 值都不得单独导致 Binary reject。 `fieldType` MUST NOT 决定: ```text Plane count Plane semantic set dtype scale / offset REQUIRED completeness Rice block interpretation Profile compatibility Renderer behavior ``` 因此: ```text fieldType == WIND ``` 不能替代外部: ```text fieldProfileId = wind fieldProfileVersion = 2 ``` 也不能使 Parser 自动要求 U/V Plane。 `fieldType` 与具体 Profile 是否一致属于外部 Profile / Product validation, 不属于 QBV3 binary corruption。 ## 6.2 Header Bounds 的 Canonical Float64 Zero `west / south / east / north` 使用 IEEE-754 binary64 little-endian。 为了 deterministic Writer: ```text 如果任一 bound 的数学值 == 0: MUST serialize as +0.0 binary64 bit-pattern: 0x0000000000000000 ``` 禁止: ```text -0.0 bit-pattern = 0x8000000000000000 ``` 其他有限非零值按其 canonical binary64 value 写入。 --- # 7. Plane Descriptor V3 第一版继续保持每个 Descriptor 32 bytes: | Offset | Size | Type | Field | |---:|---:|---|---| | 0 | 2 | uint16 | semantic | | 2 | 1 | uint8 | dtype | | 3 | 1 | uint8 | flags | | 4 | 4 | float32 | scale | | 8 | 4 | float32 | offset | | 12 | 4 | uint32 | count | | 16 | 4 | uint32 | byteOffset | | 20 | 4 | uint32 | byteLength | | 24 | 2 | uint16 | unit | | 26 | 2 | uint16 | groupId | | 28 | 1 | uint8 | valueClass | | 29 | 1 | uint8 | component | | 30 | 2 | uint16 | reserved=0 | ## 7.1 DType Byte-level Enum QBV3 `dtype` 是 `uint8`,byte-level 值冻结为: ```text 1 = INT16 2 = UINT16 3 = UINT8 4 = INT8 5 = FLOAT32 6 = BITSET ``` QBV3 Version 3 第一版合法组合: ```text Numeric Plane: dtype ∈ {INT16, UINT16, UINT8, INT8} 即 byte value ∈ {1,2,3,4} Validity Plane: dtype = BITSET 即 byte value = 6 ``` 以下在 QBV3 Version 3 第一版必须 reject: ```text Numeric dtype = FLOAT32 (5) Numeric dtype = BITSET (6) Validity dtype != BITSET (6) unknown dtype ``` `FLOAT32=5` 的 enum 值保留是为了保持跨代 registry / decoded type 一致性, 但它不代表 QBV3 Version 3 第一版允许 FLOAT32 Rice Plane。 V3 与 V2 的关键区别: ### Numeric Plane `dtype` 表示 **解码后的逻辑 Quantized Integer 类型**,不是 Payload 的固定宽度存储长度。 ```text count = width × height byteLength = 该 Plane 的实际 Rice encoded byte 数 ``` 因此 V3 Numeric Plane 不再要求: ```text byteLength == count × dtypeSize ``` ### Validity Plane 第一版仍保持直接 BITSET: ```text dtype = BITSET count = width × height byteLength = ceil(count / 8) ``` ## 7.2 Descriptor Canonical Float Representation Descriptor 中: ```text scale offset ``` 都是 IEEE-754 binary32 little-endian。 QBV3 deterministic Writer 必须使用 canonical binary32 representation。 特别冻结: ```text 如果某语义要求 offset == 0: offset MUST = +0.0f bit-pattern = 0x00000000 不得写: -0.0f bit-pattern = 0x80000000 ``` Validity Plane 固定: ```text scale = +1.0f bit-pattern = 0x3f800000 offset = +0.0f bit-pattern = 0x00000000 ``` 对于所有 Numeric Plane: ```text scale MUST finite scale > 0 offset MUST finite ``` 并冻结全局 canonical zero: ```text if offset == 0.0 numerically: bit-pattern MUST = +0.0f 0x00000000 -0.0f 0x80000000 → MUST reject ``` 该规则不依赖外部 Profile 是否显式声明“offset=0”。 该规则属于 binary canonicalization,目的包括: ```text byte-for-byte deterministic Writer CRC 稳定 Content Identity 稳定 跨语言 / 跨平台一致 ``` --- ## 7.3 Descriptor Byte-level Structural Invariants 为了让 QBV3 Binary Parser 不依赖外部 Profile 名称, 以下机器值与通用结构约束直接属于 Container Version 3。 ### Value Class ```text 0 = SCALAR 1 = VELOCITY_COMPONENT 2 = DIRECTION_ANGLE 3 = VALIDITY ``` 未知 `valueClass`: ```text MUST reject ``` ### Component ```text 0 = NONE 1 = U_EAST 2 = V_NORTH 3 = W_UP ``` 未知 `component`: ```text MUST reject ``` ### Core Unit IDs QBV3 第一版直接使用: ```text 0 = NONE 1 = MPS 4 = DEGREE ``` Scalar 的其他 unit ID 可以由外部 Unit Registry 定义; Binary Parser 不因为“不认识某个 Scalar unit ID”而自动判定 corruption。 ### Core Semantic Shared Validity 的 frozen core semantic: ```text VALIDITY semantic = 3 ``` 并冻结双向约束: ```text semantic == 3 ⇔ valueClass == VALIDITY ⇔ dtype == BITSET ``` 因此: ```text semantic = 3 + SCALAR / VELOCITY_COMPONENT / DIRECTION_ANGLE → MUST reject valueClass = VALIDITY + semantic != 3 → MUST reject dtype = BITSET + valueClass != VALIDITY → MUST reject ``` 一个合法 QBV3 Frame 仍必须有且只有一个满足上述关系的 Shared Validity Plane。 Numeric semantic: ```text semantic = 0 → reserved / invalid ``` 除 `semantic=3` 已被冻结为 VALIDITY 外, 其他 Numeric semantic ID 的业务含义由外部 Semantic Registry 决定。 ### 通用组合约束 ```text SCALAR: dtype ∈ {INT16, UINT16, UINT8, INT8} component = NONE VELOCITY_COMPONENT: dtype ∈ {INT16, UINT16, UINT8, INT8} unit = MPS component ∈ {U_EAST, V_NORTH, W_UP} groupId != 0 DIRECTION_ANGLE: dtype = UINT16 unit = DEGREE component = NONE groupId = 0 offset = canonical +0.0f scale obeys 第 15 节 Circular Contract VALIDITY: semantic = 3 dtype = BITSET unit = NONE groupId = 0 component = NONE flags.REQUIRED = 1 scale = canonical +1.0f offset = canonical +0.0f ``` 一个 Frame: ```text MUST 有且只有一个 VALIDITY Plane ``` Binary Parser **不负责**验证: ```text 某天气 Profile 是否需要 U/V 成对 某 Scalar semantic 是否 REQUIRED 某 Field Profile 是否允许 additional Plane ``` 这些属于外部 Profile Contract,而不是 QBV3 corruption。 # 8. Value Class / Semantic / Unit / groupId QBV3 Binary Parser 使用第 7.3 节冻结的: ```text valueClass component core unit VALIDITY semantic ``` 作为 byte-level structural contract。 外部 Semantic Registry / Unit Registry 可以为: ```text Scalar semantic Scalar unit 未来扩展语义 ``` 赋予更具体含义,但不得改变 `QBV3/version=3` 已冻结的 byte-level 解释。 `groupId` 的 Container 级基本规则: ```text VELOCITY_COMPONENT → groupId != 0 DIRECTION_ANGLE → groupId = 0 VALIDITY → groupId = 0 ``` SCALAR 的 `groupId` 是否具有额外业务含义由外部 Profile 决定。 V3 不因为编码变化增加: ```text if WIND if WAVE if RAIN if CURRENT ``` 等天气业务分支。 # 9. REQUIRED Flag 与 Binary-valid / Profile-valid 分层 Descriptor `flags`: ```text bit0 = REQUIRED bit1..7 = reserved ``` 在 QBV3 Binary Container 层,Parser 只验证: ```text flags 的 reserved bits == 0 Descriptor 本身 structurally valid Plane bytes / semantic / dtype / validity / packing 等满足本文 Binary Contract ``` QBV3 Binary Container **不根据天气 Profile 名称决定 required Plane 集合**。 因此必须区分: ```text Binary-valid ``` 和: ```text Profile-valid ``` ## 9.1 Binary-valid 只由: ```text QbinV3Decoder ``` 根据本文 normative Binary Contract 判断。 一个 QBV3 文件即使缺少某个产品 Profile 所需 Plane, 只要文件自身 Header / Descriptor / Payload / CRC / Validity / Rice 等合法, 仍可以是: ```text binary-valid ``` ## 9.2 Profile-valid 具体: ```text wind / 2 wave / 2 rain / 2 current / 2 ``` 要求哪些 Plane、dtype、scale、offset、unit、group/component, 属于外部 Profile Contract / Registry。 例如一个 binary-valid 文件: ```text VECTOR_U VALIDITY ``` 拿 `wind / 2` Contract 验证时因为缺失 `VECTOR_V`: ```text Profile validation → reject ``` 但不能称为: ```text QBV3 corruption ``` ## 9.3 REQUIRED flag 的职责 Descriptor REQUIRED flag 是: ```text 文件内 requirement declaration / mirror ``` 外部 Profile Contract 可以要求: ```text required Plane 必须存在 对应 Descriptor REQUIRED bit 必须一致 ``` 这种一致性属于: ```text Encoded Field Ingress / Profile Contract Validation ``` 而不是 QBV3 binary parser 对天气业务完整性的判断。 不得在 `QbinV3Decoder` 内写: ```text if fieldType == WIND: require U require V ``` 也不得让 Binary Decoder 依赖: ```text NavSea React Contract JSON fieldProfileId fieldProfileVersion ``` ## 9.4 QBV3 Quantization Contract 的边界 QBV3 Binary Container 自身承载: ```text dtype scale offset ``` Parser 必须验证它们满足本文通用 Binary Contract: ```text dtype 合法 scale / offset finite canonical float / +0.0 Direction Circular Contract Validity fixed descriptor ``` 具体 Profile 是否要求: ```text INT16 scale = 0.1 offset = +0.0 ``` 由外部 Profile Contract 决定。 因此: > 同一个合法 QBV3 的 byte-level 解释不能依赖 Profile 名称或外部 Contract。 # 10. Quantization 与编码必须分离 V3 强制区分: ```text Physical Quantization ``` 和: ```text Binary Entropy Coding ``` 物理误差只允许来自 Quantization: ```text physical → quantized integer ``` 以下步骤必须完全可逆: ```text 2D Predictor ZigZag Rice ``` 因此: ```text V3 decode 后的 quantized integer MUST byte/number-exact 等于 Writer Quantizer 的输出整数 ``` 不得在 Rice/Predictor 阶段引入第二次近似。 --- # 11. Generic Numeric Quantization 普通非循环 Numeric Plane: ```text physical = raw × scale + offset ``` ## 11.1 Quantizer 参数以 Descriptor binary32 为唯一来源 Writer 必须先确定最终要写入 Descriptor 的: ```text scaleBits : IEEE-754 binary32 offsetBits : IEEE-754 binary32 ``` 然后: ```text scaleF32 = binary32_from_bits(scaleBits) offsetF32 = binary32_from_bits(offsetBits) ``` 实际 Quantizer 计算必须使用**已经序列化确定的 binary32 值**,必要时提升为 binary64: ```text scaleQ = double(scaleF32) offsetQ = double(offsetF32) normalized = (physical - offsetQ) / scaleQ raw = round_half_away_from_zero(normalized) ``` 禁止: ```text 用配置文件中的 decimal 原值 用序列化前更高精度的 double scale / offset 量化完成后再把 scale / offset 截成 float32 ``` 原因: > QBV3 的 Quantization 参数必须与文件 Descriptor 中实际携带的 bit-pattern 完全一致。 在“相同 canonical physical input + 相同 Descriptor bit-pattern”的前提下,Writer 必须产生相同 quantized integer。 普通 Writer: ```text normalized = (physical - offsetQ) / scaleQ raw = round_half_away_from_zero(normalized) ``` Validity 必须在 Numeric Quantizer 之前已经确定。 对每个 cell: ```text if validity[index] == 1: physical MUST be finite IEEE-754 binary64 执行 Numeric / Direction Quantization if validity[index] == 0: physical value is ignored MAY be NaN / +Infinity / -Infinity / missing MUST NOT 进入 Quantizer MUST NOT 产生 Rice symbol decoded canonical raw MUST = 0 ``` 禁止: ```text 通过 physical 是 NaN / Inf 自动推导 validity = 0 ``` Validity 是独立、权威的 Shared Validity Domain; non-finite numeric payload 不能替代 Validity BITSET。 `round_half_away_from_zero(x)` 的数学定义冻结为: ```text if x >= 0: result = floor(x + 0.5) else: result = ceil(x - 0.5) ``` Quantizer 的规范计算域: ```text physical : IEEE-754 binary64 scaleQ : exact binary64(double(scaleF32)) offsetQ : exact binary64(double(offsetF32)) ``` 规范计算步骤: ```text delta64 = roundTiesToEven_binary64( physical - offsetQ ) normalized64 = roundTiesToEven_binary64( delta64 / scaleQ ) delta64 MUST finite normalized64 MUST finite 如果任一 intermediate 为: ```text NaN +Infinity -Infinity ``` Writer MUST FAIL。 raw = round_half_away_from_zero(normalized64) ``` 这里的: ```text roundTiesToEven_binary64 ``` 表示 IEEE-754 binary64 round-to-nearest, ties-to-even。 Writer 必须得到与上述步骤相同的 binary64 结果,不得依赖: ```text host locale decimal string formatting host default integer cast rounding FPU 当前 rounding mode excess precision / extended register precision ``` 来决定最终 raw integer。 超出逻辑 dtype: ```text Writer FAIL ``` 禁止: ```text silent clamp integer wrap 隐式 modulo ``` Invalid Cell 不进入 Numeric Rice symbol stream;Decoder materialize 时其 raw 值必须恢复为 0。 --- # 12. V3 第一版支持的 Numeric dtype 第一版编码支持: ```text INT16 UINT16 INT8 UINT8 ``` 所有上述 dtype 在进入 Predictor 前转换到至少 `int32` 运算域。 Predictor residual: ```text int32 ``` ZigZag 输出: ```text uint32 ``` `FLOAT32` 不进入 V3 第一版 Rice Numeric Plane。 需要 FLOAT32 的 Field: ```text 继续使用其他已支持 Container 或未来明确扩展 V3 codec contract ``` 不得私自把 FLOAT32 bytes 当整数 Rice 编码。 --- # 13. Shared Validity V3 第一版继续保留 v4.4 的单 Frame Shared Validity Domain: ```text semantic = VALIDITY valueClass = VALIDITY dtype = BITSET unit = NONE groupId = 0 component = NONE flags = REQUIRED ``` BITSET: ```text LSB first byteLength = ceil(count / 8) ``` 最后 byte 未使用 high bits: ```text MUST = 0 ``` Validity bit 与 flattened cell index 的对应关系冻结为: ```text index = row * width + col byteIndex = index >> 3 bitIndex = index & 7 valid = (validityBytes[byteIndex] >> bitIndex) & 1 ``` 因此每个 byte 内: ```text bit 0 → 较小 index bit 7 → 较大 index ``` 即明确的 LSB-first。 一个 Frame 内: ```text 所有 Numeric Plane MUST 共享完全相同 validity domain ``` 不同 validity domain 的数据继续拆成不同 Field/QBIN。 V3 第一版**不增加**: ```text ALL_VALID special payload ALL_INVALID special payload RLE validity per-plane validity per-group validity ``` 原因:保持 Container 简单统一。 Distribution 层 gzip 可以自然压缩全 1 或高度重复的 BITSET。 ## 13.1 Validity 的逻辑解析顺序 Descriptor Table 仍按本文 canonical descriptor order 排序,Payload 仍按 Descriptor 顺序打包。 QBV3 **不要求** Validity Plane 在物理 Payload 中排在 Numeric Plane 前面。 Decoder 必须采用两阶段逻辑解析: ```text 1. 解析全部 Header / Descriptor 2. 定位唯一 Shared Validity Plane 3. 完成 CRC / padding / Validity BITSET 校验 4. 读取完整 Validity BITSET 5. 计算每个 Rice block 的 valid symbolCount 6. 再解各 Numeric Plane ``` 因此: ```text 逻辑上 Validity 必须先可用 != 物理上 Validity 必须排在最前 ``` 不得为了 Rice 解码方便而改变 Descriptor canonical order 或 Plane packing order。 --- # 14. 2D Spatial Predictor V3 第一版所有 Numeric Plane 使用同一个二维 predictor。 预测在**整个 Grid 的全局坐标**上进行,不因 Rice block 边界 reset。 对当前 cell `(r,c)`: ```text L = (r, c-1) U = (r-1, c) UL = (r-1, c-1) ``` 预测规则: ```text 如果 current valid 且 L/U/UL 全部 valid: predicted = raw(L) + raw(U) - raw(UL) 否则如果 current valid 且 L valid: predicted = raw(L) 否则如果 current valid 且 U valid: predicted = raw(U) 否则: predicted = 0 ``` 普通 Numeric residual: ```text residual = raw(current) - predicted ``` 所有中间计算至少使用: ```text int32 ``` 不得用 int16 中间运算导致 overflow。 Invalid cell: ```text 不产生 Rice symbol Decoder materialize raw = 0 ``` --- # 15. Direction Circular Quantization / Predictor `DIRECTION_ANGLE` 继续使用 v4.4 的物理约定: ```text DIRECTION_TO 0° True North 90° East 180° South 270° West clockwise positive [0°, 360°) ``` QBIN V3 不再把 `360 / 65536°` 作为唯一合法 Direction scale。 Direction quantization 正式升级为**通用 Circular Contract**。 Descriptor 基本约束: ```text valueClass = DIRECTION_ANGLE dtype = UINT16 unit = DEGREE component = NONE offset = 0 scale > 0 scale finite ``` ## 15.0 QBV3 Direction Validation Scope 本节只定义: ```text QBV3 / version=3 ``` 自身的 Direction Circular Contract。 QBV3 Parser 对 `DIRECTION_ANGLE` 必须验证: ```text dtype = UINT16 unit = DEGREE component = NONE groupId = 0 offset = canonical +0.0f scale = canonical float32(360/N) rawDirection ∈ [0,N) ``` QBV2 的 legacy acceptance、共享 Validator 如何重构等兼容实现问题: ```text 不属于 QBV3 Binary ABI ``` 移至 Appendix A。 ## 15.1 Canonical Direction Scale Direction scale 不使用实现方自行决定的 epsilon / tolerance。 协议直接冻结 canonical float32 计算规则。 Reader / Writer 均定义: ```text scaleF32 = Descriptor 中 scale 的 IEEE-754 float32 值 ratioToN = 360.0 / double(scaleF32) ``` 在把 `ratioToN` 转为整数前必须先验证: ```text ratioToN finite 1 <= ratioToN <= 65536 ``` 然后固定: ```text N = floor(ratioToN + 0.5) ``` 由于 `ratioToN > 0`,该规则等价于正数域的 `round_half_away_from_zero`,不依赖 host FPU rounding mode。 必须满足: ```text 1 <= N <= 65536 ratio64 = 360.0 / double(N) ratio64 finite canonicalScaleF32 = IEEE-754 binary32( ratio64, round-to-nearest, ties-to-even ) bit_pattern(scaleF32) == bit_pattern(canonicalScaleF32) ``` 即:Descriptor 中的 `scale` 必须是 `360/N` 转为 IEEE-754 float32 后的**唯一 canonical bit pattern**。 不得接受“足够接近”的任意浮点值。 因此不再需要 `DIRECTION_SCALE_TOLERANCE`。 逻辑 raw 范围: ```text rawDirection ∈ [0, N) ``` 合法 Profile 示例: ```text N = 65536 → scale = float32(360/65536)° N = 360 → scale = 1° N = 720 → scale = 0.5° ``` QBV3 Writer 的 Direction input 必须在进入 Writer 前已经是 canonical: ```text physicalDirection finite 0 <= physicalDirection < 360 DIRECTION_TO clockwise positive True North = 0° ``` QBV3 Writer 不负责: ```text FROM → TO 转换 任意角度 wrap 天气 Provider 方向约定修正 ``` 这些属于上游 Normalizer。 Writer 使用: ```text scaleQ = double(scaleF32) normalizedDirection64 = roundTiesToEven_binary64( physicalDirection / scaleQ ) normalizedDirection64 MUST finite 否则 Writer MUST FAIL。 rawDirection = round_half_away_from_zero(normalizedDirection64) mod N ``` 其中 `mod N` 只用于处理接近 360° 边界时量化得到 `N` 的合法 wrap, 输入 physicalDirection 本身仍必须位于 `[0,360)`。 QBV3 Binary Parser 只验证上述通用 Circular Contract,禁止: ```text if profile == wave: allow 1 degree ``` 合法性来自 `scale → N → canonical float32(360/N)`, 不得把具体天气 Profile 名称写进 Container Parser。 ## 15.2 Direction Integer Normalization 所有 Direction predictor / residual 运算必须使用**整数圆周语义**,不得依赖不同语言对负数 `%` 的行为。 定义 `normalize_direction(x, N)`,其结果必须位于 `[0, N)`。 对于本协议 predictor 产生的范围,固定参考规则为: ```text if x < 0: x = x + N else if x >= N: x = x - N return x ``` 该规则成立是因为输入 raw 均在 `[0,N)`,三邻居 predictor `L + U - UL` 的结果必定位于: ```text [-(N-1), 2(N-1)] ``` 因此最多需要一次 `+N` 或 `-N`。 如果实现使用通用 modulo helper,也必须保证得到相同的 non-negative modulo 结果。 ## 15.3 Circular Predictor 空间邻居选择和 fallback 顺序继续使用第 14 节 validity-aware 规则。 当 `L/U/UL` 全部 valid 时,Direction predictor 必须先计算 widened integer: ```text p = int32(raw(L)) + int32(raw(U)) - int32(raw(UL)) predictedRaw = normalize_direction(p, N) ``` Fallback: ```text L valid → predictedRaw = raw(L) U valid → predictedRaw = raw(U) 否则 → predictedRaw = 0 ``` 不得把未经 `mod N` 规范化的 `L + U - UL` 直接用于 Direction residual。 ## 15.4 circular_shortest_delta() 精确公式 设: ```text d = int32(currentRaw) - int32(predictedRaw) ``` 先将差值规范到 `[0,N)`: ```text m = d if m < 0: m = m + N ``` 此时 `m ∈ [0,N)`。 然后固定: ```text if 2*m > N: residual = m - N else if 2*m < N: residual = m else: # 仅 N 为偶数且恰好半圈时成立 residual = -(N / 2) ``` 因此 half-circle tie **固定选择负方向 `-N/2`**。 该选择属于 QBV3 Version 3 ABI,不得由 Writer / Decoder 自行选择 `+N/2`。 Residual 范围: ```text N 为偶数:[-N/2, N/2) N 为奇数:[-floor(N/2), floor(N/2)] ``` Decoder: ```text x = int32(predictedRaw) + residual rawDirection = normalize_direction(x, N) ``` 边界 Golden Test 至少覆盖: ```text 359° → 0° 0° → 359° N-1 → 0 0 → N-1 偶数 N 的 +N/2 / -N/2 tie → 固定解为 -N/2 三邻居 L+U-UL < 0 三邻居 L+U-UL >= N ``` 在 `scale = 1°` 时,`359° → 0°` 必须得到最短圆周残差,而不是 `±359`。 --- # 16. ZigZag 与固定宽度整数语义 Signed residual 使用 32-bit 逻辑 ZigZag。 精确数学映射冻结为: ```text zigzag(r): if r >= 0: z = 2 * r else: z = -2 * r - 1 ``` inverse: ```text unzigzag(z): if (z & 1) == 0: r = z / 2 else: r = -(z / 2) - 1 ``` 示例: ```text 0 → 0 -1 → 1 1 → 2 -2 → 3 2 → 4 ... ``` 文档中的位运算表达只用于说明数学关系,**不得直接要求 C++ 对 signed integer 执行可能产生 UB / implementation-defined 行为的 shift**。 正式 Writer / Decoder 必须冻结: ```text residual / predictor arithmetic:至少 int32 ZigZag 数学计算:使用 int64 / uint64 widened domain 最终 ZigZag symbol:验证后收敛为 uint32 bit manipulation:uint32 / uint64 shift count:先验证再执行 add / sub / multiply:checked 或 widened arithmetic ``` ZigZag 与 inverse ZigZag 必须提供 Android / iOS 共用的固定宽度 C++ reference implementation, 不得依赖: ```text signed left shift overflow signed right shift implementation behavior host integer width compiler bitfield layout ``` Rice remainder mask 也必须使用明确的 unsigned 宽度,例如逻辑上: ```text uint64_t{1} << k ``` 并保证: ```text k = 0..31 ``` 时不会发生 signed `1 << 31` 或非法 shift。 Golden Test 至少覆盖: ```text 0 1 -1 INT16_MIN INT16_MAX 最大合法 predictor residual ``` Predictor、ZigZag、Rice 必须完全可逆,不能引入任何新的数值误差。 --- # 17. Rice Block Geometry:冻结前候选与最终 ABI V3 已确定采用: ```text validity-aware 2D Predictor → ZigZag → block-adaptive Rice ``` **截至文档 v2.2,Block Geometry 是 QBV3 Version 3 尚未冻结的唯一核心 Binary ABI 参数。** 因此: ```text v2.2 仍是 freeze candidate 不是 production-final ABI ``` 在 16×16 / 32×32 benchmark 完成并回填唯一尺寸前, 任何实验文件都不得作为长期可解释的 production `QBV3/version=3` 发布。 但在正式发布 `QBV3 / version=3` 前,**Block Geometry 尚需用真实 C++ Decoder 做最后一次 16×16 / 32×32 对比**。 当前候选: ```text Candidate A:16×16 Candidate B:32×32 ``` 原因:现有 Wind 143 帧实验中,两者编码体积差异约只有: ```text Rice16 ≈ 43.929 MiB Rice32 ≈ 43.953 MiB 差约 25 KiB / 143 帧 ≈ 175 B / Frame ≈ 0.056% ``` 而 32×32 的 block 数约为 16×16 的 1/4,可能减少: ```text block metadata loop / branch 次数 per-block k 搜索次数 ``` 因此正式冻结前必须在同一 C++ prototype 中记录: ```text encoded bytes decode ms encode ms peak temporary bytes block count ``` 分别比较四类真实数据: ```text Wind Rain Wave Current ``` ## 17.0 Block Partition 数学定义 在 Block Geometry 最终冻结前,用参数: ```text BLOCK_WIDTH BLOCK_HEIGHT ``` 表示候选尺寸。 定义: ```text blockCols = (width + BLOCK_WIDTH - 1) / BLOCK_WIDTH # integer floor division blockRows = (height + BLOCK_HEIGHT - 1) / BLOCK_HEIGHT ``` 对: ```text br ∈ [0, blockRows) bc ∈ [0, blockCols) ``` 定义: ```text rowBegin = br * BLOCK_HEIGHT rowEnd = min(rowBegin + BLOCK_HEIGHT, height) colBegin = bc * BLOCK_WIDTH colEnd = min(colBegin + BLOCK_WIDTH, width) ``` Block traversal: ```text for br = 0 .. blockRows-1: for bc = 0 .. blockCols-1: process block(br, bc) ``` 等价: ```text blockIndex = br * blockCols + bc ``` Block 内: ```text for row = rowBegin .. rowEnd-1: for col = colBegin .. colEnd-1: index = row * width + col if validity[index] == 1: emit one Rice symbol else: emit no symbol ``` 边缘 block 自然裁切到实际 Grid 边界,不补虚拟 cell。 Predictor 继续使用全局 Grid 邻居, 不得因为进入新 block 而 reset。 ## 17.1 正式发布规则 QBV3 第一版**不增加 blockSize 字段,也不增加 codec enum**。 这意味着:一旦 benchmark 选择最终 Block Geometry 并正式发布: ```text magic = QBV3 version = 3 ``` 选定的 block width / height 就成为 Container V3 ABI 的固定组成部分。 在正式冻结前,测试 Writer / Decoder 可以通过编译参数或测试参数运行 16×16 / 32×32; **测试参数不得写进正式 QBV3 文件,也不得形成两种 production version=3 文件解释。** Block Geometry 未冻结期间产生的实验文件: ```text 不得进入 production Manifest 不得进入正式 CDN / qbin_v3 发布路径 不得被 NavSea production 配置发现或缓存 不得标记为正式 QBV3 Golden Fixture ``` 实验产物必须位于明确的: ```text /tmp _runtime experimental/ 或其他非 production 路径 ``` 只有 Block Geometry 选定、文档回填唯一尺寸并完成对应 Writer/Decoder round-trip 后,才允许启用 production `QBIN_V3 / container_version=3` Manifest。 边缘 block 可以小于正式 block width / height。 Block 顺序: ```text north → south west → east ``` 即 block row-major。 Block 内 symbol 顺序: ```text cell row-major 仅遍历 validity=1 的 cell ``` 如果 block 中没有 valid cell: ```text 该 block 写 0 bytes ``` 如果至少存在一个 valid cell: ```text 1 byte riceK 随后为 Rice bitstream 最后补 0 bit 到 byte boundary ``` `riceK`: ```text uint8 允许范围 0..31 ``` Writer 必须选择使该 block Rice bit 数最小的 `k`。 Tie: ```text 选择较小 k ``` 保证 deterministic output。 --- # 18. Rice Bitstream 精确定义 每个 ZigZag value `z`: ```text q = z >> k r = z & ((1u << k) - 1) # 数学表达;实现使用安全 unsigned width ``` 编码: ```text 1. 写 q 个 0 bit 2. 写 1 个终止 bit 3. 写 k 个 remainder bit ``` remainder bit 顺序: ```text Least Significant Bit first ``` 整个 block bitstream 也采用: ```text LSB-first within each byte ``` block 最后不足 8 bit: ```text high unused bits MUST = 0 ``` Decoder 根据 validity mask 可以提前知道该 block 的 `symbolCount`。 Decoder 必须: ```text 精确解出 symbolCount 个 symbol 然后到达/验证该 block 的 byte boundary ``` 不得依赖 sentinel。 不得读过 Descriptor.byteLength。 在 unary quotient 扫描过程中,Decoder 必须在每次 bit advance 前检查剩余 encoded range; 以下情况全部 fail-closed: ```text 终止 bit 在 Plane 结束前不存在 q 超过可安全重建 uint32 residual 的范围 q << k / q * 2^k 发生溢出 remainder 不完整 非零 block padding bit symbolCount 不足或超出 ``` ## 18.1 Logical Residual Upper Bound 除 bitstream / uint32 overflow 检查外,Decoder 还必须根据逻辑 dtype 拒绝**数学上不可能出现**的 residual,避免 CRC 合法但恶意构造的超长 unary quotient 消耗无意义 CPU。 对普通非 Direction Numeric Plane,设 logical raw dtype 的最小/最大值为: ```text minRaw maxRaw ``` 在第 14 节 predictor 下,最大可能 residual 绝对值为: ```text MAX_ABS_RESIDUAL = 2 × (maxRaw - minRaw) ``` 因此: ```text INT16 / UINT16 → MAX_ABS_RESIDUAL = 131070 INT8 / UINT8 → MAX_ABS_RESIDUAL = 510 ``` 对 Direction: ```text MAX_ABS_RESIDUAL = floor(N / 2) ``` 并遵守第 15 节 half-circle tie 固定负方向规则。 Decoder 可据此得到安全上界: ```text MAX_ZIGZAG <= 2 × MAX_ABS_RESIDUAL MAX_Q = MAX_ZIGZAG >> k ``` 在扫描 unary zeros 时,一旦: ```text q > MAX_Q ``` 即可立即 reject,不必继续扫描到 Plane 尾部。 完成 inverse ZigZag 后仍必须再次验证: ```text abs(residual) <= MAX_ABS_RESIDUAL ``` 然后再执行 predictor reconstruction 与最终 logical raw dtype range 检查。 这些检查属于 parser hardening,不改变任何合法 QBV3 bitstream。 --- ## 18.2 Rice k 的 Deterministic 选择公式 对一个 non-empty block,设其按 block 内 canonical cell order 得到的 ZigZag symbol 为: ```text z_0, z_1, ... z_(n-1) ``` 对每个候选: ```text k ∈ [0, 31] ``` 定义纯 Rice symbol bit count: ```text bits(k) = Σ_i [ (z_i >> k) + 1 + k ] ``` 其中: ```text (z_i >> k) = unary zero count q +1 = unary terminator bit +k = remainder bits ``` Writer 必须选择: ```text k* = argmin bits(k) ``` 如果多个 `k` 得到相同 `bits(k)`: ```text 选择数值较小的 k ``` 该 `k*` 属于 **Deterministic Writer Contract**: ```text Writer MUST 写入 k* ``` 但 QBV3 Decoder 的 Binary acceptance 不要求重新计算全部 32 个候选 `k`。 Decoder 对每个 non-empty block 只要求: ```text 0 <= riceK <= 31 bitstream 可在 descriptor.byteLength 内完整解出 symbolCount 精确 padding 合法 residual / reconstructed raw 合法 ``` 因此: ```text riceK != k* ``` 如果其他 Binary Contract 全部合法: ```text MUST NOT solely cause Decoder reject ``` 也就是说: ```text 最优 k* = canonical deterministic Writer output 非最优但合法的 riceK != QBV3 binary corruption ``` Decoder MUST NOT 为 canonicality 验证而强制执行: ```text 对已解出的每个 block 再扫描 k=0..31 重算最优 k* ``` 优化目标**只计算 Rice symbol bits**。 以下固定开销不参与 k 比较: ```text 1-byte riceK block 尾部补到 byte boundary 的 zero padding ``` 原因是必须冻结与当前编码实验一致的 deterministic 选择语义,避免不同 Writer 分别按: ```text raw bit count ``` 或: ```text ceil(bit count / 8) ``` 选择出不同 `k`。 选定 `k*` 后,该 non-empty block 的 encoded byte 数: ```text blockByteLength = 1 + ceil(bits(k*) / 8) ``` 其中前 `1` byte 为 `riceK`。 # 19. Numeric Plane Payload 一个 Numeric Plane payload: ```text Block(0,0) Block(0,1) ... Block(last) ``` Block Geometry 使用第 17 节在正式 ABI freeze 前选定的唯一尺寸。 正式 QBV3 不增加独立 block index table。 原因: ```text Grid size 已知 Block size 在 Container V3 ABI 中固定 Validity 已知 每个非空 block 自带 1-byte k Decoder 可以按 symbolCount 顺序解析 ``` V3 第一版优先完整 Frame decode,不为随机访问单个 block 增加额外索引成本。 ## 19.0 Numeric Plane byteLength 的精确定义 对 Numeric Plane: ```text Descriptor.byteLength ``` 严格定义为该 Plane 自身所有 block encoded bytes 的总和。 对每个 block: ```text validCount == 0 → block contributes 0 bytes validCount > 0 → block contributes: 1 byte riceK + ceil(RiceSymbolBits / 8) ``` 因此: ```text NumericPlane.byteLength = Σ(non-empty blockByteLength) ``` `byteLength` **不包含**: ```text Plane 之前的 align16 padding Plane 之后的 align16 padding Descriptor bytes Header bytes 其他 Plane bytes HTTP / gzip 外层编码 ``` Block 内最后一个 byte 的未使用 high bits仍必须为 0; 这些 bit 位属于该 block 的最后一个 encoded byte,因此属于 `byteLength`。 Plane 间的 16-byte alignment padding 不属于任何 Plane 的 `byteLength`,只由 `byteOffset / payloadLength` canonical packing 规则体现。 ## 19.1 All-invalid Frame V3 第一版正式允许: ```text validity 全 0 ``` 此时: ```text Validity Plane: 正常 BITSET,全 0 Numeric Plane: byteLength = 0 ``` Decoder: ```text 不读取 Rice block 直接 materialize 全 0 canonical raw Plane ``` 成立条件必须严格为: ```text validCount == 0 ``` 如果: ```text validCount > 0 && numeric byteLength == 0 ``` 必须 reject。 `all-invalid`: ```text 不是 corruption 不需要特殊 codec 不写虚假的 1-byte block ``` 产品层如果不希望发布 all-invalid Frame,可以在 Weather Writer / Product Validation 拒绝, 但 Container 行为必须保持上述确定语义。 --- # 20. Plane Packing / Alignment Descriptor Table 排序继续继承 v4.4: ```text semantic → groupId → component ``` Plane payload 按 Descriptor 顺序排列。 ```text plane[0].byteOffset = 0 plane[n].byteOffset = align16(previousEnd) payloadLength = align16(lastEnd) ``` 其中: ```text previousEnd = previous.byteOffset + previous.byteLength align16(x) = (x + 15) & ~15 ``` Plane 间与尾部 padding: ```text MUST = 0 ``` 区别仅在: ```text Numeric Plane byteLength = Rice encoded bytes ``` Validity: ```text byteLength = ceil(count/8) ``` V3 仍要求 canonical minimal packing,不允许额外预留空间。 --- # 21. CRC32 QBV3 使用: ```text CRC-32 / ISO-HDLC ``` 完整参数冻结为: ```text width = 32 poly = 0x04C11DB7 init = 0xFFFFFFFF refin = true refout = true xorout = 0xFFFFFFFF check("123456789") = 0xCBF43926 ``` 对 reflected 实现,等价使用: ```text reflected polynomial = 0xEDB88320 ``` 与: ```text zlib.crc32 ``` 兼容。 CRC 覆盖完整未经 HTTP Distribution Encoding 的 QBV3 bytes: ```text Header Descriptor Table Payload Plane padding Tail padding ``` 计算时: ```text Header offset 76..79 fileCrc32 的 4 bytes 按 0x00 0x00 0x00 0x00 参与计算 ``` Writer: ```text 1. 先写 fileCrc32 = 0 2. 对完整 QBV3 bytes 计算 CRC 3. 将 uint32 CRC little-endian 写回 offset 76..79 ``` Parser: ```text 读取 stored CRC ↓ 计算时把 offset 76..79 逻辑视为 0 ↓ 比较 uint32 ``` 不得对 gzip / HTTP transport 后的 bytes 计算 QBV3 CRC。 如果同时 benchmark QBV2 / QBV3, CRC helper 必须一致,并单独记录 `crcMs`。 # 22. Parser 安全规则:Encoded Budget 与 Decoded Budget 分离 QBV3 Version 3 的 parser conformance limits 冻结为: ```text MAX_PLANE_COUNT = 32 MAX_CELL_COUNT = 2,097,152 MAX_QBIN_BYTES = 64 MiB MAX_DECODED_BYTES_PER_FRAME = 32 MiB ``` 其中: ```text 64 MiB = 64 × 1024 × 1024 bytes 32 MiB = 32 × 1024 × 1024 bytes ``` 这些值属于 QBV3 Version 3 的 normative acceptance limits。 当前 Wind / Rain / Wave / Current 生产需求确认在该容量范围内, 因此 QBV3 Version 3 继续冻结这些上限。 任何 conforming Decoder 对超过上述限制的文件: ```text MUST fail-closed ``` 实现可以额外拥有更严格的本地资源 policy, 但不得把一个超出上述 QBV3 conformance limit 的文件视为 Version 3 合法文件。 未来如果业务确实需要突破任一上限: ```text MAX_PLANE_COUNT MAX_CELL_COUNT MAX_QBIN_BYTES MAX_DECODED_BYTES_PER_FRAME ``` 不得在已发布 `QBV3/version=3` 上静默放宽后仍声称 ABI 未改变。 应通过: ```text 新的 Container Version 或明确 successor binary specification ``` 升级并重新冻结对应 conformance limits。 QBIN V3 的 encoded size 与 decoded size 不再近似相等,因此必须分别限制,并冻结 Parser 执行顺序。 ## 22.1 Stage A:便宜的结构与 Per-frame Decoded Budget 预检查 在 CRC 与任何 Rice entropy decode 之前,先执行不需要解释 Rice bitstream 的结构检查: ```text magic == QBV3 version == 3 planeCount > 0 planeCount <= MAX_PLANE_COUNT width >= 2 height >= 2 cells = checked(width × height) cells <= MAX_CELL_COUNT payloadLength 合理 actualFileLength == 112 + planeCount×32 + payloadLength actualFileLength <= MAX_QBIN_BYTES reserved == 0 Header 固定 ABI 值合法 bounds / time 合法 Descriptor order canonical (semantic, groupId) unique count == cells dtype / valueClass / component 合法 scale / offset 满足 canonical float 规则 byteOffset / byteLength 范围合法 canonical align16 packing / payloadLength 公式合法 ``` 同时执行 Encoded Budget: ```text actual file bytes payloadLength 每个 Plane encoded byteLength 所有 offset + length checked arithmetic ``` 并在任何大 Plane allocation 前执行 Decoder 自己负责的 per-frame decoded budget: ```text decodedNumericPlaneBytes = checked(count × logical numeric dtype width) decodedNumericBytes = checked(sum(decodedNumericPlaneBytes)) decodedValidityBytes = ceil(count / 8) decodedFrameBytes = checked(decodedNumericBytes + decodedValidityBytes) ``` 同一个 canonical Validity BITSET 只计一次。 必须满足: ```text decodedFrameBytes <= MAX_DECODED_BYTES_PER_FRAME ``` 否则: ```text fail-closed ``` QBV3 Binary ABI 只冻结“必须有 per-frame decoded allocation budget 与 checked arithmetic”这一安全要求。 跨多个 retained Frame 的 Store memory policy: ```text 不属于 QBV3 Binary Container ``` 移至 Appendix A 的 Non-normative Integration Notes。 Stage A 不扫描 Rice unary,不根据 Rice 内容做 entropy decode。 ## 22.2 Stage B:CRC32 Stage A 通过后,**先验证完整 QBV3 CRC32**。 ```text 结构 / length / bounds / budget ↓ CRC32 ``` CRC 失败: ```text 立即 fail-closed ``` 不得先对 CRC 已损坏文件执行 Rice entropy decode。 ## 22.3 Stage C:Canonical Payload / Validity CRC 通过后再验证 Payload 内容级规则: ```text Plane / tail padding byte == 0 Validity dtype == BITSET Validity byteLength == ceil(count/8) Validity tail unused high bits == 0 ``` 随后计算: ```text validCount ``` 并冻结 all-invalid 对 Numeric Plane 的约束: ```text validCount == 0 → Numeric byteLength MUST == 0 validCount > 0 → Numeric byteLength MUST > 0 ``` ### 22.3.1 Zero-length Plane Canonical Packing all-invalid Frame 中可能出现多个 zero-length Numeric Plane。 canonical packing 继续按: ```text nextOffset = align16(previousEnd) ``` 计算。 因此: ```text zero-length Plane MAY share byteOffset with adjacent zero-length Plane or the next non-empty Plane. ``` 合法示例: ```text Plane A offset=0 length=0 Plane B offset=0 length=0 Plane C offset=0 length=validityBytes ``` 这属于合法 canonical representation,不是真实 payload overlap。 Parser 的 overlap validation MUST: ```text 只对实际占用非零 byte range 的 Plane 做 overlap 判断; zero-length interval 不得被误判为 overlapping payload corruption。 ``` ## 22.4 Stage D:Rice Entropy Decode 只有 Stage A/B/C 全部通过后,才进入 Numeric Rice decode。 逐 block / symbol 验证: ```text riceK <= 31 非最优 riceK 本身不属于 corruption,不要求 Decoder 重算 k* block exact symbolCount unary quotient <= 第 18.1 节 logical MAX_Q bitstream 不越界 q / remainder / ZigZag arithmetic 不溢出 inverse ZigZag residual 在逻辑上限内 predictor reconstruction checked arithmetic 普通 Numeric: decoded raw 必须落入 logical dtype range Direction: decoded raw 必须同时满足: 0 <= rawDirection < N 否则: fail-closed block padding bit == 0 Plane 解码后精确消费 descriptor.byteLength ``` Malformed Rice stream: ```text fail-closed ``` Direction corruption / acceptance 必须额外覆盖: ```text decoded rawDirection >= N → reject ``` `UINT16` dtype range 合法但超出当前 Circular Contract `[0,N)` 的值不得被接受。 ## 22.5 固定执行顺序 正式 Parser 顺序冻结为: ```text Header / Descriptor / file length / bounds ↓ Encoded + Decoded budget 预检查 ↓ CRC32 ↓ Canonical padding + Validity BITSET 检查 / validCount ↓ Rice entropy decode + ZigZag + Predictor reconstruction ↓ canonical raw materialization ↓ QBV3 Binary Decoder Accepted ``` 之后如果存在外部 Profile Contract: ```text Encoded Field Ingress ↓ Profile Contract Validation ↓ Product / Runtime acceptance ``` 该第二阶段不属于 QBV3 Binary Container validation。 实现可以合并无副作用的小检查,但不得把 Rice entropy decode 提前到 CRC 之前,也不得在 budget 预检查前进行大内存 allocation。 --- # 23. Canonical Decoded Raw Reference Model 本节不是 Runtime API 规范,而是 QBV3 Round-trip 的参考解码结果定义。 Numeric Plane: ```text QBV3 Rice Plane ↓ Rice decode ↓ inverse ZigZag ↓ Predictor reconstruction ↓ logical quantized integer ↓ canonical little-endian fixed-width raw bytes ``` Canonical raw: ```text INT16 → count × 2 bytes, little-endian two's-complement UINT16 → count × 2 bytes, little-endian UINT8 → count × 1 byte INT8 → count × 1 byte, two's-complement ``` Invalid cell: ```text validity = 0 → canonical decoded raw MUST = 0 ``` Validity reference decoded form: ```text 保持 canonical BITSET bytes LSB-first tail unused high bits = 0 ``` bit-exact Round-trip 的权威比较对象: ```text Writer Quantizer integer grid + Writer Validity BITSET ``` 与: ```text Decoder canonical integer grid + Decoder Validity BITSET ``` 必须完全一致。 任何 Runtime-specific: ```text DecodedFieldFrame ContentIdentity hash FieldSeries Projection Renderer ``` 均不属于 QBV3 Binary ABI,移至 Appendix A。 # 24. 非 Normative 的 Profile / 实验 / Distribution 信息 Wind / Rain / Wave / Current 第一阶段候选 Profile、压缩实验统计、 HTTP Distribution Encoding 与 Manifest 示例都属于产品 / Profile / 发布层信息, 不属于 `QBV3/version=3` Binary ABI。 统一移至 Appendix B。 QBV3 Binary Parser 不得根据: ```text wind / 2 wave / 2 rain / 2 current / 2 Manifest 文件扩展名 HTTP Content-Encoding ``` 改变 Header / Descriptor / Validity / Predictor / ZigZag / Rice / Packing / CRC 的解释。 # 25. Container Version Dispatch 的最小要求 如果同一系统同时支持 QBV2 / QBV3: ```text QBV2 → magic "QBV2", version=2 QBV3 → magic "QBV3", version=3 ``` Unknown magic/version combination: ```text fail-closed ``` 除以上识别规则外,迁移、Store、Runtime、平台实现均不属于 QBV3 Binary ABI。 # 26. Binary Spec 与消费实现分离 QBV3 Binary Container 只规定: ```text bytes 如何写 bytes 如何验证 bytes 如何无损恢复 quantized integer grid ``` NavSea、React、Store、Binding、Renderer、平台 Bridge 等消费方式: ```text 不属于本文 normative Binary ABI ``` 相关背景统一放入 Appendix A。 # 27. Decoder 实现语言中立 QBV3 不规定 Decoder 必须使用何种语言。 任何 conforming implementation 都必须对同一合法 QBV3 bytes 得到相同: ```text Header Descriptor Validity canonical quantized integer grid ``` 并对同一 malformed bytes 得到相同 Binary Accept / Reject 结论。 # 28. Deterministic Writer 与 Container V3 Codec ABI 相同: ```text Canonical Field Field Profile Version Container Version ``` 必须生成: ```text byte-for-byte identical QBV3 ``` 正式 `QBV3 / version=3` 发布前,必须先完成第 17 节 Block Geometry benchmark 并选择唯一尺寸。 一旦正式发布,下列内容全部成为 Container V3 Binary ABI: ```text validity-aware predictor 规则 predictor fallback 顺序 Direction circular residual 规则 ZigZag 定义 最终冻结的 Block Geometry Block traversal order Cell traversal order valid-cell-only symbol stream Rice k search 0..31 Rice k tie → smaller k Rice unary form Rice remainder bit order byte 内 bit order block padding Descriptor canonical order Plane canonical packing Padding = 0 reserved = 0 CRC algorithm ``` 不得依赖: ```text hash/map iteration order platform endian compiler bitfield layout undefined signed overflow / shift behavior ``` 如果正式发布后要改变: ```text Block Geometry Predictor Rice bitstream bit order 新增第二种内部 codec ``` 不能只修改文档修订号让相同 `QBV3/version=3` 出现两种解释。 必须: ```text 升级新的 Container Version ``` 或者在**新的 Container Version 设计阶段**明确引入可识别 codec 字段。 V3 第一版继续保持单一固定 codec,不为未来可能性提前增加 codec switch。 --- # 29. Golden Binary Fixtures 正式冻结后至少准备: ```text Wind Wave Rain Current ``` 四类真实数据的 Golden QBV3 Fixture。 每个 Fixture 至少记录: ```text QBV3 document revision container version magic referenceTimeUtc validTimeUtc grid / bounds Header bytes Descriptor bytes canonical physical baseline quantized integer baseline validity baseline 正式 QBV3 bytes CRC32 SHA-256 raw QBV3 byteLength gzip byteLength(若另外做 distribution benchmark) per-plane encoded byteLength blockCount nonEmptyBlockCount Rice k distribution writer timing decoder timing peak temporary memory ``` Block Geometry 冻结前允许生成: ```text experimental/16x16/ experimental/32x32/ ``` 两组 benchmark fixture。 最终 Block Geometry 冻结后必须重新生成唯一正式 Golden Fixture 集合。 # 30. Round-trip 验收 最重要的 Round-trip 先验证整数 bit-exact: ```text Writer Quantizer output integer array ↓ QBV3 Writer ↓ QBV3 file ↓ C++ QbinV3Decoder ↓ Decoded canonical raw integer array ``` 结果必须: ```text array_equal == true ``` 不是近似比较。 同时: ```text validity array_equal == true invalid cell decoded raw == 0 ``` 物理误差测试单独比较: ```text 原始 canonical physical vs decoded raw × scale + offset ``` 确保: ```text Predictor / ZigZag / Rice 不贡献任何额外误差 物理误差只来自 Field Profile Quantization ``` 全量验证阶段建议覆盖全部生成 Frame,而不是只抽样。 Direction 必须包含: ```text 359° ↔ 0° N-1 ↔ 0 half-circle tie ``` All-invalid fixture 必须验证: ```text Validity 全 0 Numeric byteLength = 0 Decoded raw 全 0 zero-length Numeric Plane 可共享 canonical byteOffset ``` --- # 31. Binary Reject / Accept / Writer Validation 验收 本节按职责拆分为三组,避免把: ```text Binary corruption Binary canonical-but-unusual input Writer input validation ``` 混为同一类。 ## 31.1 Binary Reject Cases 以下 malformed / corruption 情况必须: ```text MUST fail-closed ``` 至少覆盖: ```text Bad magic Bad version Big-endian/mixed endian Header reserved != 0 Descriptor reserved != 0 Invalid planeCount Invalid cell count Overflowed width×height Bad byteOffset Bad byteLength Non-canonical descriptor order Extra padding Nonzero padding Bad CRC Truncated Rice block Rice unary never terminates before end riceK > 31 Block symbol count insufficient Block symbol count extra data Nonzero block padding bits Invalid validity tail bits Numeric offset = -0.0f Header bound = -0.0 binary64 Direction invalid canonical scale QBV3 decoded rawDirection >= N non-zero Plane actual byte-range overlap semantic = 3 but valueClass != VALIDITY semantic = 3 but dtype != BITSET valueClass = VALIDITY but semantic != 3 dtype = BITSET but valueClass != VALIDITY ``` 以上情况: ```text QbinV3Decoder → reject ``` ## 31.2 Binary Accept Cases 以下情况本身不得单独导致 Binary reject: ```text non-optimal riceK + otherwise-valid block → MUST accept Unknown fieldType → MUST accept as opaque hint fieldType = 0 → MUST accept as UNKNOWN / UNSPECIFIED opaque hint all-invalid Frame Validity 全 0 Numeric byteLength = 0 → MUST accept all-invalid zero-length adjacent Plane shared byteOffset → MUST accept as canonical packing ``` 特别冻结: ```text riceK != Writer 最优 k* ``` 如果其余: ```text riceK range symbolCount padding residual raw range descriptor.byteLength ``` 全部合法,则: ```text MUST NOT solely cause Decoder reject ``` Decoder 不要求为 canonicality 重新计算: ```text k = 0..31 ``` 的全部候选。 ## 31.3 Writer Validation Cases 以下属于 Writer input / deterministic output 验证, 不是“Decoder corruption”: ```text validity=1 + physical = NaN / +Inf / -Inf → Writer MUST reject validity=0 + numeric physical = NaN / +Inf / -Inf / missing → Writer MAY accept → value MUST be ignored → MUST NOT enter Quantizer → MUST NOT emit Rice symbol Writer MUST NOT: 通过 NaN / Inf 自动推导 validity=0 delta64 non-finite → Writer MUST reject normalized64 non-finite → Writer MUST reject normalizedDirection64 non-finite → Writer MUST reject physicalDirection 不满足: finite 0 <= angle < 360 DIRECTION_TO → Writer MUST reject / 上游先 normalize Writer 对每个 non-empty block: MUST 写 deterministic 最优 k* ``` ## 31.4 外部 Profile / Integration Validation 以下属于外部 Integration / Profile Contract validation, 不得标记为 QBV3 binary corruption: ```text Missing Profile-required Plane Undeclared REQUIRED relative to external Contract Contract mismatch fieldType / fieldProfile mismatch QBV2 Direction legacy acceptance ``` QBV2 的 Direction legacy regression 应在 V2 ingress compatibility test 中覆盖, 不属于 QBV3 corruption suite。 # 32. Codec 性能验收 QBV3 的 Binary ABI 不规定消费方 Runtime 生命周期,但正式冻结 Block Geometry 前必须完成 codec-level benchmark。 同一测试平台、同一 build 配置下至少记录: ```text raw QBV3 bytes gzip QBV3 bytes(若测试 distribution gzip) crcMs entropyDecodeMs totalDecodeMs encodeMs peakTemporaryBytes decodedFrameBytes blockCount nonEmptyBlockCount Rice k distribution ``` 必须比较: ```text 16×16 vs 32×32 ``` 并覆盖: ```text Wind Rain Wave Current ``` 如果同时比较 QBV2 / QBV3: ```text CRC 实现必须一致 crcMs 与 entropyDecodeMs 必须分开 ``` 不要求 QBV3 entropy decode 比固定宽度 QBV2 decode 更快。 Block Geometry 的选择依据应综合: ```text encoded bytes encode CPU decode CPU peak temporary memory 实现复杂度 ``` 而不是只看压缩率。 ## 32.1 Streaming reconstruction 实现目标 推荐 Decoder: ```text compressed Plane input ↓ BitReader ↓ 逐 symbol Rice decode ↓ inverse ZigZag ↓ 立即 Predictor reconstruction ↓ 直接写最终 canonical fixed-width raw storage ``` 应避免为了实现方便同时建立多个 full-grid 临时数组: ```text residual[] zigzagDecoded[] predictorOutput[] rawOutput[] ``` 这是性能实现目标,不改变 QBV3 bitstream。 # 33. QBV3 第一阶段 Binary ABI 验收基线 正式冻结 / 发布 `QBV3/version=3` 前至少满足: ```text 1. Header 112-byte layout、Little Endian、reserved=0 已冻结。 2. layout=1 / projection=1 / sampleOrder=1 / gridRegistration=1 已冻结。 3. tileZ=0xffff / tileX=0 / tileY=0 已冻结。 4. referenceTimeUtc / validTimeUtc 为正 int64 Unix UTC seconds。 5. Binary Parser 不强制 validTimeUtc >= referenceTimeUtc。 6. Bounds 是 finite binary64 WGS84 lon/lat,0 必须编码为 +0.0。 7. WEB_MERCATOR + NODE projected-space sample 公式有 Golden Test。 8. Descriptor 32-byte layout 与 dtype byte enum 已冻结。 9. valueClass / component / core unit / VALIDITY semantic structural invariants 已冻结。 10. Numeric dtype 仅允许 INT16/UINT16/UINT8/INT8;FLOAT32 Rice Plane reject。 11. Shared Validity 有且只有一个,semantic=3、dtype=BITSET、REQUIRED。 12. Validity scale=+1.0f、offset=+0.0f。 13. Numeric scale > 0 finite;offset finite;零 offset 使用 +0.0f。 14. Quantizer 先确定 Descriptor binary32 scale/offset,再提升到 binary64 计算。 15. validity=1 的 canonical physical sample MUST 为 finite binary64; validity=0 的 numeric physical value 不参与 Quantizer,可为 NaN / Inf / missing。 16. round_half_away_from_zero 精确公式有 ±0.5 边界 Golden Test。 17. Shared Validity BITSET LSB-first,tail unused high bits=0。 18. Decoder 先解析全部 Descriptor,逻辑上先定位/读取 Validity,再解 Numeric。 19. 2D Predictor 在整个 Grid 连续,不在 block 边界 reset。 20. Direction canonical float32(360/N)、N=floor(ratio+0.5)、raw∈[0,N)。 21. Direction half-circle tie 固定为 -N/2。 22. ZigZag / inverse ZigZag 使用固定宽度无 UB 语义。 23. Block partition 数学公式、block row-major、cell row-major 已冻结。 24. 16×16 / 32×32 使用同一 Writer/Decoder prototype 完成四类真实 benchmark。 25. Rice k 使用 bits(k)=Σ((z>>k)+1+k),tie 取较小 k。 26. k 优化不把 riceK byte / byte padding 纳入目标。 27. non-empty blockByteLength = 1 + ceil(RiceSymbolBits/8)。 28. Numeric Plane byteLength = Σ(non-empty blockByteLength),不含 align16 padding。 29. all-invalid:Validity 全 0、Numeric byteLength=0、decoded raw 全 0。 30. zero-length Plane shared byteOffset 不误判 overlap。 31. Plane / tail align16 padding 全 0。 32. CRC-32/ISO-HDLC 完整参数、check value 与 CRC field-zeroing 已冻结。 33. Parser 顺序:结构+budget → CRC → Validity → Rice。 34. MAX_Q / residual logical upper-bound hardening 生效。 35. malformed Rice / truncation / overflow / nonzero padding 全部 fail-closed。 36. MAX_PLANE_COUNT=32。 37. MAX_CELL_COUNT=2,097,152。 38. MAX_QBIN_BYTES=64 MiB。 39. MAX_DECODED_BYTES_PER_FRAME=32 MiB。 40. 超出上述 Version 3 conformance limits 的文件 fail-closed。 41. 全部 Numeric Plane integer bit-exact round-trip。 42. strict Validity bit-exact round-trip。 43. Direction 359°↔0° / N-1↔0 / half-circle / predictor wrap 通过。 44. Writer deterministic:相同 canonical input + 相同 Descriptor → byte-for-byte 相同 QBV3。 45. Golden Binary Fixtures 覆盖 Wind / Rain / Wave / Current。 46. Block Geometry 未冻结前实验文件不进入 production。 47. 最终选择唯一 BLOCK_WIDTH / BLOCK_HEIGHT 后重新生成正式 Golden Binary。 48. validity=1 的 physical sample 必须 finite;validity=0 的 numeric physical value 被忽略,不参与 Quantizer。 49. Writer 不得通过 NaN/Inf 自动推导 Validity。 50. ZigZag / inverse ZigZag 精确数学公式有 Golden Test。 51. Quantizer binary64 subtraction/division 使用 round-to-nearest, ties-to-even 语义。 52. Direction input 在 Writer 前已经 canonical 为 DIRECTION_TO 且 0<=angle<360。 53. unknown fieldType 不得单独导致 binary reject。 54. 任意 Numeric offset 数值为 0 时必须使用 +0.0f,-0.0f reject。 55. Validity BITSET 的 byteIndex / bitIndex 公式有 byte-exact Golden。 56. semantic==3 ⇔ valueClass==VALIDITY ⇔ dtype==BITSET 的双向规则通过 corruption test。 57. delta64 / normalized64 / normalizedDirection64 non-finite → Writer FAIL。 58. fieldType=0 作为 UNKNOWN / UNSPECIFIED opaque hint 可 binary-accept。 59. Writer 对每个 non-empty block 写最优 k*。 60. Decoder 不因非最优但 otherwise-valid 的 riceK 单独 reject,也不要求重算 k*。 61. WEB_MERCATOR mercatorX / mercatorY / inverse 数学公式有定位 Golden Test。 62. 一个 targetTime 一个独立 QBV3 Frame。 ``` 在 v2.2 中: > **除最终 `BLOCK_WIDTH / BLOCK_HEIGHT` 尚需通过 16×16 / 32×32 C++ benchmark 实测选择外,其他核心 QBV3 Binary ABI 语义已完成文档冻结;Rice canonicality 采用 Writer-canonical / Decoder-permissive。v2.2 之后不再因实现偏好继续修改 Binary Spec。** 消费侧 Store、Binding、Renderer、NavSea、React、Profile Contract、Manifest 与平台 Bridge 不作为 QBV3 Binary ABI 的冻结条件。 # 34. 版本与命名最终规则 以后统一使用: ```text QBIN V2 = Container Version 2 = Magic QBV2 = 最终权威设计基线文档 v4.4 QBIN V3 = Container Version 3 = Magic QBV3 = 本文从 Document Revision v1.0 开始;当前修订为 v2.2 ``` 禁止再使用: ```text “QBIN V4” ``` 来代指 Container V2。 如果需要说明历史: ```text QBIN V2 / v4.4 design baseline ``` 如果需要说明新格式: ```text QBIN V3 ``` Field Profile Version 独立: ```text wind / 2 wave / 2 rain / 2 current / 2 ``` --- # 35. 最终冻结候选语句 **架构继承:** > QBIN V3 继承 QBIN V2 / v4.4 的 Semantic、Unit、Field Profile Contract、Independent Binding、Forecast Runtime 与 Generic Renderer 架构;只在 Encoded Field Ingress 之前改变二进制 Numeric Plane 表达。 **数值误差:** > V3 的物理误差只来自 Field Profile Quantization;2D Predictor、ZigZag 与 Rice 必须 bit-exact 可逆。 **统一编码:** > V3 第一版所有整数 Numeric Plane 统一使用 validity-aware 2D Predictor + ZigZag + 单一固定 Block Geometry 的 adaptive Rice;Validity 继续使用 shared BITSET。Block Geometry 在正式 `QBV3/version=3` 发布前通过 16×16 / 32×32 C++ benchmark 选定,发布后成为不可兼容修改的 Container V3 ABI。 **Direction:** > QBV3 `DIRECTION_ANGLE` 使用 Generic Circular Quantization Contract;合法 scale 必须满足 canonical `float32(360/N)`,Container Parser 不根据具体天气 Profile 名称放宽或改变该规则。 **Decoded contract:** > QBV3 Decoder 的 reference decoded result 是 canonical fixed-width quantized raw grid;Predictor / ZigZag / Rice 必须完全可逆,Invalid cell 的 canonical raw 固定为 0。 **职责边界:** > QBV3 Binary ABI 只规定 Writer 如何生成 bytes、Parser 如何验证 bytes、Decoder 如何无损恢复 quantized integer grid;消费侧架构不属于 Container 规范。 **时间单位:** > 一个 targetTime = 一个独立 QBV3 Frame,不把多个时间点合并成一个网络归档。 **四类第一阶段 Profile:** ```text Wind U/V 0.1 m/s Rain 0.1 mm/h Wave Height 0.05 m / Period 0.1 s / Direction 1° Current U/V 0.02 m/s ``` **Wave Range:** > Wave Height 不以 10 m 为格式上限;第一阶段至少验证 0–30 m,10 m 必须正常表达。 **版本:** > 新编码不继续冒充 QBIN V2,也不创建“QBIN V5”第二套编号;直接使用 QBIN V3 / QBV3 / version=3。 --- # 36. 当前状态与下一步 本文当前状态: ```text 设计冻结候选 v2.2 ``` 已经完成: ```text Header / Descriptor byte layout Little Endian / canonical float Header fixed FRAME ABI WEB_MERCATOR + NODE Grid 空间语义 DType / ValueClass / Component / Core Unit 机器值 Shared Validity BITSET Generic Numeric Quantization round_half_away_from_zero Direction Circular Contract 2D Predictor ZigZag Rice bitstream Rice k deterministic 选择公式 Block partition 数学公式 Numeric Plane byteLength Plane Packing / Alignment All-invalid representation CRC-32/ISO-HDLC 完整参数 Parser 执行顺序与 fail-closed Parser conformance limits Canonical decoded raw reference model Deterministic Writer 规则 Golden / Round-trip 验收规则 Invalid-cell / non-finite physical Writer 语义 ZigZag / inverse ZigZag 精确数学 ABI Quantizer binary64 rounding 语义 unknown fieldType forward-compatible Binary 行为 Validity BITSET 精确位索引 Numeric canonical +0.0 offset 全局规则 WEB_MERCATOR 精确数学公式 VALIDITY semantic 双向约束 Quantizer intermediate finite 规则 fieldType=0 UNKNOWN / UNSPECIFIED 语义 Rice Writer-canonical / Decoder-permissive 规则 ``` 尚未完成: ```text 16×16 / 32×32 真实 Writer/Decoder benchmark 最终 BLOCK_WIDTH / BLOCK_HEIGHT freeze 正式 QBV3 Writer 正式 QBV3 Decoder 四类 full integer/validity bit-exact round-trip 正式 Golden Binary Fixtures corruption / fail-closed 全量验证 codec encode/decode CPU + peak temporary memory benchmark ``` 其中: ```text 最终 BLOCK_WIDTH / BLOCK_HEIGHT ``` 是正式发布前唯一仍需通过实测选择的核心 Binary ABI 参数。 其余 Binary 结构与数据语义在 v2.2 中不再保留未决分支。 从 v2.2 起,除非 Prototype / Golden / Corruption Test 证明现有 Binary Contract 存在真实不可实现、不可唯一解释或自相矛盾的问题,否则不得再因实现偏好修改 QBV3 Binary ABI。 在以上实现与验证完成前: ```text QBIN V2 / v4.4 仍是已实施历史基线 QBIN V3 v2.2 是下一代候选生产格式设计 ``` 下一步建议严格按以下顺序: ```text 1. 以本文 v2.2 作为最终设计冻结稿,实现最小 deterministic QBV3 Writer + Decoder prototype。 2. 同一 prototype 仅以测试参数运行 16×16 / 32×32。 3. 用 Wind / Rain / Wave / Current 真实 Frame 做 integer/validity bit-exact round-trip。 4. 同时记录 raw/gzip bytes、encodeMs、crcMs、entropyDecodeMs、totalDecodeMs、peakTemporaryBytes。 5. 选择唯一 BLOCK_WIDTH / BLOCK_HEIGHT。 6. 将唯一 Block Geometry 回填本文,删除所有实验双选语义。 7. 生成正式 Golden Binary Fixtures。 8. 完成 corruption / fail-closed 全量验证。 9. 将该版本作为 QBV3/version=3 production-final Binary ABI 冻结稿。 ``` --- # Appendix A. Non-normative Integration / Compatibility Notes 本 Appendix **不属于 QBV3 Binary ABI**。 ## A.1 QBV2 Legacy Direction Compatibility 当前项目若继续支持 QBV2,应保持其既有 authoritative ingress acceptance, 包括历史 Direction scale tolerance。 该规则属于: ```text QBV2 compatibility ``` 不是 QBV3 Container 规则。 QBV3 只使用正文第 15 节的 canonical Circular Contract。 ## A.2 ContentIdentity / Runtime Hash 当前项目可为了 QBV2/QBV3 共存,让 decoded Plane 复用既有 runtime identity helper。 这些: ```text uint64 hash runtime contentIdentity string ``` 不写入 QBV3 文件,也不参与 QBV3 CRC,因此不是 Container Version 3 ABI。 ## A.3 Profile Contract 外部 Profile Contract 可以比 QBV3 Binary Parser 更严格,例如校验: ```text expectedDType expectedScaleBits expectedOffsetBits required Plane 集合 ``` 这些属于: ```text Profile-valid ``` 而不是: ```text Binary-valid ``` 一个 binary-valid 但 profile-invalid 的 QBV3 文件不应被称为 binary corruption。 ## A.4 Store / Runtime / NavSea / React / Platform Bridge 以下都不是 QBV3 Binary ABI: ```text EncodedFieldStore FieldSeries T0 / T1 / mix Binding Renderer NavSea 下载/缓存/预取 React / RN API Android / iOS transport retained-memory policy ``` 这些实现不得反向改变正文对 `QBV3/version=3` bytes 的解释。 --- # Appendix B. Informative Profile / Product / Distribution Notes 本 Appendix 只保留当前 WeatherV2 第一阶段实验与产品背景, 用于 Writer Prototype 和 Golden Fixture 选样。 ## B.1 第一阶段候选 Profile ```text Wind / 2 U/V INT16 0.1 m/s offset +0.0 Rain / 2 UINT16 0.1 mm/h offset +0.0 Wave / 2 Height UINT16 0.05 m Period UINT16 0.1 s Direction UINT16 1° offset +0.0 Current / 2 U/V INT16 0.02 m/s offset +0.0 ``` 这些 Profile 用于当前真实数据 benchmark, 但 QBV3 Parser 不得写 `if WIND / WAVE / RAIN / CURRENT`。 ## B.2 当前量化误差实验 ```text Wind: speed MAE ≈ 0.02461 m/s speed p95 ≈ 0.05205 m/s speed p99 ≈ 0.06201 m/s speed max ≈ 0.07071 m/s Rain: MAE ≈ 0.0149 mm/h max ≈ 0.0500 mm/h Wave: Height max additional error ≈ 0.02 m Direction max additional error ≈ 0.5° Current: speed MAE ≈ 0.00646 m/s speed max ≈ 0.0141 m/s ``` Predictor / ZigZag / Rice 不允许增加额外数值误差。 ## B.3 Block-size 既有实验 Wind 143 帧既有模型结果: ```text Rice16 ≈ 43.929 MiB Rice32 ≈ 43.953 MiB 差约: 25 KiB / 143 Frames ≈ 175 B / Frame ≈ 0.056% ``` 因此最终 Block Geometry 不能只看压缩率, 必须等待真实 Writer/Decoder CPU 与 memory benchmark。 ## B.4 Distribution / Manifest QBV3 Container 与 HTTP Distribution Encoding 分离。 可以外层发布: ```text .qbin .qbin.gz HTTP Content-Encoding ``` 但解压后必须恢复同一 QBV3 bytes。 Manifest / CDN path / Profile metadata: ```text 不属于 QBV3 Binary ABI ```