90 KiB
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 的最终文档清理:
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 的最终收口重点:
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 的最终收口重点:
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 的收口重点:
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 的收口重点:
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 的收口重点:
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 的收口重点:
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 的收口重点:
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 的收口重点:
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 的收口重点:
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 的收口重点:
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 的第一版设计文档修订版。
上一代权威设计基线为:
WeatherV2_QBIN_V2通用天气场二进制格式与React独立Render_Binding设计_v4.4.md
其中:
文档设计版本: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 已冻结的下列架构原则继续有效:
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 原则继续冻结:
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
等天气业务分支
因此:
QBIN V2 Decoder
↓
DecodedFieldFrame
↓
Runtime / Binding / Renderer
升级为:
QBIN V3 Decoder
↓
DecodedFieldFrame
↓
Runtime / Binding / Renderer
Decoder 之后的公共架构原则保持不变。
0.2 V3 为什么需要新的 Container Version
QBIN V2 将 Numeric Plane 定义为固定宽度的直接量化整数数组,例如:
INT16 → byteLength = count × 2
UINT16 → byteLength = count × 2
Numeric Plane 的 byteLength 可以直接由:
count × dtype size
推导。
QBIN V3 引入新的 Numeric Plane 编码:
Physical Value
↓
Quantization
↓
Integer Grid
↓
2D Spatial Predictor
↓
Signed Residual
↓
ZigZag
↓
固定 Block Geometry 的 adaptive Rice Coding
↓
Variable-length Encoded Plane
因此 Numeric Plane 的编码长度不再等于:
count × dtype size
而成为真正的:
variable-length encoded payload
这改变了 QBIN V2 的二进制 Plane Contract,因此不能继续标记为 Container Version 2。
正式升级为:
QBIN Container Version:3
Magic:QBV3
Version:3
0.3 V3 不代表业务协议重做
Container Version 升级只表示:
Encoded Binary Representation
发生不兼容变化。
它不意味着以下协议重新开始:
Semantic ID
Unit ID
Value Class
Component
groupId
Field Profile
Render Binding
Forecast Runtime
Renderer
这些仍继承 v4.4 的长期通用设计。
因此:
Container Version
和:
Field Profile Version
必须继续独立管理。
第一阶段建议:
QBIN V3
wind / 2
wave / 2
rain / 2
current / 2
表示:
Container 使用 QBIN V3
+
各天气 Field 使用自己的 Profile Version
而不是把天气业务规则硬编码进 Container Version。
0.4 v4.4 文档的历史地位
WeatherV2_QBIN_V2通用天气场二进制格式与React独立Render_Binding设计_v4.4.md
从 QBIN V3 生效后仍永久保留,作为:
QBIN V2 最终冻结规范
QBIN V3 架构来源基线
旧 QBV2 文件解释依据
V2/V3 兼容与迁移依据
不得覆盖、改名或修改其已经冻结的历史定义。
本文只定义:
QBIN V3
以后对 V3 的小幅修订使用本文自身的:
Document Revision
管理,例如:
v1.0
v1.1
v1.2
不得再用文档修订号代替 Container Version。
因此版本体系统一为:
QBIN V2
└── 最终设计基线:v4.4
QBIN V3
└── 本文初始设计版本:v1.0
0.5 本文的 Normative Scope
从 v1.7 开始,本文的 normative 主体只定义:
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:
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 保存,不能反向改变同一个:
magic = QBV3
version = 3
的文件解释。
目标是:
Weather 生产方只阅读本文 normative 主体,就能生成 byte-for-byte deterministic、跨平台可解码、可严格校验的 QBV3 文件;消费方实现细节不属于 Container 语义。
1. V3 设计目标
QBIN V3 的核心目标只有一个:
在保持 v4.4 通用天气场架构不变的前提下,大幅降低每个时间 Frame 的网络与缓存体积,并保持 Native 解码简单、确定、可校验。
设计目标:
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 不负责:
颜色表
粒子颜色
粒子数量
Trail
UI
Provider 网络请求
Route / ETA 业务
Forecast 下载调度
缓存淘汰策略
V3 也不改变:
ColorBinding / ParticleBinding
Core Forecast Clock
FieldSeries
T0 / T1 / mix
GPU Renderer
3. 最终数据链
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:
QBV2 → QbinV2Decoder ┐
├→ DecodedFieldFrame
QBV3 → QbinV3Decoder ┘
不得把 V3 编码细节泄漏到 Runtime/Renderer。
4. 文件总体结构
V3 第一版继续采用简单固定结构:
┌──────────────────────────────┐
│ Fixed Header │ 112 bytes
├──────────────────────────────┤
│ Plane Descriptor Table │ 32 bytes × planeCount
├──────────────────────────────┤
│ Payload │ variable
└──────────────────────────────┘
继续不保存:
headerSize
descriptorSize
descriptorOffset
payloadOffset
totalLength
固定:
HEADER_SIZE = 112
DESCRIPTOR_SIZE = 32
descriptorOffset = 112
payloadOffset = 112 + planeCount × 32
expectedTotalLength = payloadOffset + payloadLength
V3 第一版不利用 Header/Descriptor 的 reserved 字段承载新业务信息。
所有 reserved 字段仍必须:
0
这样保留二进制结构的简单性。
5. Magic / Version / Endian
magic = ASCII "QBV3"
version = 3
未知 Version:
fail-closed
所有 multi-byte integer 与 IEEE-754 floating point:
Little Endian
Rice bitstream 的 bit order 由本文第 18 节单独定义,不使用 host-native bitfield。
5.1 QBV3 第一版 FRAME 固定 Header ABI
QBV3 第一版只定义:
layout = FRAME
对应 Header 固定值:
layout = 1
projection = 1 # WEB_MERCATOR
sampleOrder = 1 # NORTH_TO_SOUTH_WEST_TO_EAST
gridRegistration = 1 # NODE
tileZ = 0xffff
tileX = 0
tileY = 0
以下时间字段:
referenceTimeUtc
validTimeUtc
固定为:
int64
Unix UTC seconds
MUST > 0
不得在 Header 中直接写毫秒。
QBV3 Container 不规定二者的相对大小:
不得在 Binary Parser 中强制:
validTimeUtc >= referenceTimeUtc
以下情况都可以由外部 Profile / Dataset 语义决定:
Forecast
Analysis
Observation
Reanalysis / Hindcast
因此 Binary-valid 只要求两个时间字段各自满足格式与范围要求,
不因 validTimeUtc < referenceTimeUtc 自动判定 corruption。
Bounds:
west / south / east / north
必须是 finite float64,第一版 WEB_MERCATOR FRAME 至少满足:
-180 <= west < east <= 180
-85.0511287798066 <= south < north <= 85.0511287798066
未知 layout / projection / sampleOrder / gridRegistration:
fail-closed
这些值直接属于 QBV3 Container ABI,不要求 Writer 通过查阅 QBIN V2 文档才能生成合法 Header。
5.2 WEB_MERCATOR + NODE Grid 的精确空间语义
Header:
west / south / east / north
是:
WGS84 longitude / latitude degrees
但 Grid node 在南北方向的等间距不是按 latitude degree 线性插值, 而是在 Web Mercator projected space 中等间距。
定义数学上的 dimensionless spherical Web Mercator:
λ = longitudeDeg × π / 180
φ = latitudeDeg × π / 180
mercatorX(longitudeDeg) =
λ
mercatorY(latitudeDeg) =
ln(
tan(
π/4 + φ/2
)
)
其 inverse:
longitudeDeg =
X × 180 / π
latitudeDeg =
(
2 × atan(exp(Y))
- π/2
) × 180 / π
由于 Header 已限制:
-85.0511287798066 <= latitude <= 85.0511287798066
正文不再额外定义 latitude clamp。
若某实现使用 EPSG:3857 meter coordinate:
X_meter = 6378137 × X
Y_meter = 6378137 × Y
其 Grid node 位置与本文 dimensionless 公式完全等价; 规范语义以本文 dimensionless 公式为准。
实现用于 Grid sample 定位时应采用 IEEE-754 binary64 计算。
因此:
xWest = mercatorX(west)
xEast = mercatorX(east)
yNorth = mercatorY(north)
ySouth = mercatorY(south)
对于 NODE grid:
dx = (xEast - xWest) / (width - 1)
dy = (yNorth - ySouth) / (height - 1)
逻辑 sample (row, col):
x = xWest + col * dx
y = yNorth - row * dy
因此:
row = 0
→ north edge
row = height - 1
→ south edge
col = 0
→ west edge
col = width - 1
→ east edge
flattened cell index:
index = row * width + col
sample order:
NORTH_TO_SOUTH_WEST_TO_EAST
等价于:
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,沿用上一代已知值:
1 = WIND
2 = WAVE
3 = CURRENT
4 = RAIN
5 = AIR_TEMPERATURE
6 = SEA_TEMPERATURE
7 = AIR_PRESSURE
8 = HUMIDITY
9 = VISIBILITY
未知 fieldType:
MUST NOT solely cause binary rejection
只要 Header / Descriptor / Plane / CRC 等其他 QBV3 Binary Contract 全部合法, Generic QBV3 Parser 必须继续按 binary-valid 处理。
也就是说 fieldType 是:
opaque uint16 machine hint
已知值具有当前约定含义,未知值仍保持 forward-compatible hint 语义。
特别冻结:
fieldType = 0
= UNKNOWN / UNSPECIFIED
= binary-valid opaque hint
fieldType=0 或其他未知 uint16 值都不得单独导致 Binary reject。
fieldType MUST NOT 决定:
Plane count
Plane semantic set
dtype
scale / offset
REQUIRED completeness
Rice block interpretation
Profile compatibility
Renderer behavior
因此:
fieldType == WIND
不能替代外部:
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:
如果任一 bound 的数学值 == 0:
MUST serialize as +0.0 binary64
bit-pattern:
0x0000000000000000
禁止:
-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 值冻结为:
1 = INT16
2 = UINT16
3 = UINT8
4 = INT8
5 = FLOAT32
6 = BITSET
QBV3 Version 3 第一版合法组合:
Numeric Plane:
dtype ∈ {INT16, UINT16, UINT8, INT8}
即 byte value ∈ {1,2,3,4}
Validity Plane:
dtype = BITSET
即 byte value = 6
以下在 QBV3 Version 3 第一版必须 reject:
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 的固定宽度存储长度。
count = width × height
byteLength = 该 Plane 的实际 Rice encoded byte 数
因此 V3 Numeric Plane 不再要求:
byteLength == count × dtypeSize
Validity Plane
第一版仍保持直接 BITSET:
dtype = BITSET
count = width × height
byteLength = ceil(count / 8)
7.2 Descriptor Canonical Float Representation
Descriptor 中:
scale
offset
都是 IEEE-754 binary32 little-endian。
QBV3 deterministic Writer 必须使用 canonical binary32 representation。
特别冻结:
如果某语义要求 offset == 0:
offset MUST = +0.0f
bit-pattern = 0x00000000
不得写:
-0.0f
bit-pattern = 0x80000000
Validity Plane 固定:
scale = +1.0f
bit-pattern = 0x3f800000
offset = +0.0f
bit-pattern = 0x00000000
对于所有 Numeric Plane:
scale MUST finite
scale > 0
offset MUST finite
并冻结全局 canonical zero:
if offset == 0.0 numerically:
bit-pattern MUST = +0.0f
0x00000000
-0.0f
0x80000000
→ MUST reject
该规则不依赖外部 Profile 是否显式声明“offset=0”。
该规则属于 binary canonicalization,目的包括:
byte-for-byte deterministic Writer
CRC 稳定
Content Identity 稳定
跨语言 / 跨平台一致
7.3 Descriptor Byte-level Structural Invariants
为了让 QBV3 Binary Parser 不依赖外部 Profile 名称, 以下机器值与通用结构约束直接属于 Container Version 3。
Value Class
0 = SCALAR
1 = VELOCITY_COMPONENT
2 = DIRECTION_ANGLE
3 = VALIDITY
未知 valueClass:
MUST reject
Component
0 = NONE
1 = U_EAST
2 = V_NORTH
3 = W_UP
未知 component:
MUST reject
Core Unit IDs
QBV3 第一版直接使用:
0 = NONE
1 = MPS
4 = DEGREE
Scalar 的其他 unit ID 可以由外部 Unit Registry 定义; Binary Parser 不因为“不认识某个 Scalar unit ID”而自动判定 corruption。
Core Semantic
Shared Validity 的 frozen core semantic:
VALIDITY semantic = 3
并冻结双向约束:
semantic == 3
⇔ valueClass == VALIDITY
⇔ dtype == BITSET
因此:
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:
semantic = 0
→ reserved / invalid
除 semantic=3 已被冻结为 VALIDITY 外,
其他 Numeric semantic ID 的业务含义由外部 Semantic Registry 决定。
通用组合约束
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:
MUST 有且只有一个 VALIDITY Plane
Binary Parser 不负责验证:
某天气 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 节冻结的:
valueClass
component
core unit
VALIDITY semantic
作为 byte-level structural contract。
外部 Semantic Registry / Unit Registry 可以为:
Scalar semantic
Scalar unit
未来扩展语义
赋予更具体含义,但不得改变 QBV3/version=3 已冻结的 byte-level 解释。
groupId 的 Container 级基本规则:
VELOCITY_COMPONENT → groupId != 0
DIRECTION_ANGLE → groupId = 0
VALIDITY → groupId = 0
SCALAR 的 groupId 是否具有额外业务含义由外部 Profile 决定。
V3 不因为编码变化增加:
if WIND
if WAVE
if RAIN
if CURRENT
等天气业务分支。
9. REQUIRED Flag 与 Binary-valid / Profile-valid 分层
Descriptor flags:
bit0 = REQUIRED
bit1..7 = reserved
在 QBV3 Binary Container 层,Parser 只验证:
flags 的 reserved bits == 0
Descriptor 本身 structurally valid
Plane bytes / semantic / dtype / validity / packing 等满足本文 Binary Contract
QBV3 Binary Container 不根据天气 Profile 名称决定 required Plane 集合。
因此必须区分:
Binary-valid
和:
Profile-valid
9.1 Binary-valid
只由:
QbinV3Decoder
根据本文 normative Binary Contract 判断。
一个 QBV3 文件即使缺少某个产品 Profile 所需 Plane, 只要文件自身 Header / Descriptor / Payload / CRC / Validity / Rice 等合法, 仍可以是:
binary-valid
9.2 Profile-valid
具体:
wind / 2
wave / 2
rain / 2
current / 2
要求哪些 Plane、dtype、scale、offset、unit、group/component, 属于外部 Profile Contract / Registry。
例如一个 binary-valid 文件:
VECTOR_U
VALIDITY
拿 wind / 2 Contract 验证时因为缺失 VECTOR_V:
Profile validation → reject
但不能称为:
QBV3 corruption
9.3 REQUIRED flag 的职责
Descriptor REQUIRED flag 是:
文件内 requirement declaration / mirror
外部 Profile Contract 可以要求:
required Plane 必须存在
对应 Descriptor REQUIRED bit 必须一致
这种一致性属于:
Encoded Field Ingress / Profile Contract Validation
而不是 QBV3 binary parser 对天气业务完整性的判断。
不得在 QbinV3Decoder 内写:
if fieldType == WIND:
require U
require V
也不得让 Binary Decoder 依赖:
NavSea
React
Contract JSON
fieldProfileId
fieldProfileVersion
9.4 QBV3 Quantization Contract 的边界
QBV3 Binary Container 自身承载:
dtype
scale
offset
Parser 必须验证它们满足本文通用 Binary Contract:
dtype 合法
scale / offset finite
canonical float / +0.0
Direction Circular Contract
Validity fixed descriptor
具体 Profile 是否要求:
INT16
scale = 0.1
offset = +0.0
由外部 Profile Contract 决定。
因此:
同一个合法 QBV3 的 byte-level 解释不能依赖 Profile 名称或外部 Contract。
10. Quantization 与编码必须分离
V3 强制区分:
Physical Quantization
和:
Binary Entropy Coding
物理误差只允许来自 Quantization:
physical → quantized integer
以下步骤必须完全可逆:
2D Predictor
ZigZag
Rice
因此:
V3 decode 后的 quantized integer
MUST byte/number-exact 等于 Writer Quantizer 的输出整数
不得在 Rice/Predictor 阶段引入第二次近似。
11. Generic Numeric Quantization
普通非循环 Numeric Plane:
physical = raw × scale + offset
11.1 Quantizer 参数以 Descriptor binary32 为唯一来源
Writer 必须先确定最终要写入 Descriptor 的:
scaleBits : IEEE-754 binary32
offsetBits : IEEE-754 binary32
然后:
scaleF32 = binary32_from_bits(scaleBits)
offsetF32 = binary32_from_bits(offsetBits)
实际 Quantizer 计算必须使用已经序列化确定的 binary32 值,必要时提升为 binary64:
scaleQ = double(scaleF32)
offsetQ = double(offsetF32)
normalized = (physical - offsetQ) / scaleQ
raw = round_half_away_from_zero(normalized)
禁止:
用配置文件中的 decimal 原值
用序列化前更高精度的 double scale / offset
量化完成后再把 scale / offset 截成 float32
原因:
QBV3 的 Quantization 参数必须与文件 Descriptor 中实际携带的 bit-pattern 完全一致。
在“相同 canonical physical input + 相同 Descriptor bit-pattern”的前提下,Writer 必须产生相同 quantized integer。
普通 Writer:
normalized = (physical - offsetQ) / scaleQ
raw = round_half_away_from_zero(normalized)
Validity 必须在 Numeric Quantizer 之前已经确定。
对每个 cell:
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
禁止:
通过 physical 是 NaN / Inf 自动推导 validity = 0
Validity 是独立、权威的 Shared Validity Domain; non-finite numeric payload 不能替代 Validity BITSET。
round_half_away_from_zero(x) 的数学定义冻结为:
if x >= 0:
result = floor(x + 0.5)
else:
result = ceil(x - 0.5)
Quantizer 的规范计算域:
physical : IEEE-754 binary64
scaleQ : exact binary64(double(scaleF32))
offsetQ : exact binary64(double(offsetF32))
规范计算步骤:
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 结果,不得依赖:
host locale
decimal string formatting
host default integer cast rounding
FPU 当前 rounding mode
excess precision / extended register precision
来决定最终 raw integer。
超出逻辑 dtype:
Writer FAIL
禁止:
silent clamp
integer wrap
隐式 modulo
Invalid Cell 不进入 Numeric Rice symbol stream;Decoder materialize 时其 raw 值必须恢复为 0。
12. V3 第一版支持的 Numeric dtype
第一版编码支持:
INT16
UINT16
INT8
UINT8
所有上述 dtype 在进入 Predictor 前转换到至少 int32 运算域。
Predictor residual:
int32
ZigZag 输出:
uint32
FLOAT32 不进入 V3 第一版 Rice Numeric Plane。
需要 FLOAT32 的 Field:
继续使用其他已支持 Container
或未来明确扩展 V3 codec contract
不得私自把 FLOAT32 bytes 当整数 Rice 编码。
13. Shared Validity
V3 第一版继续保留 v4.4 的单 Frame Shared Validity Domain:
semantic = VALIDITY
valueClass = VALIDITY
dtype = BITSET
unit = NONE
groupId = 0
component = NONE
flags = REQUIRED
BITSET:
LSB first
byteLength = ceil(count / 8)
最后 byte 未使用 high bits:
MUST = 0
Validity bit 与 flattened cell index 的对应关系冻结为:
index = row * width + col
byteIndex = index >> 3
bitIndex = index & 7
valid =
(validityBytes[byteIndex] >> bitIndex) & 1
因此每个 byte 内:
bit 0 → 较小 index
bit 7 → 较大 index
即明确的 LSB-first。
一个 Frame 内:
所有 Numeric Plane MUST 共享完全相同 validity domain
不同 validity domain 的数据继续拆成不同 Field/QBIN。
V3 第一版不增加:
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 必须采用两阶段逻辑解析:
1. 解析全部 Header / Descriptor
2. 定位唯一 Shared Validity Plane
3. 完成 CRC / padding / Validity BITSET 校验
4. 读取完整 Validity BITSET
5. 计算每个 Rice block 的 valid symbolCount
6. 再解各 Numeric Plane
因此:
逻辑上 Validity 必须先可用
!=
物理上 Validity 必须排在最前
不得为了 Rice 解码方便而改变 Descriptor canonical order 或 Plane packing order。
14. 2D Spatial Predictor
V3 第一版所有 Numeric Plane 使用同一个二维 predictor。
预测在整个 Grid 的全局坐标上进行,不因 Rice block 边界 reset。
对当前 cell (r,c):
L = (r, c-1)
U = (r-1, c)
UL = (r-1, c-1)
预测规则:
如果 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:
residual = raw(current) - predicted
所有中间计算至少使用:
int32
不得用 int16 中间运算导致 overflow。
Invalid cell:
不产生 Rice symbol
Decoder materialize raw = 0
15. Direction Circular Quantization / Predictor
DIRECTION_ANGLE 继续使用 v4.4 的物理约定:
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 基本约束:
valueClass = DIRECTION_ANGLE
dtype = UINT16
unit = DEGREE
component = NONE
offset = 0
scale > 0
scale finite
15.0 QBV3 Direction Validation Scope
本节只定义:
QBV3 / version=3
自身的 Direction Circular Contract。
QBV3 Parser 对 DIRECTION_ANGLE 必须验证:
dtype = UINT16
unit = DEGREE
component = NONE
groupId = 0
offset = canonical +0.0f
scale = canonical float32(360/N)
rawDirection ∈ [0,N)
QBV2 的 legacy acceptance、共享 Validator 如何重构等兼容实现问题:
不属于 QBV3 Binary ABI
移至 Appendix A。
15.1 Canonical Direction Scale
Direction scale 不使用实现方自行决定的 epsilon / tolerance。 协议直接冻结 canonical float32 计算规则。
Reader / Writer 均定义:
scaleF32 = Descriptor 中 scale 的 IEEE-754 float32 值
ratioToN = 360.0 / double(scaleF32)
在把 ratioToN 转为整数前必须先验证:
ratioToN finite
1 <= ratioToN <= 65536
然后固定:
N = floor(ratioToN + 0.5)
由于 ratioToN > 0,该规则等价于正数域的 round_half_away_from_zero,不依赖 host FPU rounding mode。
必须满足:
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 范围:
rawDirection ∈ [0, N)
合法 Profile 示例:
N = 65536 → scale = float32(360/65536)°
N = 360 → scale = 1°
N = 720 → scale = 0.5°
QBV3 Writer 的 Direction input 必须在进入 Writer 前已经是 canonical:
physicalDirection finite
0 <= physicalDirection < 360
DIRECTION_TO
clockwise positive
True North = 0°
QBV3 Writer 不负责:
FROM → TO 转换
任意角度 wrap
天气 Provider 方向约定修正
这些属于上游 Normalizer。
Writer 使用:
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,禁止:
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 产生的范围,固定参考规则为:
if x < 0:
x = x + N
else if x >= N:
x = x - N
return x
该规则成立是因为输入 raw 均在 [0,N),三邻居 predictor L + U - UL 的结果必定位于:
[-(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:
p = int32(raw(L)) + int32(raw(U)) - int32(raw(UL))
predictedRaw = normalize_direction(p, N)
Fallback:
L valid → predictedRaw = raw(L)
U valid → predictedRaw = raw(U)
否则 → predictedRaw = 0
不得把未经 mod N 规范化的 L + U - UL 直接用于 Direction residual。
15.4 circular_shortest_delta() 精确公式
设:
d = int32(currentRaw) - int32(predictedRaw)
先将差值规范到 [0,N):
m = d
if m < 0:
m = m + N
此时 m ∈ [0,N)。
然后固定:
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 范围:
N 为偶数:[-N/2, N/2)
N 为奇数:[-floor(N/2), floor(N/2)]
Decoder:
x = int32(predictedRaw) + residual
rawDirection = normalize_direction(x, N)
边界 Golden Test 至少覆盖:
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。
精确数学映射冻结为:
zigzag(r):
if r >= 0:
z = 2 * r
else:
z = -2 * r - 1
inverse:
unzigzag(z):
if (z & 1) == 0:
r = z / 2
else:
r = -(z / 2) - 1
示例:
0 → 0
-1 → 1
1 → 2
-2 → 3
2 → 4
...
文档中的位运算表达只用于说明数学关系,不得直接要求 C++ 对 signed integer 执行可能产生 UB / implementation-defined 行为的 shift。
正式 Writer / Decoder 必须冻结:
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, 不得依赖:
signed left shift overflow
signed right shift implementation behavior
host integer width
compiler bitfield layout
Rice remainder mask 也必须使用明确的 unsigned 宽度,例如逻辑上:
uint64_t{1} << k
并保证:
k = 0..31
时不会发生 signed 1 << 31 或非法 shift。
Golden Test 至少覆盖:
0
1
-1
INT16_MIN
INT16_MAX
最大合法 predictor residual
Predictor、ZigZag、Rice 必须完全可逆,不能引入任何新的数值误差。
17. Rice Block Geometry:冻结前候选与最终 ABI
V3 已确定采用:
validity-aware 2D Predictor
→ ZigZag
→ block-adaptive Rice
截至文档 v2.2,Block Geometry 是 QBV3 Version 3 尚未冻结的唯一核心 Binary ABI 参数。
因此:
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 对比。
当前候选:
Candidate A:16×16
Candidate B:32×32
原因:现有 Wind 143 帧实验中,两者编码体积差异约只有:
Rice16 ≈ 43.929 MiB
Rice32 ≈ 43.953 MiB
差约 25 KiB / 143 帧
≈ 175 B / Frame
≈ 0.056%
而 32×32 的 block 数约为 16×16 的 1/4,可能减少:
block metadata
loop / branch 次数
per-block k 搜索次数
因此正式冻结前必须在同一 C++ prototype 中记录:
encoded bytes
decode ms
encode ms
peak temporary bytes
block count
分别比较四类真实数据:
Wind
Rain
Wave
Current
17.0 Block Partition 数学定义
在 Block Geometry 最终冻结前,用参数:
BLOCK_WIDTH
BLOCK_HEIGHT
表示候选尺寸。
定义:
blockCols =
(width + BLOCK_WIDTH - 1) / BLOCK_WIDTH
# integer floor division
blockRows =
(height + BLOCK_HEIGHT - 1) / BLOCK_HEIGHT
对:
br ∈ [0, blockRows)
bc ∈ [0, blockCols)
定义:
rowBegin = br * BLOCK_HEIGHT
rowEnd = min(rowBegin + BLOCK_HEIGHT, height)
colBegin = bc * BLOCK_WIDTH
colEnd = min(colBegin + BLOCK_WIDTH, width)
Block traversal:
for br = 0 .. blockRows-1:
for bc = 0 .. blockCols-1:
process block(br, bc)
等价:
blockIndex = br * blockCols + bc
Block 内:
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 并正式发布:
magic = QBV3
version = 3
选定的 block width / height 就成为 Container V3 ABI 的固定组成部分。
在正式冻结前,测试 Writer / Decoder 可以通过编译参数或测试参数运行 16×16 / 32×32; 测试参数不得写进正式 QBV3 文件,也不得形成两种 production version=3 文件解释。
Block Geometry 未冻结期间产生的实验文件:
不得进入 production Manifest
不得进入正式 CDN / qbin_v3 发布路径
不得被 NavSea production 配置发现或缓存
不得标记为正式 QBV3 Golden Fixture
实验产物必须位于明确的:
/tmp
_runtime
experimental/
或其他非 production 路径
只有 Block Geometry 选定、文档回填唯一尺寸并完成对应 Writer/Decoder round-trip 后,才允许启用 production QBIN_V3 / container_version=3 Manifest。
边缘 block 可以小于正式 block width / height。
Block 顺序:
north → south
west → east
即 block row-major。
Block 内 symbol 顺序:
cell row-major
仅遍历 validity=1 的 cell
如果 block 中没有 valid cell:
该 block 写 0 bytes
如果至少存在一个 valid cell:
1 byte riceK
随后为 Rice bitstream
最后补 0 bit 到 byte boundary
riceK:
uint8
允许范围 0..31
Writer 必须选择使该 block Rice bit 数最小的 k。
Tie:
选择较小 k
保证 deterministic output。
18. Rice Bitstream 精确定义
每个 ZigZag value z:
q = z >> k
r = z & ((1u << k) - 1) # 数学表达;实现使用安全 unsigned width
编码:
1. 写 q 个 0 bit
2. 写 1 个终止 bit
3. 写 k 个 remainder bit
remainder bit 顺序:
Least Significant Bit first
整个 block bitstream 也采用:
LSB-first within each byte
block 最后不足 8 bit:
high unused bits MUST = 0
Decoder 根据 validity mask 可以提前知道该 block 的 symbolCount。
Decoder 必须:
精确解出 symbolCount 个 symbol
然后到达/验证该 block 的 byte boundary
不得依赖 sentinel。
不得读过 Descriptor.byteLength。
在 unary quotient 扫描过程中,Decoder 必须在每次 bit advance 前检查剩余 encoded range; 以下情况全部 fail-closed:
终止 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 的最小/最大值为:
minRaw
maxRaw
在第 14 节 predictor 下,最大可能 residual 绝对值为:
MAX_ABS_RESIDUAL = 2 × (maxRaw - minRaw)
因此:
INT16 / UINT16 → MAX_ABS_RESIDUAL = 131070
INT8 / UINT8 → MAX_ABS_RESIDUAL = 510
对 Direction:
MAX_ABS_RESIDUAL = floor(N / 2)
并遵守第 15 节 half-circle tie 固定负方向规则。
Decoder 可据此得到安全上界:
MAX_ZIGZAG <= 2 × MAX_ABS_RESIDUAL
MAX_Q = MAX_ZIGZAG >> k
在扫描 unary zeros 时,一旦:
q > MAX_Q
即可立即 reject,不必继续扫描到 Plane 尾部。
完成 inverse ZigZag 后仍必须再次验证:
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 为:
z_0, z_1, ... z_(n-1)
对每个候选:
k ∈ [0, 31]
定义纯 Rice symbol bit count:
bits(k) =
Σ_i [ (z_i >> k) + 1 + k ]
其中:
(z_i >> k) = unary zero count q
+1 = unary terminator bit
+k = remainder bits
Writer 必须选择:
k* = argmin bits(k)
如果多个 k 得到相同 bits(k):
选择数值较小的 k
该 k* 属于 Deterministic Writer Contract:
Writer MUST 写入 k*
但 QBV3 Decoder 的 Binary acceptance 不要求重新计算全部 32 个候选 k。
Decoder 对每个 non-empty block 只要求:
0 <= riceK <= 31
bitstream 可在 descriptor.byteLength 内完整解出
symbolCount 精确
padding 合法
residual / reconstructed raw 合法
因此:
riceK != k*
如果其他 Binary Contract 全部合法:
MUST NOT solely cause Decoder reject
也就是说:
最优 k*
= canonical deterministic Writer output
非最优但合法的 riceK
!= QBV3 binary corruption
Decoder MUST NOT 为 canonicality 验证而强制执行:
对已解出的每个 block 再扫描 k=0..31 重算最优 k*
优化目标只计算 Rice symbol bits。
以下固定开销不参与 k 比较:
1-byte riceK
block 尾部补到 byte boundary 的 zero padding
原因是必须冻结与当前编码实验一致的 deterministic 选择语义,避免不同 Writer 分别按:
raw bit count
或:
ceil(bit count / 8)
选择出不同 k。
选定 k* 后,该 non-empty block 的 encoded byte 数:
blockByteLength =
1
+
ceil(bits(k*) / 8)
其中前 1 byte 为 riceK。
19. Numeric Plane Payload
一个 Numeric Plane payload:
Block(0,0)
Block(0,1)
...
Block(last)
Block Geometry 使用第 17 节在正式 ABI freeze 前选定的唯一尺寸。 正式 QBV3 不增加独立 block index table。
原因:
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:
Descriptor.byteLength
严格定义为该 Plane 自身所有 block encoded bytes 的总和。
对每个 block:
validCount == 0
→ block contributes 0 bytes
validCount > 0
→ block contributes:
1 byte riceK
+ ceil(RiceSymbolBits / 8)
因此:
NumericPlane.byteLength =
Σ(non-empty blockByteLength)
byteLength 不包含:
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 第一版正式允许:
validity 全 0
此时:
Validity Plane:
正常 BITSET,全 0
Numeric Plane:
byteLength = 0
Decoder:
不读取 Rice block
直接 materialize 全 0 canonical raw Plane
成立条件必须严格为:
validCount == 0
如果:
validCount > 0
&& numeric byteLength == 0
必须 reject。
all-invalid:
不是 corruption
不需要特殊 codec
不写虚假的 1-byte block
产品层如果不希望发布 all-invalid Frame,可以在 Weather Writer / Product Validation 拒绝, 但 Container 行为必须保持上述确定语义。
20. Plane Packing / Alignment
Descriptor Table 排序继续继承 v4.4:
semantic
→ groupId
→ component
Plane payload 按 Descriptor 顺序排列。
plane[0].byteOffset = 0
plane[n].byteOffset = align16(previousEnd)
payloadLength = align16(lastEnd)
其中:
previousEnd = previous.byteOffset + previous.byteLength
align16(x) = (x + 15) & ~15
Plane 间与尾部 padding:
MUST = 0
区别仅在:
Numeric Plane byteLength
= Rice encoded bytes
Validity:
byteLength = ceil(count/8)
V3 仍要求 canonical minimal packing,不允许额外预留空间。
21. CRC32
QBV3 使用:
CRC-32 / ISO-HDLC
完整参数冻结为:
width = 32
poly = 0x04C11DB7
init = 0xFFFFFFFF
refin = true
refout = true
xorout = 0xFFFFFFFF
check("123456789") = 0xCBF43926
对 reflected 实现,等价使用:
reflected polynomial = 0xEDB88320
与:
zlib.crc32
兼容。
CRC 覆盖完整未经 HTTP Distribution Encoding 的 QBV3 bytes:
Header
Descriptor Table
Payload
Plane padding
Tail padding
计算时:
Header offset 76..79
fileCrc32 的 4 bytes
按 0x00 0x00 0x00 0x00 参与计算
Writer:
1. 先写 fileCrc32 = 0
2. 对完整 QBV3 bytes 计算 CRC
3. 将 uint32 CRC little-endian 写回 offset 76..79
Parser:
读取 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 冻结为:
MAX_PLANE_COUNT = 32
MAX_CELL_COUNT = 2,097,152
MAX_QBIN_BYTES = 64 MiB
MAX_DECODED_BYTES_PER_FRAME = 32 MiB
其中:
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 对超过上述限制的文件:
MUST fail-closed
实现可以额外拥有更严格的本地资源 policy, 但不得把一个超出上述 QBV3 conformance limit 的文件视为 Version 3 合法文件。
未来如果业务确实需要突破任一上限:
MAX_PLANE_COUNT
MAX_CELL_COUNT
MAX_QBIN_BYTES
MAX_DECODED_BYTES_PER_FRAME
不得在已发布 QBV3/version=3 上静默放宽后仍声称 ABI 未改变。
应通过:
新的 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 的结构检查:
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:
actual file bytes
payloadLength
每个 Plane encoded byteLength
所有 offset + length checked arithmetic
并在任何大 Plane allocation 前执行 Decoder 自己负责的 per-frame decoded budget:
decodedNumericPlaneBytes =
checked(count × logical numeric dtype width)
decodedNumericBytes =
checked(sum(decodedNumericPlaneBytes))
decodedValidityBytes =
ceil(count / 8)
decodedFrameBytes =
checked(decodedNumericBytes + decodedValidityBytes)
同一个 canonical Validity BITSET 只计一次。
必须满足:
decodedFrameBytes <= MAX_DECODED_BYTES_PER_FRAME
否则:
fail-closed
QBV3 Binary ABI 只冻结“必须有 per-frame decoded allocation budget 与 checked arithmetic”这一安全要求。
跨多个 retained Frame 的 Store memory policy:
不属于 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。
结构 / length / bounds / budget
↓
CRC32
CRC 失败:
立即 fail-closed
不得先对 CRC 已损坏文件执行 Rice entropy decode。
22.3 Stage C:Canonical Payload / Validity
CRC 通过后再验证 Payload 内容级规则:
Plane / tail padding byte == 0
Validity dtype == BITSET
Validity byteLength == ceil(count/8)
Validity tail unused high bits == 0
随后计算:
validCount
并冻结 all-invalid 对 Numeric Plane 的约束:
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 继续按:
nextOffset = align16(previousEnd)
计算。
因此:
zero-length Plane MAY share byteOffset
with adjacent zero-length Plane
or the next non-empty Plane.
合法示例:
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:
只对实际占用非零 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 验证:
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:
fail-closed
Direction corruption / acceptance 必须额外覆盖:
decoded rawDirection >= N
→ reject
UINT16 dtype range 合法但超出当前 Circular Contract [0,N) 的值不得被接受。
22.5 固定执行顺序
正式 Parser 顺序冻结为:
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:
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:
QBV3 Rice Plane
↓
Rice decode
↓
inverse ZigZag
↓
Predictor reconstruction
↓
logical quantized integer
↓
canonical little-endian fixed-width raw bytes
Canonical raw:
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:
validity = 0
→ canonical decoded raw MUST = 0
Validity reference decoded form:
保持 canonical BITSET bytes
LSB-first
tail unused high bits = 0
bit-exact Round-trip 的权威比较对象:
Writer Quantizer integer grid
+
Writer Validity BITSET
与:
Decoder canonical integer grid
+
Decoder Validity BITSET
必须完全一致。
任何 Runtime-specific:
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 不得根据:
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:
QBV2 → magic "QBV2", version=2
QBV3 → magic "QBV3", version=3
Unknown magic/version combination:
fail-closed
除以上识别规则外,迁移、Store、Runtime、平台实现均不属于 QBV3 Binary ABI。
26. Binary Spec 与消费实现分离
QBV3 Binary Container 只规定:
bytes 如何写
bytes 如何验证
bytes 如何无损恢复 quantized integer grid
NavSea、React、Store、Binding、Renderer、平台 Bridge 等消费方式:
不属于本文 normative Binary ABI
相关背景统一放入 Appendix A。
27. Decoder 实现语言中立
QBV3 不规定 Decoder 必须使用何种语言。
任何 conforming implementation 都必须对同一合法 QBV3 bytes 得到相同:
Header
Descriptor
Validity
canonical quantized integer grid
并对同一 malformed bytes 得到相同 Binary Accept / Reject 结论。
28. Deterministic Writer 与 Container V3 Codec ABI
相同:
Canonical Field
Field Profile Version
Container Version
必须生成:
byte-for-byte identical QBV3
正式 QBV3 / version=3 发布前,必须先完成第 17 节 Block Geometry benchmark 并选择唯一尺寸。
一旦正式发布,下列内容全部成为 Container V3 Binary ABI:
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
不得依赖:
hash/map iteration order
platform endian
compiler bitfield layout
undefined signed overflow / shift behavior
如果正式发布后要改变:
Block Geometry
Predictor
Rice bitstream
bit order
新增第二种内部 codec
不能只修改文档修订号让相同 QBV3/version=3 出现两种解释。
必须:
升级新的 Container Version
或者在新的 Container Version 设计阶段明确引入可识别 codec 字段。 V3 第一版继续保持单一固定 codec,不为未来可能性提前增加 codec switch。
29. Golden Binary Fixtures
正式冻结后至少准备:
Wind
Wave
Rain
Current
四类真实数据的 Golden QBV3 Fixture。
每个 Fixture 至少记录:
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 冻结前允许生成:
experimental/16x16/
experimental/32x32/
两组 benchmark fixture。
最终 Block Geometry 冻结后必须重新生成唯一正式 Golden Fixture 集合。
30. Round-trip 验收
最重要的 Round-trip 先验证整数 bit-exact:
Writer Quantizer output integer array
↓
QBV3 Writer
↓
QBV3 file
↓
C++ QbinV3Decoder
↓
Decoded canonical raw integer array
结果必须:
array_equal == true
不是近似比较。
同时:
validity array_equal == true
invalid cell decoded raw == 0
物理误差测试单独比较:
原始 canonical physical
vs
decoded raw × scale + offset
确保:
Predictor / ZigZag / Rice 不贡献任何额外误差
物理误差只来自 Field Profile Quantization
全量验证阶段建议覆盖全部生成 Frame,而不是只抽样。
Direction 必须包含:
359° ↔ 0°
N-1 ↔ 0
half-circle tie
All-invalid fixture 必须验证:
Validity 全 0
Numeric byteLength = 0
Decoded raw 全 0
zero-length Numeric Plane 可共享 canonical byteOffset
31. Binary Reject / Accept / Writer Validation 验收
本节按职责拆分为三组,避免把:
Binary corruption
Binary canonical-but-unusual input
Writer input validation
混为同一类。
31.1 Binary Reject Cases
以下 malformed / corruption 情况必须:
MUST fail-closed
至少覆盖:
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
以上情况:
QbinV3Decoder
→ reject
31.2 Binary Accept Cases
以下情况本身不得单独导致 Binary reject:
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
特别冻结:
riceK != Writer 最优 k*
如果其余:
riceK range
symbolCount
padding
residual
raw range
descriptor.byteLength
全部合法,则:
MUST NOT solely cause Decoder reject
Decoder 不要求为 canonicality 重新计算:
k = 0..31
的全部候选。
31.3 Writer Validation Cases
以下属于 Writer input / deterministic output 验证, 不是“Decoder corruption”:
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:
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 配置下至少记录:
raw QBV3 bytes
gzip QBV3 bytes(若测试 distribution gzip)
crcMs
entropyDecodeMs
totalDecodeMs
encodeMs
peakTemporaryBytes
decodedFrameBytes
blockCount
nonEmptyBlockCount
Rice k distribution
必须比较:
16×16
vs
32×32
并覆盖:
Wind
Rain
Wave
Current
如果同时比较 QBV2 / QBV3:
CRC 实现必须一致
crcMs 与 entropyDecodeMs 必须分开
不要求 QBV3 entropy decode 比固定宽度 QBV2 decode 更快。
Block Geometry 的选择依据应综合:
encoded bytes
encode CPU
decode CPU
peak temporary memory
实现复杂度
而不是只看压缩率。
32.1 Streaming reconstruction 实现目标
推荐 Decoder:
compressed Plane input
↓
BitReader
↓
逐 symbol Rice decode
↓
inverse ZigZag
↓
立即 Predictor reconstruction
↓
直接写最终 canonical fixed-width raw storage
应避免为了实现方便同时建立多个 full-grid 临时数组:
residual[]
zigzagDecoded[]
predictorOutput[]
rawOutput[]
这是性能实现目标,不改变 QBV3 bitstream。
33. QBV3 第一阶段 Binary ABI 验收基线
正式冻结 / 发布 QBV3/version=3 前至少满足:
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. 版本与命名最终规则
以后统一使用:
QBIN V2
= Container Version 2
= Magic QBV2
= 最终权威设计基线文档 v4.4
QBIN V3
= Container Version 3
= Magic QBV3
= 本文从 Document Revision v1.0 开始;当前修订为 v2.2
禁止再使用:
“QBIN V4”
来代指 Container V2。
如果需要说明历史:
QBIN V2 / v4.4 design baseline
如果需要说明新格式:
QBIN V3
Field Profile Version 独立:
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 必须满足 canonicalfloat32(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:
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. 当前状态与下一步
本文当前状态:
设计冻结候选 v2.2
已经完成:
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 规则
尚未完成:
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
其中:
最终 BLOCK_WIDTH / BLOCK_HEIGHT
是正式发布前唯一仍需通过实测选择的核心 Binary ABI 参数。 其余 Binary 结构与数据语义在 v2.2 中不再保留未决分支。
从 v2.2 起,除非 Prototype / Golden / Corruption Test 证明现有 Binary Contract 存在真实不可实现、不可唯一解释或自相矛盾的问题,否则不得再因实现偏好修改 QBV3 Binary ABI。
在以上实现与验证完成前:
QBIN V2 / v4.4 仍是已实施历史基线
QBIN V3 v2.2 是下一代候选生产格式设计
下一步建议严格按以下顺序:
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。
该规则属于:
QBV2 compatibility
不是 QBV3 Container 规则。
QBV3 只使用正文第 15 节的 canonical Circular Contract。
A.2 ContentIdentity / Runtime Hash
当前项目可为了 QBV2/QBV3 共存,让 decoded Plane 复用既有 runtime identity helper。
这些:
uint64 hash
runtime contentIdentity string
不写入 QBV3 文件,也不参与 QBV3 CRC,因此不是 Container Version 3 ABI。
A.3 Profile Contract
外部 Profile Contract 可以比 QBV3 Binary Parser 更严格,例如校验:
expectedDType
expectedScaleBits
expectedOffsetBits
required Plane 集合
这些属于:
Profile-valid
而不是:
Binary-valid
一个 binary-valid 但 profile-invalid 的 QBV3 文件不应被称为 binary corruption。
A.4 Store / Runtime / NavSea / React / Platform Bridge
以下都不是 QBV3 Binary ABI:
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
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 当前量化误差实验
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 帧既有模型结果:
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 分离。
可以外层发布:
.qbin
.qbin.gz
HTTP Content-Encoding
但解压后必须恢复同一 QBV3 bytes。
Manifest / CDN path / Profile metadata:
不属于 QBV3 Binary ABI