毫米波雷达数据回放与复盘实战课程 - 第2节

一、原始ADC数据格式——从天线到数字的“第一手资料”

做雷达数据回放,第一步就是搞懂原始ADC数据长什么样。说白了,ADC数据就是雷达芯片把天线收到的模拟信号“翻译”成数字后的结果。我刚开始接触毫米波雷达时,拿到一包数据直接懵了——全是16进制数,完全不知道哪个是哪个。

TI的IWR系列芯片,比如IWR6843、IWR1642,输出的原始ADC数据通常是复数形式。为什么呢?因为雷达需要同时知道信号的幅度和相位。幅度决定目标有多“亮”,相位决定目标在哪个方向。

1.1 复数IQ数据的含义

IQ数据,I是In-phase(同相分量),Q是Quadrature(正交分量)。你可以把I想象成信号的“实部”,Q是“虚部”。

一个采样点就是一个复数:sample = I + j*Q

我在项目中遇到过一个问题:某次采集的数据回放时,目标距离总是不对。排查了半天,发现是I和Q的顺序搞反了。嗯,这里要注意——不同芯片的IQ顺序可能不同,TI的芯片通常是I在前、Q在后。

关键点:每个ADC采样点占2个字节(16位),I和Q各占2字节,所以一个复数采样点占4字节。

1.2 数据包结构:Header + Payload

雷达数据不是一股脑儿往外扔的。它像快递一样,有“包裹单”(Header)和“货物”(Payload)。

典型的TI毫米波雷达数据包结构如下:

字段 大小(字节) 说明
Magic Word 8 固定值,用于帧同步,比如0x0102 0304 0506 0708
Version 4 协议版本号
Total Packet Length 4 整个数据包长度(含Header)
Platform 4 芯片型号标识
Frame Number 4 当前帧序号
Subframe Number 4 子帧序号(多帧模式用)
Chirp Margin 4 Chirp起始余量
Num Samples 4 每个Chirp的采样点数
Num Chirps 4 每帧的Chirp数
Num Rx Antennas 4 接收天线数量
Num Tx Antennas 4 发射天线数量
Payload 可变 原始ADC数据(IQ数据)

Header之后紧跟着的就是Payload,里面按顺序排列着所有天线的IQ数据。我习惯先解析Header,确认帧号和数据长度,再读取Payload。这样做的好处是——万一数据丢包了,你能立刻发现。

二、常见雷达芯片的数据输出协议

2.1 TI IWR系列芯片

TI的IWR系列,比如IWR6843、IWR1642,最常用的数据输出接口是LVDS(低压差分信号)。LVDS的好处是速度快、抗干扰强。实际项目中,LVDS数据通过DMM(Debug Message Manager)模块打包成上面说的Header+Payload结构。

TI还提供了DCA1000数据采集卡,专门用来抓取原始ADC数据。DCA1000通过以太网把数据传到PC,数据格式就是标准的LVDS协议包。

我的小技巧:用DCA1000抓数据时,记得设置好采样率和帧周期。我曾经因为采样率设错了,导致回放时目标距离偏移了整整10米——嗯,那天的晚饭都没吃好。

2.2 其他常见芯片

除了TI,还有Infineon、NXP等厂商的毫米波雷达芯片。它们的输出协议大同小异,但细节上有些差异:

  • Infineon:常用SPI或LVDS输出,数据包结构类似,但Magic Word不同
  • NXP:部分芯片支持MIPI CSI-2接口,数据格式更接近摄像头
  • Acconeer:采用UDP直接输出,数据包更轻量

你想想看,不同芯片的协议差异,说白了就是Header里的字段定义不同。只要掌握了TI的协议,其他芯片的协议你花半天就能看懂。

三、数据格式解析实战——手把手教你拆包

光说不练假把式。我们拿一段真实的TI雷达数据来拆解一下。

假设收到一包数据,开头8个字节是:01 02 03 04 05 06 07 08——这就是Magic Word,用来找帧头。

接下来4个字节是Version,比如01 00 00 00表示版本1.0。

再往后4个字节是Total Packet Length,比如00 10 00 00(小端模式,实际长度0x1000=4096字节)。

嗯,这里要注意:TI的数据包是小端模式(Little Endian),低字节在前。我刚开始做解析时,直接按大端读,结果帧号全乱了。

避坑指南:我曾经因为字节序搞错,解析出来的数据全是乱码。后来养成了一个习惯——拿到数据先看Magic Word,确认字节序后再往下解析。

解析Payload时,假设有4个接收天线,每个Chirp采样256点,每帧有128个Chirp。那么一帧的Payload大小就是:

4(天线数) × 256(采样点/Chirp) × 128(Chirp/帧) × 4(字节/复数采样点) = 524,288 字节

数据在Payload中的排列顺序是:

  1. 先按Chirp排列:Chirp 0, Chirp 1, ..., Chirp 127
  2. 每个Chirp内按天线排列:Rx0, Rx1, Rx2, Rx3
  3. 每个天线内按采样点排列:Sample 0, Sample 1, ..., Sample 255

我习惯用Python的struct模块来解析,代码大概长这样:

import struct

def parse_ti_packet(data):
    # 解析Header
    magic = struct.unpack('<Q', data[0:8])[0]
    version = struct.unpack('<I', data[8:12])[0]
    total_len = struct.unpack('<I', data[12:16])[0]
    frame_num = struct.unpack('<I', data[16:20])[0]
    
    # 解析配置信息
    num_samples = struct.unpack('<I', data[32:36])[0]
    num_chirps = struct.unpack('<I', data[36:40])[0]
    num_rx = struct.unpack('<I', data[40:44])[0]
    
    # 解析Payload(IQ数据)
    payload = data[48:]  # Header固定48字节
    iq_data = []
    for i in range(0, len(payload), 4):
        i = struct.unpack('<h', payload[i:i+2])[0]
        q = struct.unpack('<h', payload[i+2:i+4])[0]
        iq_data.append(complex(i, q))
    
    return frame_num, iq_data, num_samples, num_chirps, num_rx

四、知识体系总览

下面这张图,是我自己总结的本章知识结构。你看一眼,心里就有谱了。

毫米波雷达数据格式解析知识体系 原始ADC数据格式 数据包结构 芯片输出协议 复数IQ数据(I + jQ) 16位有符号整数 幅度 + 相位信息 Header(48字节固定) Magic Word + 版本号 帧号 + 配置参数 Payload(IQ数据体) TI IWR系列(LVDS) Infineon(SPI/LVDS) NXP(MIPI CSI-2) Acconeer(UDP) 核心要点: 理解IQ数据 → 掌握Header结构 → 熟悉芯片协议 → 能写解析代码

这张图把本章的核心内容串起来了。从原始ADC数据格式,到数据包结构,再到不同芯片的协议差异。你跟着这个脉络走,就不会迷路。

总结一下:数据格式解析是雷达数据回放的基石。搞懂了IQ数据的含义,掌握了Header+Payload的结构,再熟悉一下TI等芯片的协议,你就能轻松解析任何一包雷达数据。我在实际项目中,靠这套方法解决过不下10次数据解析问题。

可可精品资料库