创建仓库
This commit is contained in:
177
关于新版雷达前端通信协议的若干想法.md
Normal file
177
关于新版雷达前端通信协议的若干想法.md
Normal file
@@ -0,0 +1,177 @@
|
||||
---
|
||||
tags: []
|
||||
aliases:
|
||||
- 网络标准是 大端序。 但是考虑到既然大家都在 x86/ARM (Little-Endian) 环境下跑,且为了追求极致性能(减少转换指令),保持主机字节序是雷达内部私有协议的常见做法
|
||||
date created: 星期四, 十二月 4日 2025, 8:34:02 晚上
|
||||
date modified: 星期四, 十二月 4日 2025, 10:22:01 晚上
|
||||
---
|
||||
|
||||
# 网络标准是 大端序。 但是考虑到既然大家都在 x86/ARM (Little-Endian) 环境下跑,且为了追求极致性能(减少转换指令),保持主机字节序是雷达内部私有协议的常见做法
|
||||
|
||||
> 此处 C++ 防御性编程
|
||||
> ```cpp
|
||||
> // 在 protocol_v1.0.h 头部加入
|
||||
> #include <type_traits>
|
||||
>
|
||||
> // C++20 标准检测方式 (推荐)
|
||||
> // static_assert(std::endian::native == std::endian::little, "CRITICAL ERROR: Platform must be Little-Endian!");
|
||||
>
|
||||
> // C++17 兼容检测方式 (针对您的环境)
|
||||
> constexpr bool is_little_endian() {
|
||||
> uint16_t x = 0x0001;
|
||||
> auto p = reinterpret_cast<const uint8_t*>(&x);
|
||||
> return *p == 0x01;
|
||||
> }
|
||||
> static_assert(is_little_endian(), "CRITICAL ERROR: Platform must be Little-Endian according to ICD V0.1 !");
|
||||
> ```
|
||||
|
||||
# 核心议题 1.1:校验算法 (Checksum)——为了工程安全升级为 CRC
|
||||
|
||||
> 升级 (CRC-16-CCITT)
|
||||
> - 2 字节 (末尾)
|
||||
|
||||
# 核心议题 1.3:帧头与对齐 (Header & Alignment)
|
||||
|
||||
- C++ 结构体对齐方式(`#pragma pack(1)` 还是 4 字节对齐?),以及如何统一两种链路的帧头处理。【判断我们的硬件资源倾向于去优化什么?】
|
||||
|
||||
# 巨型帧硬件可能不支持
|
||||
|
||||
> **路径 A:硬件流 - 强制巨型帧 (Jumbo Frames)**
|
||||
>
|
||||
> - **原理**:命令网卡和交换机支持更大的包,将 MTU 设置为 **9000** 字节。
|
||||
>
|
||||
> - **优点**:
|
||||
>
|
||||
> - **极简代码**:C++ 端几乎不需要改动,直接发大包。
|
||||
>
|
||||
> - **极高性能**:CPU 中断次数减少 6 倍(发 1 个大包 vs 发 6 个小包)。
|
||||
>
|
||||
> - **缺点**:
|
||||
>
|
||||
> - **环境依赖**:必须确保**所有**设备(雷达网卡、交换机、服务器网卡)都配置了 MTU 9000。如果中间经过一个不支持 Jumbo 的普通路由器,包会被丢弃。
|
||||
>
|
||||
> - **运维成本**:您提到过您是运维工程师,这意味着每次部署新环境,您都必须手动配置 MTU。
|
||||
>
|
||||
> **路径 B:软件流 - 应用层分片 (Application Layer Slicing)**
|
||||
>
|
||||
> - **原理**:在 C++ 代码里,手动把 16KB 数据切成 1400 字节的小块,给每个小块加一个微型包头(包含:帧 ID、分片序号、总分片数)。接收端收到后再手动拼起来。
|
||||
>
|
||||
> - **优点**:
|
||||
>
|
||||
> - **环境适应性强**:插在任何普通交换机或路由器上都能跑。
|
||||
>
|
||||
> - **抗干扰优化**:如果丢了一个小片,我们可以只重传那个小片(虽然 UDP 实现这个很难,但理论上可行),或者至少我们知道丢了哪一片。
|
||||
>
|
||||
> - **缺点**:
|
||||
>
|
||||
> - **代码极其复杂**:需要编写“分包器”和“重组缓冲区”逻辑,处理乱序到达、超时丢弃等棘手问题。这对开发进度是巨大挑战。
|
||||
|
||||
> 补充防御:预留分片能力 (The Safety Valve)
|
||||
> 虽然我们主推巨型帧,但我建议在定义回波数据包的 C++ 结构体时,**不要把所有空间都写死**。
|
||||
> 在《以太网协议格式》(表 7)中 ,有一个 `参数长度` (2 Bytes) 和 `命令参数` (不定长)。对于回波数据(表 A),虽然它没有显式的“保留字段”,但我建议在设计 `EchoPacket` 结构体时,定义一个**可选的头部结构**,一旦后续需要应用层切片,直接启用即可,无需重构整个通信流程。
|
||||
> *(此动作不改变当前文档,仅在代码层面做防御性设计。)*
|
||||
|
||||
# UDP 可靠性机制 需要在算法上增加其可靠性
|
||||
|
||||
> **决策点**:
|
||||
> - 重发次数定多少?
|
||||
> - 超时时间设为多少(建议 <5ms)?--> 这个根据雷达的设计指标确定。建议不同指令设置不同的时间间隔。
|
||||
> - 控制指令是否需要 QoS 优先标记?必须使用这个作为标注。
|
||||
|
||||
> 综合建议
|
||||
> ```text
|
||||
> 第一级:紧急指令(如"紧急停机")
|
||||
> - 重发次数:1次
|
||||
> - 超时时间:1ms
|
||||
> - QoS:最高优先级(EF)
|
||||
> - 特点:宁可丢包,不可延迟
|
||||
>
|
||||
> 第二级:实时控制指令(如"波束指向")
|
||||
> - 重发次数:2次
|
||||
> - 超时时间:3ms
|
||||
> - QoS:高优先级(AF41)
|
||||
> - 特点:平衡可靠性与实时性
|
||||
>
|
||||
> 第三级:配置与状态指令
|
||||
> - 重发次数:3次
|
||||
> - 超时时间:10ms
|
||||
> - QoS:普通优先级(CS0)
|
||||
> - 特点:保证可靠,允许延迟
|
||||
> ```
|
||||
|
||||
# 指令精度与物理现实—— **DBF???**
|
||||
|
||||
> **传输层**:严格按照 `int16_t` 传输,缩放因子为 `0.0025`。
|
||||
> ```cpp
|
||||
> // 0.0025 度量化 -> 2 Bytes (int16_t)
|
||||
> // Max value: 65.0 / 0.0025 = 26000 (fit in int16_t range ±32767)
|
||||
> int16_t azimuth_raw;
|
||||
>
|
||||
> // 辅助函数 (Helper)
|
||||
> float get_azimuth_deg() const { return azimuth_raw * 0.0025f; }
|
||||
> void set_azimuth_deg(float deg) { azimuth_raw = (int16_t)(deg / 0.0025f); }
|
||||
> ```
|
||||
|
||||
- **混合模型**
|
||||
|
||||
```python
|
||||
class BeamSteeringSimulator:
|
||||
def __init__(self, hardware_type="DBF"):
|
||||
"""
|
||||
硬件类型:
|
||||
- "DBF": 数字波束形成,完美精度
|
||||
- "HighRes": 高精度移相器(10-12位)
|
||||
- "MidRes": 中精度移相器(8位)+抖动
|
||||
- "LowRes": 低精度移相器(6位)+校准
|
||||
"""
|
||||
self.hardware_type = hardware_type
|
||||
|
||||
# 设置不同硬件的精度模型
|
||||
self.models = {
|
||||
"DBF": {"bits": 32, "has_dithering": False, "has_calibration": False},
|
||||
"HighRes": {"bits": 12, "has_dithering": True, "has_calibration": True},
|
||||
"MidRes": {"bits": 8, "has_dithering": True, "has_calibration": True},
|
||||
"LowRes": {"bits": 6, "has_dithering": True, "has_calibration": False}
|
||||
}
|
||||
|
||||
model = self.models[hardware_type]
|
||||
self.min_step = 360.0 / (2**model["bits"])
|
||||
|
||||
if model["has_calibration"]:
|
||||
self.effective_step = self.min_step / 10.0 # 校准提升10倍
|
||||
else:
|
||||
self.effective_step = self.min_step
|
||||
|
||||
self.has_dithering = model["has_dithering"]
|
||||
|
||||
def steer_beam(self, target_angle):
|
||||
# 基础量化
|
||||
base_angle = round(target_angle / self.effective_step) * self.effective_step
|
||||
|
||||
# 相位抖动效果
|
||||
if self.has_dithering and abs(target_angle - base_angle) > 0:
|
||||
# 在两个相邻状态间抖动,获得平均精度
|
||||
next_angle = base_angle + self.effective_step
|
||||
error_to_base = target_angle - base_angle
|
||||
dither_ratio = error_to_base / self.effective_step
|
||||
|
||||
# 实际实现中,抖动是时分的,这里模拟平均效果
|
||||
actual_angle = base_angle * (1 - dither_ratio) + next_angle * dither_ratio
|
||||
else:
|
||||
actual_angle = base_angle
|
||||
|
||||
# 加上微小随机误差(模拟现实不完美)
|
||||
if self.hardware_type != "DBF":
|
||||
random_error = np.random.normal(0, self.effective_step * 0.1)
|
||||
actual_angle += random_error
|
||||
|
||||
return actual_angle
|
||||
|
||||
# 使用示例
|
||||
sim = BeamSteeringSimulator(hardware_type="HighRes")
|
||||
target = 45.0025
|
||||
actual = sim.steer_beam(target)
|
||||
print(f"硬件类型: {sim.hardware_type}")
|
||||
print(f"目标角度: {target:f}°, 实际角度: {actual:f}°")
|
||||
print(f"角度误差: {abs(target-actual):f}°")
|
||||
```
|
||||
Reference in New Issue
Block a user