4. 原始数据采集:DCA1000数据格式、LVDS接口、数据解析、Bin文件结构
做毫米波雷达开发,第一步就是拿到原始数据。这一步要是搞错了,后面所有算法都是白搭。我见过不少新手,算法仿真跑得飞起,一上硬件就抓瞎——说白了,就是数据格式没吃透。
今天咱们就聊聊DCA1000采集卡、LVDS接口、数据解析,还有那个让人又爱又恨的bin文件。嗯,这里要注意,不同TI芯片的bin文件结构其实有细微差别,我会把通用的规律讲清楚。
4.1 DCA1000是什么?为什么需要它?
DCA1000是TI官方出的数据采集卡。它的作用很简单:把雷达芯片的LVDS信号转成USB或者以太网数据,送到PC上。
你可能会问:雷达芯片自己不是能处理数据吗?为什么还要外挂采集卡?
原因有两个:
- 调试阶段需要看原始数据——芯片内部的DSP处理完就丢了,你根本不知道中间发生了什么
- 算法开发需要大量数据——采集真实场景数据,离线跑算法,调参数
我在项目里遇到过一件事:客户说目标检测不准,我拿DCA1000抓了原始数据一看,原来是ADC饱和了。要是没有原始数据,这种问题根本查不出来。
4.2 LVDS接口——高速数据传输的通道
LVDS全称是Low-Voltage Differential Signaling,低压差分信号。说白了,就是用两根线传一个信号,抗干扰能力强,速率高。
TI的毫米波芯片(比如IWR6843、AWR1843)都支持LVDS输出。典型配置是这样的:
| 参数 | 典型值 | 说明 |
|---|---|---|
| LVDS通道数 | 2或4 | 取决于芯片型号 |
| 数据速率 | 600 Mbps / 通道 | 4通道可达2.4 Gbps |
| 数据格式 | 12位或16位 | I/Q两路交替 |
| 时钟 | 差分时钟 | 与数据同步 |
DCA1000通过FPC排线连接到雷达板,把LVDS信号接收下来,再打包成以太网帧发出去。这个过程是硬件自动完成的,我们只需要关心数据到了PC端怎么解析。
4.3 DCA1000的数据格式——以太网包结构
DCA1000通过千兆以太网发送数据。每个以太网包的结构是这样的:
以太网帧结构:
+------------------+------------------+------------------+
| UDP Header | DCA1000 Header | Raw Data |
| 8 bytes | 36 bytes | 1460 bytes max |
+------------------+------------------+------------------+
DCA1000 Header里包含关键信息:
- Magic Word:固定值0xA5A5,用来校验同步
- Frame Number:帧序号,检查丢包
- Packet Number:包序号,一帧可能拆成多个包
- Data Length:有效数据长度
我建议你在解析时先检查Magic Word。如果不对,说明同步丢了,需要重新开始。这个坑我踩过——有一次网线接触不良,数据全是乱的,程序还在傻傻地解析。
4.4 Bin文件结构——数据存储的格式
DCA1000采集软件(mmWave Studio)会把数据存成.bin文件。这个文件的结构很多人搞不清楚,其实很简单:
Bin文件结构:
+------------------+
| Header (可选) | <-- 有些版本没有
+------------------+
| Frame 0 |
| +-- Chirp 0 |
| +-- Chirp 1 |
| +-- ... |
| +-- Chirp N-1 |
+------------------+
| Frame 1 |
| ... |
+------------------+
| Frame M-1 |
| ... |
+------------------+
每个Chirp的数据排列方式:
- 单通道模式:I0, Q0, I1, Q1, I2, Q2, ...
- 双通道模式:Rx0_I, Rx0_Q, Rx1_I, Rx1_Q, ...
- 四通道模式:四个接收通道交替排列
数据是12位或16位整数,以小端格式存储。嗯,这里要注意:TI的芯片默认是12位ADC,但DCA1000会左对齐成16位,所以解析时按16位读就行。
4.5 数据解析实战——Python代码
下面是我常用的解析代码,你可以直接拿去用:
import numpy as np
import struct
def parse_dca1000_bin(file_path, num_chirps, num_samples, num_rx=4):
"""
解析DCA1000采集的bin文件
参数:
file_path: bin文件路径
num_chirps: 每帧的chirp数
num_samples: 每个chirp的采样点数
num_rx: 接收通道数(1/2/4)
返回:
data: 复数数组,形状为(num_frames, num_chirps, num_rx, num_samples)
"""
# 读取原始二进制数据
raw_data = np.fromfile(file_path, dtype=np.int16)
# 计算每帧需要的采样点数
samples_per_frame = num_chirps * num_rx * num_samples * 2 # 乘以2是因为I/Q
# 计算总帧数
num_frames = len(raw_data) // samples_per_frame
# 重塑数据
data = raw_data[:num_frames * samples_per_frame]
data = data.reshape(num_frames, num_chirps, num_rx, num_samples, 2)
# 合并I/Q为复数
complex_data = data[..., 0] + 1j * data[..., 1]
return complex_data
# 使用示例
if __name__ == '__main__':
# 假设配置:64个chirp,每chirp 256个采样点,4个接收通道
data = parse_dca1000_bin('adc_data.bin', 64, 256, 4)
print(f'数据维度: {data.shape}')
print(f'数据类型: {data.dtype}')
这段代码我用了好几年,基本没出过问题。但要注意:如果你的bin文件有Header,需要先跳过前36个字节。怎么判断有没有Header?看文件大小是不是刚好等于理论值。如果多了36字节,那就是有Header。
4.6 常见问题与调试技巧
在实际采集过程中,你可能会遇到这些问题:
- 数据全是0——检查LVDS连接,或者DCA1000供电是否正常
- 数据有周期性跳变——可能是时钟抖动,检查时钟源
- 帧数不对——检查UDP丢包,可以用Wireshark抓包看看
- I/Q不平衡——这是硬件特性,需要在算法里做校正
我的调试流程:
- 先用mmWave Studio自带的工具采集,确认硬件没问题
- 用上面的Python脚本解析,看数据波形是否正常
- 做一次简单的FFT,看距离维有没有峰值
- 如果都正常,再接入自己的算法流程
你想想看,如果第一步就错了,后面再花哨的算法都是白费功夫。所以数据采集和解析这块,一定要稳扎稳打。
好了,这一章就到这里。下一章我们会聊数据预处理——怎么把原始ADC数据变成我们真正需要的距离-多普勒图。到时候我会分享一些我在项目中用到的滤波和校正技巧,保证实用。