ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

IWR6843毫米波雷达原始ADC数据采集与MATLAB解析实战

2026/10/3 18:01:35 拓冰建站 浏览量
IWR6843毫米波雷达原始ADC数据采集与MATLAB解析实战 手里有一块 IWR6843ISK想抓点原始 ADC 数据回来自己写处理算法结果发现串口里只有目标点云真正的 I/Q 数据根本出不来——这是很多刚开始碰毫米波雷达的人都会撞上的第一堵墙。DCA1000EVM 就是用来拆这堵墙的它把 IWR6843 的 LVDS 高速接口引出来转成以太网数据最终在电脑上落成一个 bin 文件。可是 bin 文件到手之后真正的麻烦才开始文件里一个 sample 是 I/Q 两个 16 位整数四个 lane 又按 chirp 交织在一起再加上 adcBits、字节序、lane 映射这些细节稍不留意MATLAB 里 reshape 出来的全是噪声。这篇文章我按自己完整跑通一遍的顺序来写从接线、配 IP、mmWave Studio 采集到 bin 文件格式再到一段可以直接跑的 MATLAB 解析代码最后列几个我实际踩过的坑。适合正在用 IWR6843 DCA1000EVM 做开发、或者想拿原始 ADC 数据做距离 FFT / 目标检测 / 4D 雷达算法预研的同学。读完你至少能做到拿到 adc_data.bin 后半小时内用 MATLAB 画出正确的距离谱。1. 动手前先弄清 DCA1000EVM 在信号链里的角色1.1 为什么 IWR6843 不能直接把 ADC 数据吐给 PCIWR6843 是 TI 的 60GHz 毫米波传感器内部有射频前端、ADC、DSP 硬件加速器和 ARM 核。正常跑 demo 时芯片内部会把 ADC 数据一路做距离 FFT、多普勒 FFT、CFAR、角度估计最后只输出目标点云x、y、z、速度。对大多数用户来说这个流程没问题但如果你要做自己的算法比如自定义波形、更复杂的 CFAR、或者用神经网络处理中间特征那就必须拿到 ADC 原始复数数据。IWR6843 支持通过 LVDS 或 CSI-2 接口把原始 ADC 数据导出来。注意这个接口是板上排针形式的不是 USB也不是网口。IWR6843ISK 评估板上有一个 60pin 的连接器但这些高速差分信号没法直接插电脑。DCA1000EVM 干的事就是把这个 LVDS 信号接收下来用板上的 FPGA 做缓冲和打包再通过千兆以太网以 UDP 包的形式发给 PC。PC 端的 mmWave Studio 收到 UDP 数据后统一写成一个 bin 文件。打个比方雷达芯片里的 ADC 是生产线DSP 是质检包装线你平时拿到的点云是已经装箱的成品。DCA1000 相当于在生产线中段开了一扇侧门把半成品——也就是 I/Q 复数数据——提前搬出来给你。这扇侧门不影响正常生产但它能让你看到流水线上最原始的样子。1.2 板卡组合与工具链版本匹配我这里用的是 IWR6843ISK DCA1000EVM 的标准组合。IWR6843 还有 AOP 版本天线集成在封装里采集流程是一样的只是板卡长相不同。连接上需要一根 60pin 板对板连接器排线把 IWR6843ISK 和 DCA1000EVM 连起来一根网线从 DCA1000EVM 的网口连到电脑一根 Micro USB 线给 DCA1000EVM 供电同时它上面的 FTDI 芯片会把 IWR6843 的 UART 也转成 USB 串口供 mmWave Studio 下发配置。工具链上主要三样东西mmWave Studio、mmWave SDK / DFPDevice Firmware Package、DCA1000 固件。我的经验是先确认这三者版本能对上否则会出现 DCA1000 明明连着但 Set Up DCA1000 一直失败的现象。IWR6843 一般需要 mmWave Studio 2.x 以上版本具体小版本按 TI 文档来。别用太老的 mmWave Studio新版本对 DCA1000 的解析逻辑更成熟后面数据格式的坑也少一些。供电问题很容易被忽略DCA1000EVM 由 USB 供电同时还要给 IWR6843 板子供电。建议用电脑后置 USB 口或带屏蔽的 USB 线供电不足时最典型的表现就是固件加载到一半卡住。2. 配好采集环境网络、固件和一次完整 Trigger2.1 PC 网络与 DCA1000 的 IP 设置DCA1000 默认静态 IP 是 192.168.33.30电脑要配成同网段的 192.168.33.1子网掩码 255.255.255.0。步骤不复杂打开 Windows 的网络适配器设置找到连 DCA1000 的那个以太网口双击 IPv4手动填入地址。填完先别急着开 mmWave Studio命令行里 ping 一下ping 192.168.33.30 -t能持续 ping 通说明物理链路和 IP 没问题。如果 ping 不通先看网线插紧没有、网口灯亮不亮再检查是不是 Windows 把网卡识别成了“未识别的网络”并拦了流量。这个阶段我浪费过不少时间最后发现是电脑开了防火墙UDP 端口被挡了导致 mmWave Studio 能连上设备但收不到数据流。建议采集时暂时关闭防火墙或者单独放行 mmWave Studio 和 4096/4098 两个端口。2.2 mmWave Studio 的加载与 SensorConfig 配置打开 mmWave Studio不同版本界面稍有差异但核心步骤是一样的在 Radar Device 下拉框里选择 IWR6843。点击 Connect连接 DCA1000 和雷达板。在 DCA1000 面板里点 Set Up DCA1000工具会把固件烧进 DCA1000 的 FPGA。在 Radar Device 面板里加载 IWR6843 的 demo bin 固件一般从 mmWave SDK 包里能找到 xwr68xx_mmw_demo.bin。加载完点 Reset等待串口输出 ready 信息。在 Sensor Config 标签页里粘贴或加载 chirp 配置。点击 Trigger Frame开始采集。采集完成后默认会在 mmWave Studio 安装目录下的PostProc文件夹里生成adc_data.bin。注意这个文件每次 Trigger 都会被覆盖采集完要立刻改名或拷贝走这是我踩过的最冤枉的坑之一。我常用的一组参数如下后面 MATLAB 代码会严格依赖这些数值参数值说明numSamplesPerChirp128每个 chirp 的 ADC 采样点数numChirpsPerFrame128每帧包含的 chirp 数numFrames1读取的帧数可按需调整numRx4启用的接收通道数numLanes4LVDS lane 数DCA1000 默认 4adcBits16ADC 有效位数常见 12/14/16Fs4e6ADC 采样率4 Mspsslope24.998e12扫频斜率注意单位是 Hz/s2.3 数据端口和绕过 mmWave Studio 的可能性mmWave Studio 和 DCA1000 之间的通信是通过以太网完成的命令走 4096 端口数据流走 4098 端口。DCA1000 把 IWR6843 的 LVDS 数据打包成 UDP 包发给 PCmmWave Studio 负责接收并写入文件。知道这个机制有个好处如果你以后想自动化采集不一定要开 mmWave Studio 的图形界面可以用 DCA1000 的 CLI 工具发命令控制采集甚至在 MATLAB 里直接用udpport监听 4098 端口实时拿数据。不过直接抓 UDP 包需要自己处理 DCA1000 的包格式、包序号、跨包拼接等逻辑复杂度比读文件高一个量级建议先把 bin 文件的路径跑通再考虑这一步。3. 解读 adc_data.binI/Q 交替、lane 交织与文件大小公式3.1 bin 文件里到底存了什么adc_data.bin没有文件头没有分隔符没有帧标识就是一串接一串的 16 位有符号整数。这种设计看起来简单粗暴但它要求你在解析前必须确切知道每一段数据对应什么。在 ADC Data Format 下DCA1000 输出的排列顺序是先帧再 chirp再 lane再 sample。每个 sample 是一个复数点由两个 int16 组成I 在前Q 在后。用文字表示第1个chirp Lane1: sample0_I, sample0_Q, sample1_I, sample1_Q, ... Lane2: sample0_I, sample0_Q, sample1_I, sample1_Q, ... Lane3: ... Lane4: ... 第2个chirp ...默认情况下Lane1 到 Lane4 对应 Rx0 到 Rx3。大多数情况下这个映射是对的但不同 DCA1000 固件版本、不同 mmWave Studio 版本下lane 顺序可能反了所以后面代码里我留了一个重排接口方便你一键调整。3.2 文件大小公式先自检再解析解析前用一个公式做自检能挡掉八成低级问题。文件理论大小为bytes numSamplesPerChirp * numLanes * numChirpsPerFrame * numFrames * 4为什么乘 4因为每个复数 sample 包含 2 字节 I 和 2 字节 Q。拿上面那组参数算128 * 4 * 128 * 1 * 4 65536 字节也就是 64KB。如果你的文件大小和理论值对不上先停下来想几件事是不是 Trigger 过程中 UDP 丢包了是不是 mmWave Studio 还在写文件你就开始读了是不是配置文件里 samples 或 chirps 和我这里写的不一样这个公式还有一个妙用如果文件大小是理论值的整数倍很可能是文件里包含了多帧数据而不是配置错了。比如numFrames1但实际文件大小是理论值的 10 倍那你就把 MATLAB 里的numFrames改成 10 重新解析大概率能直接把所有帧读出来。3.3 adcBits 与 16 位容器的关系IWR6843 的 ADC 有效位数可能是 12、14 或 16 位但 DCA1000 在文件中统一用 16 位有符号整数来存放。如果配置了 12 位实际数值范围只有 -2048 到 2047相当于把一个 16 位容器的高位填了符号扩展低位留空。这种情况下做 FFT峰值位置不受影响但幅度会比 16 位数据小很多信噪比看起来也更差。处理方法很简单读取后左移补位adcBits 12; raw bitshift(int32(raw), 16 - adcBits);左移后幅度范围回到 16 位满量程CFAR 门限才好设。很多教程不提这一点结果用户用 12 位配置采完数据距离谱也能出峰但幅度怎么都不对就开始怀疑天线或硬件。实际上只是有效位数的问题。4. MATLAB 逐行拆解从裸数据到距离 FFT4.1 读取文件与 I/Q 配对下面这段代码可以直接保存成脚本运行。参数区和 mmWave Studio 里的 SensorConfig 保持一致其他地方基本不用改。%% 参数区与 mmWave Studio SensorConfig 一致 fileName adc_data.bin; numSamplesPerChirp 128; numChirpsPerFrame 128; numFrames 1; numRx 4; numLanes 4; adcBits 16; Fs 4e6; % 4 MHz slopeHzPerSec 24.998e12; % Hz/s c 3e8; %% 文件大小自检 info dir(fileName); expectBytes numSamplesPerChirp * numLanes * numChirpsPerFrame * numFrames * 4; if isempty(info) error(找不到 %s请检查文件名和路径, fileName); end if info.bytes ~ expectBytes fprintf(警告实际文件大小 %d 字节理论 %d 字节\n, info.bytes, expectBytes); end %% 读入二进制DCA1000 输出的是有符号 16 位 fid fopen(fileName, rb); raw fread(fid, inf, int16); fclose(fid); % 有效位数不足 16 位时左移补位 if adcBits 16 raw bitshift(int32(raw), 16 - adcBits); end % I/Q 配对奇数索引是 I偶数索引是 Q adcI double(raw(1:2:end)); adcQ double(raw(2:2:end)); adcIQ adcI 1j * adcQ; % 重排为 [samples, rx, chirps] % 默认按 4 lane 顺序对应 4 个 RX adc3D reshape(adcIQ, numSamplesPerChirp, numRx, []); fprintf(adc3D size %d x %d x %d\n, size(adc3D,1), size(adc3D,2), size(adc3D,3));关键点在于fread(fid, inf, int16)这一步。DCA1000 文件里存的就是有符号 16 位补码MATLAB 用int16类型读出来自动就是有符号数省掉了你自己做十六进制转补码的功夫。如果你用uint16读后面还得自己判断最高位是不是符号位纯属给自己找事。4.2 距离 FFT原理与距离轴换算FMCW 雷达发射线性调频信号回波经过目标反射回来后与本地发射信号混频得到一个低频差频信号。这个差频频率 f_b 与目标距离 R 的关系是f_b 2 * R * S / c其中 S 是扫频斜率单位 Hz/sc 是光速。整理一下R f_b * c / (2 * S)所以做距离 FFT 之前只要先把 FFT 的频率轴算出来再乘上系数c / (2 * S)横轴就变成米了。距离 FFT 的完整代码%% 距离 FFT win hann(numSamplesPerChirp, periodic); Nfft 512; rangeData zeros(Nfft, numRx, size(adc3D,3)); for k 1:size(adc3D, 3) for r 1:numRx rangeData(:, r, k) fft(adc3D(:, r, k) .* win, Nfft); end end % 非相干积累对幅度平方做平均再合并 4 个 RX powerAvg sum(abs(rangeData).^2, 3) / size(rangeData, 3); powerCombine sum(powerAvg, 2); % 距离轴 freqRes Fs / Nfft; rangeRes freqRes * c / (2 * slopeHzPerSec); rangeAxis (0 : Nfft/2 - 1) * rangeRes; %% 画图 figure; plot(rangeAxis, mag2db(powerCombine(1:Nfft/2)), LineWidth, 1.2); xlabel(距离 (m)); ylabel(幅度 (dB)); title(Range FFT (4 RX non-coherent integration)); grid on; xlim([0 10]);为什么只取1:Nfft/2因为实信号做 FFT 后频谱是对称的距离维我们只看正频率半轴就够了。至于加窗我习惯用hann(numSamplesPerChirp, periodic)周期性汉宁窗在 FFT 类处理里比较稳妥能压低旁瓣让弱目标更容易被看到。4.3 怎么判断结果对不对用这组参数跑完正常会看到距离谱上有几个明显的峰。我在实验室里放一个金属板用卷尺量大概 2.0 米远距离谱峰值落在 1.93 米附近误差在 10 厘米以内。这个误差主要来自距离分辨率和窗函数主瓣宽度属于正常范围。如果峰出现在 0 距离处大概率是直流偏置也就是天线直漏信号或者环境静态反射太强。可以先把每个 chirp 的时域信号减去均值再进 FFT。如果峰出现在很远的距离、而且形状像噪声先去检查Fs和slope这两个参数有没有抄对尤其是 slope 的单位。如果 4 个 RX 的幅度差异非常大先别急着怀疑硬件看看是不是需要 lane 重排。可以试着把adc3D(:, [4 3 2 1], :)打开再跑一遍很多时候问题就解决了。5. 数据不对时的排查链路与我的实测教训5.1 一套从现象到根因的排查顺序现象优先怀疑处理方式文件大小与理论值不符参数抄错 / UDP 丢包 / 文件被覆盖重新核对 SensorConfig采集后立即改名检查网线距离谱全是平噪声I/Q 配反、lane 映射错、adcBits 没补位先看时域波形再试 lane 重排检查 bitshift距离峰位置整体偏移Fs 或 slope 单位错误把 slope 统一换算成 Hz/s确认 4e6 是 Msps距离峰正确但幅度很小adcBits 配置与实际不符做 bitshift 补位到 16 位4 路 RX 幅度不均lane 映射反序 / RX 未全部打开试 [4 3 2 1] 重排检查 SensorConfig 的 RX 通道使能5.2 距离轴怎么都偏问题出在 slope 的单位上有一次我给一个朋友看脚本他说同样的数据他用另一份代码跑出来目标在 2.3 米我用自己脚本跑出来在 1.7 米。最后排查发现他在 mmWave Studio 界面里看到的 Slope 显示是25.000 MHz/us但脚本里我习惯直接写成25e12Hz/s。MHz/us换算成Hz/s要乘1e12这么一看其实数值是对的真正的问题是他的 SensorConfig 里 slope 实际是24.998e12不是界面显示的整数。这类单位问题在毫米波雷达处理里非常常见尤其是很多人习惯直接抄 mmWave Studio 界面显示的数字没注意界面里有时会省略单位。我的建议是把所有参数都先换算成国际单位写进代码注释再填数值。脚本里宁可多写几行注释也不要靠记忆。5.3 adcBits12 导致幅度异常另一个典型问题是 adcBits。有一次我拿到一批 12 位配置的数据用 16 位方式直接读距离谱也能看到峰但幅度谱整体很低底噪大概在 -40dB 附近目标峰只有 -10dB。当时我一度怀疑是天线增益不够。后来想起来配置里adcBits 12于是把所有 sample 左移 4 位目标峰一下就抬高了将近 24dB检测效果立刻不一样。这个案例提醒我拿到 bin 文件后第一件事不是上算法而是先确认三件事——adcBits 是多少、numLanes 是多少、lane 顺序有没有反转。这三个参数错了后面所有处理都会跟着错。5.4 文件被覆盖和 UDP 丢包adc_data.bin这个文件名是固定的每次 Trigger 都会重新覆盖。我第一次做连续采集实验时跑了 20 组配置结果最后只留下了最后一组数据前面 19 组全部被覆盖当时真的很崩溃。从那以后我养成了一个习惯Trigger 一结束立刻在命令行执行一条 copy 命令把文件按时间戳改名保存。UDP 丢包也是一个隐患。数据量大的时候比如 numChirpsPerFrame 设成 512、连续采几十帧偶尔会出现文件大小比理论值小几个 KB 的情况。原因是 DCA1000 通过 UDP 大数据量发送电脑接收端没来得及处理缓冲区溢出丢包。缓解办法关掉 Windows 防火墙、关闭网卡节能模式、采集过程中不要开着迅雷之类的下载工具。如果是长期做采集建议用带 QoS 的千兆网卡会稳很多。5.5 一个通用探针函数遇到解析结果不对但又不确定是不是 lane 排列问题时先别急着做 FFT。写一个最小探针脚本看第一个 chirp 的 4 路时域波形probe reshape(adcIQ(1:numSamplesPerChirp * numRx), numSamplesPerChirp, numRx); plot(abs(probe)); legend(RX0, RX1, RX2, RX3); xlabel(sample index); ylabel(幅度);如果每路波形都有比较明显的包络起伏说明 lane 排列大概率是对的。如果 4 路波形乱成一团完全看不出任何周期性那就要怀疑 reshape 和 lane 映射。判断数据解析是否正确的终极方法是用已知位置的强反射目标做标定。放一个金属板在已知距离解析后距离谱必须在这个距离附近出现峰。这比盯着波形瞎猜靠谱得多。6. 数据读通之后顺手把速度维 FFT 也做了6.1 从距离谱到距离-多普勒谱读通 adc_data.bin 之后下一步很自然就是做速度维 FFT。距离 FFT 得到的是每个 chirp 的频域数据如果目标在帧内多个连续 chirp 之间发生了微小位移那么每个距离 bin 上的相位会沿着 chirp 维度线性变化这个相位变化的频率就对应目标的多普勒速度。具体做法是在rangeData基础上沿第三个维度再做一次 FFT并做 fftshift 把零频移到中间dopplerWin hann(size(adc3D, 3), periodic); slowFFT fftshift(fft(rangeData .* permute(dopplerWin, [3 2 1]), [], 3), 3);注意这里需要知道 chirp 的重复周期也就是两个 chirp 起点之间的时间间隔才能把多普勒频率换算成速度。每个平台、每套配置的 chirp 周期都可能不同建议先从 SensorConfig 里找chirp cycle time或自己计算。这一步跑通之后你就有了经典的 Range-Doppler Map剩下的 CFAR 检测、角度估计都能在这张图上展开。6.2 想实时处理可以监听 4098 端口如果你的项目最终要做实时处理可以绕开 mmWave Studio直接在 MATLAB 里监听 DCA1000 的数据端口。最小代码是这样的u udpport(IPV4, LocalPort, 4098); data read(u, u.NumBytesAvailable, uint8);但这条路上真正的难点不是 UDP 接收而是要自己还原 DCA1000 的数据包格式包头里有哪些字段、一个 UDP 包装了多少个 sample、跨包时 lane 数据怎么拼接。这部分逻辑 TI 有文档但没有现成开箱即用的 MATLAB 实现需要自己对着抓包工具一点一点调。我的建议是先用文件方式把整套处理流程跑通确认算法逻辑没问题之后再考虑换成实时 UDP 接收否则排错时你会分不清问题是出在网络层还是信号处理层。我自己从第一次打开 adc_data.bin 到能稳定画出距离-多普勒谱图前后花了差不多一周大部分时间不是花在算法上而是花在怀疑数据格式上。回头看卡住我的其实就那么几个点lane 交织顺序、adcBits 补位、slope 单位换算。希望这篇文章能帮你把这一周省下来直接进入毫米波雷达算法开发的正题。