Files
Inbox/系统基座文件/2/2.4/2.4.2 业务数据序列化规范 (Business Data Serialization Specification).md

143 lines
6.1 KiB
Markdown
Raw Normal View History

2025-12-11 07:24:36 +08:00
---
tags: []
date created: 星期一, 十一月 24日 2025, 4:21:43 下午
date modified: 星期一, 十一月 24日 2025, 4:38:46 下午
---
# 2.4.2 业务数据序列化规范 (Business Data Serialization Specification)
## 1. 技术选型基线Protocol Buffers V3
- **基线决策**:继续沿用 **Google Protobuf v3**
- **论证**Protobuf 提供的 **Schema Evolution模式演进** 能力对于雷达这种生命周期长达数年的系统至关重要。它允许我们在未来添加新的字段(如“目标分类置信度”或“干扰源类型”)而不破坏旧版显控软件的兼容性。
## 2. 根消息结构定义 (Root Schema Definition)
基于 **TDP-2.4-DIST**(分布式补丁)和 **ECN-2025-001**(显控扁平化),我们需要对 `04_序列化与网络协议.md` 中定义的 `TrackDataBatch` 进行**重大升级**。
以下是最终确立的 `.proto` 契约:
```Protocol Buffers
syntax = "proto3";
package radar.ipc;
// 2.4.2 核心契约:原子业务数据批次
message TrackDataBatch {
// --- 传输层元数据 ---
// [分布式核心] 站点/阵面唯一标识 (Station ID)
// 必须由配置管理模块注入,用于显控端区分数据源
uint32 station_id = 1;
// [丢包检测] 批次序列号 (单调递增)
// 仅在单个 Station 内连续。显控端需按 StationID 分别统计丢包率。
uint64 batch_sequence_id = 2;
// [完整性] 全链路校验和 (CRC32c)
// 覆盖除本字段外的所有数据。
uint32 checksum = 3;
// --- 业务层元数据 ---
// [时序基准] 数据生成时间戳 (UTC Microseconds)
// 必须基于总控授时校正后的软时钟,严禁使用本地 Uptime。
// 显控端据此进行多站数据的时空对齐。
uint64 timestamp_us = 4;
// [可观测性] 全链路追踪 ID
// 继承自处理该 CPI 数据的 TraceContext
uint64 trace_id = 5;
// [流控状态] 当前节流等级 (反馈给显控端)
// 0=全速, 1=轻微, 2=严重。显控端可据此提示用户"当前数据已降级"。
uint32 throttle_level = 6;
// --- 业务负载 (Atomic Payload) ---
// 确认航迹 (高价值,节流时优先保留)
repeated TrackMessage tracks = 7;
// 原始点迹 (低价值,量大,节流时优先丢弃)
repeated PlotMessage plots = 8;
// 系统状态/心跳信息 (可选,用于带外健康监测)
SystemStatusMessage system_status = 9;
}
// 单个航迹定义 (精简版,详细物理含义见 02_核心数据结构.md)
message TrackMessage {
uint64 track_id = 1;
TrackStatus status = 2; // TENTATIVE, CONFIRMED, COAST, LOST
// 状态向量 (位置+速度)
// 建议统一使用 WGS84 (经纬高) 或 地心笛卡尔坐标 (ECEF)
// 以避免极坐标在分布式融合时的歧义
double pos_x = 3;
double pos_y = 4;
double pos_z = 5;
double vel_x = 6;
double vel_y = 7;
double vel_z = 8;
// 协方差矩阵 (可选,用于高级融合)
repeated float covariance = 9;
}
```
## 3. 序列化策略:原子批次 (Atomic Batch) Vs 微批次 (Micro-batch)
- **旧设计遗留问题**:在之前的设计讨论中(未实施),为了配合“抢占式调度”,曾考虑将一个 CPI 的数据切碎发送。
- **新基线 (ECN-2025-001)**
- **策略****原子批次 (Atomic Batch)**。
- **定义**:一个 Protobuf `TrackDataBatch` 消息 **严格对应一个雷达处理周期 (CPI)** 的所有产出物。
- **行为**`DisplayController` 等待 `DataProcessor` 输出完整的航迹列表后,一次性打包。
- **收益**:显控端逻辑大幅简化。收到一个包,就是一帧完整的态势图,无需处理“半帧”数据或进行复杂的跨包重组。
## 4. C++ 与 Protobuf 的映射效率优化
虽然 Protobuf 很快,但从 C++ `struct TrackData` 到 Protobuf `message TrackMessage` 的转换仍然涉及内存拷贝和遍历。为了在 100Hz+ 的刷新率下不成为瓶颈:
- **预分配 (Reserve)**:在构建 `TrackDataBatch` 时,根据 C++ `vector` 的大小,预先调用 Protobuf 的 `MutableRepeatedPtrField::Reserve()`,避免多次内存重分配。
- **移动语义 (Move Semantics)**Protobuf v3 在 C++ 中支持 `std::move`。如果序列化是在独立的 I/O 线程中进行(见 2.4.1),我们可以考虑直接接管数据所有权,但通常 Protobuf 生成的代码需要 Setter 拷贝。
- _优化技巧_对于包含大量数据的字段如点迹列表如果在 C++ 端也使用了类似 Protobuf 的内存布局(连续内存),可以使用 `Arena Allocation` 或自定义反射来加速,但在本系统中,**简单的字段赋值配合编译器优化(-O3通常已足够不必过度优化**。
## 5. 节流与数据剪裁 (Throttling & Pruning)
基于 **2.3.5 热节流控制**,序列化模块必须实现**内容感知剪裁**
```cpp
void DisplayController::serializeAndSend(const TrackDataPacket& packet) {
radar::ipc::TrackDataBatch pb_batch;
// 1. 填充元数据 (StationID, TraceID, Timestamp…)
// 2. 获取当前节流等级 (通过原子变量读取)
auto level = throttle_level_.load();
pb_batch.set_throttle_level(level);
// 3. 内容剪裁逻辑
if (level < 2) {
// Level 0/1: 发送全量数据
for (const auto& plot : packet.plots) { /* 转换点迹 */ }
}
// 始终发送航迹 (除非 Level 3 暂停)
for (const auto& track : packet.tracks) { /* 转换航迹 */ }
// 4. 序列化并发送
// …
}
```
---
# 总结2.4.2 基线图谱
| **规范项** | **核心基线** | **变更说明 (vs 旧文档)** |
| ------- | ----------------------- | ------------------- |
| **格式** | **Protobuf v3** | 保持不变。 |
| **标识** | **StationID + TraceID** | 新增 StationID 支持分布式。 |
| **时序** | **UTC Timestamp** | 取代本地时间,支持总控同步。 |
| **粒度** | **Atomic CPI Batch** | 废弃微批次,简化接收端逻辑。 |
| **流控** | **内容剪裁 (Pruning)** | 根据节流等级动态丢弃 Plot 字段。 |