☰
毫米波雷达IWR6843+DCA1000原始ADC数据解析与距离-多普勒热力图实测
2026/10/3 3:22:06 网站建设 项目流程

第一次把DCA1000EVM和IWR6843连在一起,满心期待点下Trigger,然后打开bin文件——满屏“乱码”。这不是什么新鲜事,几乎所有入门毫米波雷达数据处理的人都会卡在这一步:数据采到了,但不知道怎么解析成能看的距离、速度。这篇文章把整个过程拆开揉碎讲清楚,从硬件链路、mmwave Studio参数配置,到bin文件的字节排列规则,再到一套可以直接跑的MATLAB解析代码,最后用距离-多普勒热力图验证解析是否正确。适合正在用IWR6843做跌倒检测、存在检测、手势识别这类应用的同学参考,也适合刚拿到DCA1000EVM、还没跑通数据流的初学者。

1. 硬件链路与采集准备

1.1 这套系统是怎么工作的

IWR6843是TI的60GHz毫米波雷达传感器,板子上集成了3发4收的天线阵列,内部自带MCU和DSP,可以直接输出目标点云。但如果你要做定制化算法(比如自己写CFAR、做微多普勒分析、做呼吸心跳检测),就需要拿到最原始的ADC数据。这时候问题就来了:IWR6843板载的USB接口默认只能输出处理后的目标级数据,拿不到ADC原始采样。

DCA1000EVM就是来解决这个问题的。它通过LVDS接口连接IWR6843,把雷达前端采样到的中频信号原始I/Q数据搬出来,再通过千兆以太网UDP包发给电脑保存成bin文件。整个数据链路是这样一个走向:

IWR6843射频前端 → ADC采样 → LVDS输出 → DCA1000EVM → 千兆网口 → PC端bin文件

这里有个关键点:DCA1000不负责目标检测,它就是一个“数据搬家工”,把ADCBuf里的原始采样逐bit搬到电脑里。所以数据解析这件事,必须在电脑端用代码自己完成。

1.2 采集前必做的三件事

硬件接线直接影响数据质量,我第一次踩坑就是供电问题。注意三项:

  1. 供电:DCA1000EVM需要独立12V供电,IWR6843通过DCA1000的接口供电,不需要单独接。千万别只插IWR6843的USB就指望DCA1000工作。
  2. 网口直连:用网线直接把DCA1000的网口和电脑网口连起来,不要经过路由器,减少丢包。电脑网卡配置静态IP为192.168.33.30,子网掩码255.255.255.0,DCA1000默认IP是192.168.33.180,确保在同一网段。
  3. 启动顺序:先给DCA1000上电,等指示灯稳定后再打开mmwave Studio,避免上位机识别不到设备。

mmwave Studio里的配置是另一个容易翻车的地方。打开软件后在“mmWave Sensors”里选择IWR6843,进入配置界面。关键参数在“Sensor Config”和“DCA1000”两个模块,其中有几个要注意:

  • Data Mode必须选择LVDS模式(4-bit LVDS),这一步不能漏,否则DCA1000拿不到数据。
  • 每帧chirp数、每chirp采样点数需要和你后面MATLAB代码里的参数严格对应。
  • 配置完记得点“DCA1000 ARM”和“Trigger Frame”,等待采集完成后再点“Save”保存bin文件。

2. bin文件到底长什么样(数据格式拆解)

2.1 文件头怎么跳

用MATLAB打开bin文件后,前几十个字节往往不是我们需要的ADC数据。DCA1000保存的bin文件一般带有一个文件头,常见长度是40字节(20个int16)。不同固件版本可能有差异,有的版本是581字节,有的版本开头有一段Magic Word标识。

一个通用做法是:先用fopen打开文件,读前100个int16转成十六进制看一眼。如果你看到开头几个数像0x7243、0x5A4D、0xA5A5这种规整的Magic Word,说明这些是文件头,直接跳过。如果没有Magic Word、打开就是有规律的连续数据,可能不需要跳过或只需要跳过少量字节。

我在代码里统一按40字节头处理,这是目前大多数固件版本和教程里最常见的格式。如果你用不同版本导出的bin文件解析出来波形不对,优先检查这里。

提示:文件头偏移判断错了,后面的IQ交错、通道顺序全都会错位,而且不容易发现。建议在正式处理前,先打印前几十个采样点确认一下排列规律。

2.2 真正的ADC数据排列

跳过文件头之后,剩下的就是原始ADC采样数据,数据类型是16bit有符号整数(int16)。这里有两个关键概念需要理解:

第一,IQ数据交错。IWR6843内部ADC采样出来的是复数信号,分为I路(同相)和Q路(正交),DCA1000传输时把I和Q交替排列。也就是说每两个int16代表一个复数采样点:第一个是I,第二个是Q。如果配置成实数据模式,才没有这一层交错。

第二,多通道顺序排列。IWR6843有4个接收通道RX1~RX4,在每一个采样时刻,4个通道的数据按顺序排列,排列规律是:

RX1(I) → RX1(Q) → RX2(I) → RX2(Q) → RX3(I) → RX3(Q) → RX4(I) → RX4(Q)

然后才是下一个采样时刻。这个排列方式决定了reshape时每一列是2×numRx个数,而不是别的长度。如果搞错了顺序,距离FFT出来的峰值位置会对不上真实目标位置。

3. MATLAB解析代码与参数计算

3.1 从读取到复信号还原(完整代码)

直接上代码。这个脚本我测试过很多次,按下面的配置参数改一下就能跑通。

%% 参数定义(和mmwave Studio里的配置严格一致) numRx = 4; % 接收通道数 numSamplesPerChirp = 256; % 每个chirp的ADC采样点数 numChirpsPerFrame = 128; % 每帧chirp数量 numFrames = 10; % 采集帧数 numChirpsTotal = numChirpsPerFrame * numFrames; %% 读取bin文件 fileName = 'adc_data.bin'; fp = fopen(fileName, 'rb'); if fp == -1 error('打不开文件,检查路径'); end % 跳过文件头(DCA1000 bin文件常见为40字节) headerLenBytes = 40; Header = fread(fp, headerLenBytes/2, 'int16'); % 读取后丢弃 % 读取剩余ADC数据,int16有符号数 rawData = fread(fp, 'int16'); fclose(fp); fprintf('读取到 %d 个int16数据点\n', length(rawData)); %% 数据长度校验 expectedLen = 2 * numRx * numSamplesPerChirp * numChirpsTotal; if length(rawData) ~= expectedLen warning('数据长度不匹配:实际 %d,预期 %d,请检查参数配置', ... length(rawData), expectedLen); end %% IQ分离与通道重排 % 原始排列: RX1_I, RX1_Q, RX2_I, RX2_Q, RX3_I, RX3_Q, RX4_I, RX4_Q % 先重排成 2*numRx 行 adcIQ = reshape(rawData, 2*numRx, []); % 奇数行是I路,偶数行是Q路 iData = adcIQ(1:2:end, :); qData = adcIQ(2:2:end, :); % 合成复数信号,大小为 numRx x (总采样点数) adcComplex = iData + 1j * qData; %% 按chirp和帧整理 % 每个chirp上面有 numSamplesPerChirp 个复数采样点 % 先reshape:numRx x numSamplesPerChirp x numChirpsTotal adcData = reshape(adcComplex, numRx, numSamplesPerChirp, numChirpsTotal); % 转成 [numSamples x numChirps x numRx],方便后面沿距离维做FFT adcData = permute(adcData, [2 3 1]); fprintf('解析后的复数据矩阵大小:%d x %d x %d\n', size(adcData));

这段代码的核心就三步:读数据、IQ合成、按维度重排。做完这一步你已经拿到了纯正的ADC复数矩阵,剩下的FFT处理都基于这个矩阵。

有一个细节要留意:如果某一帧数据丢失或者以太网UDP丢包,rawData的长度会发生偏差,reshape会直接报错。代码里的长度校验就是用来兜住这种情况的。

3.2 距离/速度分辨率怎么算

解析出复数据之后,下一个步骤是算目标距离和速度,但算之前得先清楚每个FFT bin对应多少距离、多少速度。这几个公式是雷达基础,建议直接抄下来用。

距离维相关的两个关键参数:

  • 距离分辨率:ΔR = c / (2B),其中B是chirp的扫频带宽
  • 最大不模糊距离:Rmax = c·Fs / (2S),其中Fs是ADC采样率,S是chirp斜率

速度维相关的两个关键参数:

  • 速度分辨率:ΔV = λ / (2·Tf),其中Tf是一帧内所有chirp的总时间,λ是载波波长
  • 最大不模糊速度:Vmax = λ / (4·Tc),其中Tc是一个chirp的周期

举个实际例子。60GHz频段载波波长约5mm,假设chirp配置为:斜率S = 50MHz/μs,ADC采样率Fs = 5MHz,每个chirp采256个点,则chirp有效扫频时间约51.2μs,带宽B = 50MHz/μs × 51.2μs = 2.56GHz。

代入公式:

  • ΔR = 3e8 / (2 × 2.56e9) ≈ 0.058m,也就是约5.8cm
  • Rmax = 3e8 × 5e6 / (2 × 50e12) ≈ 15m

这组配置比较适合中短距离目标探测。如果要做更远距离,需要降低斜率或降低采样率,但分辨率会跟着变粗,这是互相制约的关系。

在MATLAB里可以直接写成一个参数计算小块,方便调节配置后自动更新坐标轴刻度。

%% 距离/多普勒坐标轴计算 c0 = 3e8; % 光速 fc = 60e9; % 起始频率 lambda = c0 / fc; % 波长约0.005m Fs = 5e6; % ADC采样率,根据mmwave Studio配置改 slope = 50e12; % 斜率,注意单位:MHz/us需要转成Hz/s B = slope * numSamplesPerChirp / Fs; rangeRes = c0 / (2 * B); % 距离分辨率 maxRange = c0 * Fs / (2 * slope); rangeAxis = (0 : numSamplesPerChirp-1) * rangeRes; Tc = 80e-6; % chirp周期,单位秒 speedRes = lambda / (2 * numChirpsPerFrame * Tc); maxSpeed = lambda / (4 * Tc); dopplerAxis = linspace(-maxSpeed, maxSpeed, numChirpsPerFrame);

3.3 校验解析是否正确的小技巧

数据解析完成后,先别急着上复杂算法,用最直观的方式验证:对准一个静止目标(比如一面墙、一个人站着不动),做距离FFT,在0多普勒附近应该出现一个明显峰值,峰值对应的距离要和实际距离基本吻合。

具体做法:取一帧数据,对每个chirp做距离维FFT,取平均幅度,然后找到最大峰位置,算一下对应距离。

%% 快速校验:单帧距离FFT frameIdx = 1; % 取第1帧 startIdx = (frameIdx-1) * numChirpsPerFrame + 1; endIdx = frameIdx * numChirpsPerFrame; % 取一帧数据: numSamples x numChirps x numRx frameData = adcData(:, startIdx:endIdx, :); frameData = mean(frameData, 3); % 4个RX通道平均 % 距离维FFT rangeFFT = fft(frameData, 256, 1); rangeProfile = abs(rangeFFT(1:128, :)); meanProfile = mean(rangeProfile, 2); % 找峰值 [~, idx] = max(meanProfile); estimatedRange = (idx - 1) * rangeRes; fprintf('最强目标距离约 %.2f m\n', estimatedRange);

如果这个距离值和实际完全对不上,大概率是三个原因:数字上变频方向的顺序搞反了、IQ分离时奇偶取反了、或者文件头没跳干净。这属于解析层的问题,跟后处理的FFT算法无关,先把这里的值调对了再往下走。

4. 距离-多普勒热力图与目标初检

4.1 一维距离FFT与静态杂波抑制

验证了解析没问题,接下来就可以做完整的距离-多普勒二维处理了。先做距离维FFT,这一步把每个chirp时域采样转换成距离维频率谱。

%% 距离维FFT NfftRange = 256; % 距离FFT点数,一般取2的整数次幂 rangeFFT = fft(adcData, NfftRange, 1); % 沿第1维(采样点维)做FFT % 取单边谱(正频率部分) rangeFFT = rangeFFT(1:NfftRange/2, :, :);

这里要注意一个点:静止目标和运动目标在距离维FFT之后都会出现峰,如果室内场景有墙、桌子这些静止物体,它们的能量会非常强,把运动目标完全淹没。所以需要做一个静态杂波抑制操作,常用做法是沿着chirp维减去平均值。

原理很简单:静止目标在帧内的所有chirp上幅度相位基本不变,对所有chirp取平均就近似等于静止杂波,每个chirp减去这个均值,静止目标就基本被干掉了,动态目标则保留下来。

%% 静态杂波抑制(MTI平均相消) rangeFFT = rangeFFT - mean(rangeFFT, 2); % 按chirp维减均值,广播到所有chirp

这个操作对呼吸心跳检测、微动目标检测特别重要。做存在检测时如果目标走动,这一步能显著提升后续检测概率。

4.2 二维多普勒FFT与热力图绘制

距离维处理完,继续沿chirp维做多普勒FFT,得到距离-多普勒图。多普勒维表示目标的径向速度信息,正速度表示朝雷达靠近,负速度表示远离。

%% 多普勒维FFT NfftDop = 128; % 多普勒FFT点数 dopplerFFT = fftshift(fft(rangeFFT, NfftDop, 2), 2); dopplerMap = abs(dopplerFFT); % 4个RX通道非相干累加,提升信噪比 map2D = squeeze(mean(dopplerMap, 3)); %% 绘制距离-多普勒热力图 figure; imagesc(rangeAxis, dopplerAxis, 10*log10(map2D + eps)); xlabel('距离 (m)'); ylabel('速度 (m/s)'); title('距离-多普勒热力图'); colorbar; axis xy;

画出来的热力图里,静止目标会出现在0速度附近那条线上;运动的行人会出现一个亮斑,横轴位置是距离,纵轴位置是速度。行的速度约1~2m/s,跑步约3~5m/s,你可以根据纵轴位置大致判断目标运动状态。

这里解释一下两个函数的用途:fftshift是把零频移到频谱中间,方便显示正负速度;距离维FFT用的是单边谱,所以不需要fftshift。

如果后续要做到自动目标检测,可以在距离-多普勒图上做CFAR检测。常用的有CA-CFAR、OS-CFAR等,二维CFAR相对复杂一点,我后面专门写一篇展开讲,这里先用热力图人工观察验证整条数据链路是否正常。

5. 常见问题与踩坑实录

5.1 数据长度对不上、全零、错位怎么办

做数据解析最烦的就是错误不报在明面上,而是悄悄给一个错误结果。我把实际操作中遇到的问题整理成了表格,方便快速对照排查。

现象可能原因解决办法
reshape报错,数据长度对不上每帧chirp数、采样点数配置和代码不一致打印实际数据长度,核对mmwave Studio里的配置,尤其注意帧数是否按预期采完
数据全是0或大量重复值LVDS接线松动、DCA1000未正确ARM检查硬件连接,重新在mmwave Studio里执行ARM再Trigger
距离FFT峰值位置不对文件头跳过字节数不对、IQ奇偶取反打印文件头部十六进制,确认偏移量;交换I/Q顺序测试
热力图0速度处有超强信号且不衰减正常现象,是墙面等静止杂波做静态杂波抑制后观察动态目标
数据有偶发跳变,幅度异常以太网UDP丢包使用千兆网卡、直连网线、关闭网卡节能模式、采集时避免其他大流量
解析结果多普勒速度正负反了距离FFT相位方向理解偏差这通常是符号习惯问题,确认配置中的频率上升/下降斜率,速度轴向整体取反即可

采样点数和chirp数对不上是我遇到最多的问题。记得一次采集200帧数据,mmwave Studio里的“Frame count”设置成200,但实际Save只保存了187帧,导致reshape一直报错。后来发现是丢包导致的,降低采样率后问题就消失了。

5.2 大数据量下MATLAB卡死/内存不足的优化

当每帧chirp多、帧数也大的时候,一次把整个bin读进内存很容易爆内存。比如IWR6843配置256个采样点、每帧256个chirp、采1000帧,4通道IQ模式下数据量大概有2GB,直接fread会造成系统卡顿甚至OOM。

我常用的优化方式是改用memmapfile逐帧处理,不需要一次性把整个文件都读进内存。核心思路是把bin文件映射成内存映射数组,按帧切好,一帧一帧做FFT,结果只保留最终的距离-多普勒图或者检测结果。

%% 使用memmapfile逐帧读取示例 % 定义每帧的int16数量 frameSamples = 2 * numRx * numSamplesPerChirp * numChirpsPerFrame; m = memmapfile('adc_data.bin', 'Format', 'int16', ... 'Offset', headerLenBytes, 'Repeat', inf); allData = m.Data; numTotalFrames = floor(length(allData) / frameSamples); for frameIdx = 1:numTotalFrames frameRange = (frameIdx-1)*frameSamples + 1 : frameIdx*frameSamples; rawFrame = allData(frameRange); % 这里放入IQ分离、FFT等处理逻辑 end

注意memmapfile的Offset参数只能按字节算,这里传入的是40字节的headerLenBytes。如果文件名路径里有中文,部分老版本MATLAB可能识别不了,建议路径保持英文。

另外还有一个性能细节:MATLAB的fft在多通道大矩阵上支持直接沿指定维度计算,不要用for循环逐个chirp做FFT,向量化写法快几十倍。上面代码里fft(rangeFFT, NfftRange, 1)就是一次把全帧所有chirp、所有通道的距离FFT都算了,这种写法要养成习惯。

5.3 我对这套链路的使用体会

用这套DCA1000EVM加IWR6843的方案做数据采集和算法验证,整体体验是:硬件链路稳定,数据质量在60GHz频段传感器里算相当不错的,难点不在采,而在后面解析和标注那一大堆脏活。

我个人的建议是,采集数据时养成一个好习惯:每次实验把mmwave Studio里的完整配置截图或存成txt,同时在代码里把采样率、斜率、chirp数等参数以注释形式写在脚本头部。否则三个月后回来看数据,你根本不知道当初这组bin文件是用什么参数采的,等于废数据。

数据解析完之后的扩展空间很大。你已经拿到了距离-多普勒-角度三维复数数据,后面可以做恒虚警检测、多目标跟踪、微多普勒分类、甚至用深度学习做手势识别。解析只是起点,但这一步走稳了,后面的路就顺了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询