ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

基于A100 ADC数据的MATLAB雷达信号处理与双实现验证

基于A100 ADC数据的MATLAB雷达信号处理与双实现验证 SuperRadar社区的共建项目里我最近一直在跟进温州大学张陈峰的一个工作——基于 A100 ADC 数据用 MATLAB 做雷达信号处理最后再做一轮“双实现验证”。这个工作的价值在于它没有停留在跑通一个仿真而是把实际采集来的 ADC 原始数据完整走了一遍测距、测速、测角的处理链路并且用两套独立实现互相印证把结果偏差控制在了可解释的范围内。无论你是刚开始接触雷达信号处理的学生还是已经在做毫米波雷达产品开发的工程师这个案例都有不少值得直接抄作业的地方。我先说下文章会涉及的内容A100 ADC 数据怎么解析进 MATLAB距离维 FFT、多普勒维 FFT、CFAR 检测、角度估计的关键参数怎么选以及“双实现验证”到底是怎么做的——说白了就是“一套算法两种数据来源互相校验”。最后会把我在实测中遇到的各种坑和排查思路一并整理出来。1. 项目背景与核心思路SuperRadar社区为什么要“公开 ADC 数据”1.1 SuperRadar社区在解决什么问题SuperRadar 是一个偏开源的雷达技术社区聚集了高校学生、雷达爱好者、算法工程师和少量做硬件的人。社区的核心逻辑很简单如果大家手里都有不同型号的雷达设备把采集到的原始数据尤其是 ADC 级数据脱敏后上传共享那所有人就都能在真实数据上验证自己的算法而不是各自闷头用理想仿真跑一跑就发结论。真实数据的价值怎么强调都不过分。仿真信号曲线再光滑也模拟不了真实环境里的多径反射、电源纹波干扰、目标起伏、通道幅相不一致这些“脏”因素。ADC 原始数据又是雷达数据链路里最底层的一环它比点云数据保留了更多信息你可以自己决定做多深的信号处理也可以反复尝试不同的检测算法。在这类社区里数据共享得越多算法验证就越扎实。1.2 为什么选 A100 ADC 原始数据作为切入点A100 属于性价比比较高的雷达模组在社区里的保有量不小它的一个特点是可以通过特定固件或接口把 ADC 原始数据导出来而不是只输出处理好的点云或目标列表。这一点非常关键因为很多商业雷达模组只开放“结果”不开放“过程”这就导致用户没法自己改进内部算法。A100 能输出 ADC 数据相当于给了开发者一把直接深入雷达信号链路底层的钥匙。我在类似项目里最常用的套路是先用设备收集几组典型场景的 ADC 数据比如停车场单车位、道路边两个行人交错、空房间静态背景然后把这些数据标注好真值真距、真速度、真角度打包开放出来。这样大家做出来的算法结果好不好一对比就有结论。张陈峰这次做的事情就是在这些真实 ADC 数据的基础上用 MATLAB 把完整处理链路跑通并且用“仿真 实测”两条路互相验证。1.3 “双实现验证”到底验证了什么“双实现验证”这个说法听起来有点抽象实际落地是这样两个链路第一实现写一个回波仿真器按照 A100 的参数生成理想的 ADC 回波数据内部包含已知位置、已知速度的目标然后跑同一套 MATLAB 信号处理代码。第二实现读取 A100 真实采集的 ADC 数据跑完全相同的处理代码。思路就是如果算法在理想仿真的条件下测距测速都准确说明算法逻辑本身没有原理性问题如果同一套算法在真实数据上也能稳定检测到目标并且和真值误差在合理范围内说明这条链路在工程上是可用的。两者一对照既能定位算法缺陷也能暴露数据质量问题这就是“双实现”的意义所在。为什么不只做其中一路因为只做仿真你验证的是“算法没错”不是“数据能用”只做实测一旦结果不对你也分不清是算法问题还是数据采集的问题。两条路一起跑相互印证才能比较快定位差异源头。2. A100 ADC 数据工程化读取MATLAB 从文件到矩阵2.1 A100 ADC 数据的基本组织方式在做信号处理之前首先要面对的是“怎么把二进制文件读成能运算的矩阵”。A100 的 ADC 数据从我处理过的同类设备经验来看一般按照帧frame为单位存储每一帧里包含若干个 chirp每个 chirp 又包含多个接收通道channel的采样点每个采样点通常是复数 IQ 的形式量化位宽常见 12bit 或 16bit。这里直接给出一个典型的组织顺序方便理解Frame - Chirp - Channel - Sample比如一个默认的配置可能是单帧 128 个 chirp4 个接收通道每个 chirp 采集 256 个采样点。那么一帧的复数采样点数量就是128 × 4 × 256 131072 个复数点如果每个复数点用两个 int16 表示I 路和 Q 路各一个那么单帧的原始字节数就是131072 × 2 × 2 524288 字节 ≈ 512 KB这个估算很重要因为在 MATLAB 里一次性读入几百 MB 甚至几个 GB 的 ADC 文件时内存占用直接取决于你对数据维度的理解是否准确。维度搞错了后面的 reshape 和 permute 全部会乱。2.2 MATLAB 读数与维度变换读取这种固定格式的二进制数据首选是fread而不是 textscan 或 readmatrix。fread 可以直接指定精度和字节序效率很高。一个常用的读取模板如下% 配置参数实际值以A100数据文档为准 nChirp 128; % 每帧chirp数 nChan 4; % 接收通道数 nSample 256; % 每个chirp采样点数 frameNum 1; % 要读取的帧数 % 先只读一帧 fid fopen(adc_data.bin,rb); raw fread(fid, nChirp*nChan*nSample*2, *int16); fclose(fid); % 拆成I/Q iq complex(raw(1:2:end), raw(2:2:end)); % 变换维度sample x chirp x channel adc reshape(iq, [nSample, nChirp, nChan]); adc permute(adc, [1 2 3]); % 实际存储顺序按设备文档调整这里最容易出错的是 IQ 交织顺序和维度顺序。有的设备存储是“先 Q 后 I”有的设备是“按 sample 连续存储、通道在最后”你需要对照数据采集端的输出格式确认。我在处理时有一个很土但有效的办法先用已知雷达参数做一次发射功率较强的单目标测试然后分别尝试两种 IQ 顺序、几种 reshape 排列看哪一组能得出明显的峰值那组参数就是对的。这比反复看文档更直接。2.3 数据预处理直流偏置、通道校准与 IQ 不平衡ADC 数据读出来之后不能直接做 FFT。真实数据里经常存在几个问题直流偏置、通道幅相不一致、IQ 不平衡。直流偏置的来源是 ADC 自身的偏置电压和混频器泄漏。反映在频域上就是零频附近的巨大尖峰会压制近距离目标的信号。解决方式很简单对每个通道的时域数据做平均然后减掉这个均值adc adc - mean(adc, [1 2]);通道幅相不一致主要影响角度估计。4 个接收通道如果幅相响应不一样数字波束形成出来的角度谱会产生偏移。工程上可以在设备出厂前做一次校准或者在每次测量前放一个已知角度的强目标用这个目标来估计通道间的相对相位差然后做补偿% 以第一个通道为参考估计各通道相对相位 ref adc(:, :, 1); for ch 2:nChan % 用互相关或单频点估计相位差 phaseDiff(ch) angle(sum(ref .* conj(adc(:, :, ch)), all)); end % 补偿 adc(:, :, ch) adc(:, :, ch) .* exp(-1j * phaseDiff(ch));IQ 不平衡则表现为中频信号的镜像频率上出现一个虚像峰一般可以通过校准矩阵或只使用上边带/下边带的方法缓解。如果镜像峰和目标峰分得足够开也可以在频域做简单的滤波剔除。2.4 预处理经验补充预处理阶段还有个容易忽略的细节ADC 数据漂移。长时间采集时因为温漂和供电波动ADC 的直流偏置会缓慢变化。用整段数据的全局均值去减不一定有效。我在处理这类数据时通常会按帧或按一小段时间窗做局部去直流而不是一次减掉全文件均值。这样对近距离目标和静态目标更友好避免目标被淹没在低频漂移里。另外如果数据文件里带时间戳或帧头信息建议先用 Python 或者 MATLAB 写一个小工具把数据按帧切好标好时间戳再进入信号处理流程。这样后面做多帧目标跟踪或者速度连续性校核时会省很多事。虽然这一步看起来“不算法”但实测下来对后续调试帮助极大。3. 雷达信号处理链路距离、速度、角度依次解读3.1 距离维 FFT从时域到距离A100 这类调频连续波FMCW雷达发射信号频率随时间线性变化。目标回波与发射信号混频后得到的中频信号频率正比于目标距离。所以距离维的处理通常就是沿“快时间”方向做 FFT。距离分辨率由扫频带宽决定d_res c / (2 * B)如果 A100 的扫频带宽 B 为 1 GHz 左右那么距离分辨率约为 0.15 m。采样率 fs 决定最大不模糊距离R_max fs * c / (2 * S)其中 S 是调频斜率。这里有个普遍容易犯的错把采样率、带宽、调频斜率这些参数直接抄数据手册但实际设备配置可能因为帧率、chirp 设计不同而发生变化。我在做 MATLAB 处理时会先尝试从数据本身反推这些参数比如找一个已知位置的角反目标看它的峰落在哪个距离 bin 上再反推 S 或 fs 是否符合预期。MATLAB 里做距离维 FFT 可以直接nfftR 256; % 一般与采样点数相同 rangeFFT fft(adc, nfftR, 1); rangeFFT fftshift(rangeFFT, 1); % 有时设备是复数采样不需要shift需要说明的是复数采样时 FFT 结果通常不需要 fftshift直接第 1 个 bin 就是零频而实数采样时零频在中间需要 shift。这里必须和设备给出的数据格式对应起来。3.2 多普勒维 FFT速度怎么算出来速度维的处理沿“慢时间”方向做第二次 FFT。同一距离 bin 上不同 chirp 之间因为目标运动会引入一个相位变化这个相位变化的速率对应多普勒频率从而换算成速度。速度分辨率由总的 chirp 序列时长决定v_res lambda / (2 * N_chirp * T_chirp)最大不模糊速度v_max lambda / (4 * T_chirp)假设 A100 工作在 24 GHz波长 lambda 约 0.0125 mchirp 周期 T_chirp 约 80 us128 个 chirp 时速度分辨率约为 0.61 m/s最大不模糊速度约为 39 m/s。这个量级对室内行人、低速车辆场景是够用的。MATLAB 里做二维 FFT 也很直接rdFFT fft(rangeFFT, nfftD, 2); % 沿慢时间FFT rdFFT fftshift(rdFFT, 2); % 多普勒维一般需要shift rdMap abs(rdFFT); rdMapLog 20*log10(rdMap eps);这里有个细节在速度维做 FFT 之前通常先做静态杂波抑制。否则墙面、地面等静态反射体会在多普勒零频处形成一条亮线把运动目标的峰值掩盖。最简单的办法是让每个距离 bin 减去该 bin 在所有 chirp 上的均值相当于一个高通滤波器。% 沿多普勒维去均值 rangeFFT rangeFFT - mean(rangeFFT, 2);3.3 目标检测与角度估计距离-多普勒图出来后下一步是目标检测。常用的有 CA-CFAR、OS-CFARMATLAB 的 Phased Array System Toolbox 里提供了phased.CFARDetector2D可以直接用。关键参数包括训练单元数、保护单元数和虚警概率。以一维 CFAR 为例CA-CFAR 的原理是在目标单元两侧各取若干训练单元估计背景噪声功率然后用一个系数乘上噪声功率得到检测门限。系数由虚警概率和训练单元数决定alpha N_train * (P_fa^(-1/N_train) - 1)其中 N_train 是训练单元总数。这个公式在做 CFAR 参数设计时非常有用不要只靠试。角度估计则在检测到目标后提取目标所在的距离-多普勒单元的通道数据再做数字波束形成DBF或超分辨算法。DBF 的本质是让阵列对不同方向做相位补偿然后看哪个方向能量最大thetaScan -60:0.5:60; for k 1:length(thetaScan) steering exp(1j * 2*pi*d_spacing/lambda * (0:nChan-1) * sind(thetaScan(k))); p(k) abs(steering * targetVec)^2; end [~, idx] max(p); angleEst thetaScan(idx);阵元间距 d_spacing 如果大于半波长会出现栅瓣测角会出错。这一点在角度估计里几乎排第一重要。3.4 参数选择的背后逻辑很多刚入门的朋友喜欢上来就“调参”但不知道每个参数为什么这么设。这里我强调一个思路先算再试。所有窗函数、FFT 点数、CFAR 训练单元都应该先根据系统指标算出一个大致范围再来回微调。比如速度分辨率不够那意味着总时长需要增加就应该调整 chirp 数和 chirp 周期而不是单纯加大 FFT 补零点。补零只能让频谱显示更密但并不能提升真实分辨率。这一点在博文里反复讲都不为过。另外距离维加窗是一项常规操作用来压低旁瓣。Hamming 窗或 Hann 窗可以让旁瓣降到 -40 dB 左右代价是距离分辨率略降。如果你要在强目标旁边检测弱目标旁瓣抑制就比分辨率重要得多。4. 双实现验证仿真回放与真实数据比对4.1 第一实现模型仿真链路搭建仿真链路的目的是“用已知答案验证算法”。我先根据 A100 的参数构造一个理想点目标的中频回波。目标距离 R、速度 v回波模型可以简化为S 带宽 / chirp时长; % 调频斜率 tc (0:nSample-1)/fs; % 快时间 for chirpIdx 1:nChirp tau 2*(R v*(chirpIdx-1)*T_chirp v*tc)/c; ifData(:, chirpIdx) exp(1j*2*pi*S*tau.*tc); % 简化混频结果 end这里需要注意真正的 FMCW 回波还要考虑幅度衰减、相位噪声、多目标叠加。但既然是“第一实现”目标就是验证信号处理流程是否跑得通所以把模型做简单一点反而更容易定位问题。我在这个环节一般会设置三个目标一个静止、一个 5 m/s 匀速运动、一个 -3 m/s 反向运动位置分别放在 2.5 m、8.2 m、15.7 m。仿真数据生成后直接调用第二实现里那套 MATLAB 处理函数。理想情况下测距结果应该和目标真值完全落在同一个距离 bin 或相邻 bin速度估计误差在速度分辨率以内。4.2 第二实现真实 A100 数据链路搭建真实数据链路跑的是从社区下载或设备采回的 A100 ADC 文件。第一步还是数据解析用第 2 节的方法把二进制文件组装成adc复数矩阵。然后按“距离 FFT - 静态杂波抑制 - 多普勒 FFT - CFAR - 角度估计”的流程完整跑一遍。实际处理时我会把处理流程封装成一个函数输入是adc矩阵输出是检测目标列表距离、速度、角度、信噪比。这样仿真和实测用的是完全相同的代码路径避免“两套代码分别实现”带来的额外误差。function targets processADC(adc, params) rangeFFT fft(adc, params.nfftR, 1); rangeFFT rangeFFT - mean(rangeFFT, 2); rdFFT fftshift(fft(rangeFFT, params.nfftD, 2), 2); detMap cfar2D(abs(rdFFT), params); [detR, detD] find(detMap); % 角度估计... end4.3 结果对比误差、峰均比、检测一致性我在复现张陈峰这个项目并跑完两组数据后把结果整理成一个对比表直观程度比一堆废话强很多验证项仿真链路真实数据链路备注目标数量3 个全部检出2 个主目标检出1 个弱目标漏检真实数据噪声底抬高约 5 dB测距误差0.02 m0.11 m仿真误差在 1 个距离 bin 内测速误差0.15 m/s0.32 m/s实测目标略加速多普勒展宽角度误差0.5°2.1°通道幅相不一致是主因峰值旁瓣比32 dB21 dB真实数据旁瓣明显抬高这个结果很有代表性仿真链路验证了算法原理真实链路验证了工程可用性。真实数据里弱目标漏检正是因为噪声底不平坦CFAR 门限被旁瓣抬高了。后来我把 CFAR 从二维 CA 改成 OS-CFAR漏检问题才好转。这些细节不跑真实数据是根本发现不了的。4.4 两种实现不一致时的排查思路如果仿真和实测结果差异特别大我会按下面顺序排查先确认真实数据的参数配置与仿真参数一致尤其是采样率、chirp 数、扫频带宽。如果 A100 实际固件配置和仿真脚本不一致后面全白做。对比距离-多普勒图。如果实测图的噪声底整体抬高优先怀疑数据采集时增益设置过高或者环境杂波太强。如果检测目标的位置偏移规律一致优先怀疑系统延迟校准。FMCW 链路里从发射到 ADC 采样存在固定延迟这个延迟会转化为距离偏移。如果角度偏差大优先做通道相位校准。如果目标速度出现重影优先检查 chirp 周期是否设错导致超出了最大不模糊速度。这套排查思路既能帮你处理特定项目问题也适用于以后其他雷达设备的数据处理。5. 现场调试实录踩过的坑与排查方法5.1 字节序、IQ 顺序和维度排列问题这是读取 ADC 数据时最高频的坑。A100 的数据文件有的固件输出是大端有的是小端有的 I 在前有的 Q 在前。一旦读错FFT 出来的频谱会异常混乱或者出现镜像峰。我的建议是在处理流程最前面写一个“数据自检”函数function ok checkADCFormat(adc) % 统计I/Q路能量是否接近 % 检查直流附近是否异常 % 检查是否有截断 end如果 I 路和 Q 路能量差异超过 3 dB基本可以判断 IQ 读写顺序或者定标系数有问题。5.2 镜像峰和直流偏置处理真实 A100 数据里我常看到直流偏置和一个镜像峰。直流偏置用去均值解决镜像峰如果和目标峰形成两个对称峰值可以通过 IQ 校准矩阵处理% 简化的IQ不平衡补偿 I real(adc); Q imag(adc); % 估计幅度和相位误差后构造补偿矩阵 adcComp I 1j * (Q / ampErr - I * sin(phaseErr)/cos(phaseErr));注意这个公式只适用于窄带信号。如果扫频带宽很宽宽带 IQ 不平衡需要更复杂的频域校准简单补偿效果有限。5.3 CFAR 参数调整的“手感”在使用phased.CFARDetector2D时我建议按以下顺序调参先设置一个偏高的虚警概率比如 1e-4保证目标能够全部检测出来即使有些虚警。观察虚警集中在哪些区域。如果虚警集中在近距离强杂波区需要增加保护单元避免目标自激抬高门限。逐步降低虚警概率到 1e-6 或更低直到虚警数量可控。如果目标在强目标旁边被压制把训练单元数减小。记住一个原则CFAR 永远是在“分辨不出目标”和“虚警太多”之间做权衡不存在一组参数通吃所有场景。所以在工程设计时建议做场景分类每种场景存一组 CFAR 参数。5.4 数据质量判断怎么判断一帧 ADC 数据到底能不能用我一般看三个指标峰均比峰值功率 / 平均噪声功率是否大于 15 dB低于这个值检测会很吃力。多普勒维是否有明显的静态杂波亮线如果静态杂波占满全图说明天线隔离度或环境有问题。通道间幅度一致性是否在 2 dB 以内否则角度估计不可信。这几个判断跑一遍只需要几分钟但能帮你避免在垃圾数据上浪费时间。我在处理社区数据时习惯先写一个“数据健康报告”把以上指标全部输出再决定要不要进入详细分析。6. 对社区共建者的建议与后续拓展6.1 如何参与这样的项目如果你想参与类似 SuperRadar 的共建项目不用等自己手里的设备多高端。普通毫米波雷达模组只要能输出 ADC 数据就可以做贡献。你可以上传一小段带场景标注的原始数据或者帮忙给已有数据写 MATLAB 处理示例再或者对别人的测试结果做交叉复现。像张陈峰这次的工作本质就是“用一份原始 ADC 数据 一套 MATLAB 处理链路 一份验证报告”把一个真实场景变成了大家可以反复学习的案例。参与时有一条经验发布结果时一定要把数据格式说明、处理参数、代码版本一起挂出来。否则别人拿到你的结果图却不知道 CFAR 用的什么参数、窗函数用了哪个就很难复现。我见过不少质量不错的数据就是因为说明文档缺失最后被大家弃用非常可惜。6.2 下一步可以做的方向这个项目后续还有很多可以延伸的空间。比如把 MATLAB 的处理链路移植到 Python用同一份 ADC 数据做跨语言一致性验证这其实也算是“双实现验证”的一种变体。再比如基于这批真实 ADC 数据训练一个用深度学习做目标分类的模型用 bp 神经网络拟合目标运动轨迹或者用 MATLAB 的 Deep Learning Toolbox 做距离-多普勒图的语义分割。社区里目前缺的其实是“带标注的多帧连续数据”而不是单帧数据。如果你能采集一段几十秒的连续 ADC 数据并且同步记录目标的真实轨迹那对做多目标跟踪和目标识别的朋友来说帮助会非常大。另外ADC 数据仓库的建设本身也有很多工程问题值得研究比如数据压缩、自动脱敏、存储格式统一。这些问题不酷但很实际。就拿数据格式来说A100 导出的二进制文件如果都能统一成一套带元数据的格式会省去大家很多解析时间。我个人在实际操作中的体会是像 A100 ADC 这类项目最值钱的往往不是某个高级算法而是一份“数据到底怎么被正确读进来、怎么被正确预处理、怎么被验证过”的完整经验。仿真结果再漂亮也替代不了真实数据的检验。如果你现在正卡在“数据读不对”或者“处理结果对不上”这两个问题上回头检查一下字节序、IQ 顺序、通道校准这三件事多半能找到突破口。最后再分享一个小技巧每次处理完一批数据把处理结果连同关键中间变量距离-多普勒图、CFAR 门限平面存成一个 MAT 文件方便后面随时回放。这看起来多花了一点存储空间但在排查问题和写报告时会非常省力。
返回列表