搞了好几年毫米波雷达最常被问的一句就是一个没有镜头的24GHz模块凭什么就能告诉你是“前面有个人在走”还是“一辆车在高速靠近”答案藏在一个叫FMCW的调制方式里。FMCW全称Frequency Modulated Continuous Wave调频连续波。它不靠脉冲回波计时测距而是通过发射频率随时间线性变化的连续波让回波和本振信号之间形成一个差频这个差频同时携带了距离和多普勒两层信息。只要用FFT把中频信号扒开看目标在哪、移动多快都能算出来。毫米波雷达的整套测速流程基本都围着“发射锯齿波/三角波 → 混频 → 采样 → FFT → 目标检测”这条链路转。这篇我想把FMCW测速原理讲透再结合24GHz毫米波雷达模块在40米级别场景下的实测配置聊一聊Range-Doppler矩阵、速度解算、CFAR目标检测以及现在很火的4D毫米波雷达和“雷达摄像头时空同步”这类工程应用。正在做雷达项目、信号处理刚入门、或者准备把雷达引入感知系统的朋友可以直接当一份实践笔记用。1. FMCW测速为什么能成为毫米波雷达的主流方案1.1 一次调频里测距和测速其实是同一件事先放下测速想想FMCW怎么测距。雷达发射一个频率线性上升的信号碰到目标反射回来接收信号相对发射信号有一个时间延迟τ。发射信号频率一直在变所以延迟就等于一个频率差。这个频率差叫中频频率f_IF可以写成f_IF S * τ S * 2R / c其中S是调频斜率单位Hz/s表示频率每秒钟上升多少R是目标距离。也就是说距离越远延迟越大中频频率越高。这里把目标回波的幅度忽略掉频率已经够用。现在问题来了如果目标在动回波还有一个多普勒频移f_d 2v / λ叠加到中频上单看一次扫频的f_IF距离和速度混在一起分不开。怎么解耦传统做法是三角波调制一个上升沿、一个下降沿上升沿和下降沿的速度分量符号相反通过两段中频频率相加、相减分别还原出距离和速度。现代更常用的是锯齿波快chirp序列对多个chirp在慢时间维做FFT速度信息自然被速度维FFT解出来。本质上FMCW是同时在时间维和频率维上做文章把“距离”和“速度”编码进了不同维度的频率里再用FFT这把尺子量出来。拿生活类比一下你站在路边听一辆鸣笛的车开过来音调变高是车速造成的而声音延迟了多少是距离造成的。FMCW就相当于把“音调变化”和“回声延迟”编码进同一个信号里然后用频谱分析把它们分开。1.2 为什么偏偏选毫米波而不是激光或摄像头很多人会问摄像头已经能做目标检测了为什么还要雷达因为雷达的工作频段决定了它先天不怕暗光、雾霾、雨雪也不依赖目标纹理颜色。摄像头看到的是“像不像人”雷达看到的是“这地方确实有一个反射体在移动”两者互补。毫米波频段通常指30GHz到300GHz24GHz属于厘米波到毫米波过渡地带但工程上习惯把24GHz和77GHz都归在车载毫米波雷达范畴。频率越高波长越短有两个好处一是天线物理尺寸可以做小方便在模块里放更多收发通道二是相同速度下多普勒频移更大低速目标更容易被检测。以10m/s的目标为例24GHz的多普勒频移约为1.6kHz77GHz约为5.1kHz后者频率分离度明显更高。那为什么24GHz模块还大量存在成本低、方案成熟、中距探测性能足够。40米左右的距离24GHz模块用250MHz带宽距离分辨率到0.6米速度分辨率结合帧结构可以做到0.5m/s量级做道闸防砸、交通测速、工业安全防护完全够用。2. 从回波到速度信号处理链路拆解2.1 中频信号是怎么来的FMCW发射端产生的信号一部分经过功率放大器后由天线发射另一部分作为本振信号进入混频器。接收天线收到的回波经过低噪声放大后和本振信号混频输出一个低频的差频信号也就是中频信号IF。发射信号和回波信号频率差多少取决于目标的延迟和多普勒。如果目标静止IF是一个单一频率的正弦波目标运动IF频率上叠加了多普勒频移。为了提取这个信号后端要经过ADC采样采样率的选择由最大探测距离决定。比如调制斜率S2.5THz/s时想要最大探测距离120米理论最大中频频率要支持到2MHz按带通采样或者低通采样习惯ADC采样率至少4Msps。这里容易被忽略的是抗混叠滤波器。有些开发板直接让ADC硬采中频信号里高频杂散混叠进低频段处理完才发现靠近0Hz的bin里多出一堆假能量。正经做项目混频器后端必须放一个低通滤波器截止频率按中频最大频率的1.2倍左右设计。2.2 先做距离维FFT再做多普勒维FFT顺序有讲究拿到一帧数据通常是一个二维数组横轴是单个chirp内的采样点纵轴是chirp序号。比如128个chirp每个chirp采256点就是一个128x256的复数矩阵。第一步是距离维FFT也叫Range FFT。对每个chirp的256个采样点做256点FFT得到一个距离谱横轴是距离bin纵轴是幅度。此时一个静止目标会出现在某一个距离bin上一个运动目标也会出现在距离bin上但峰值精确位置受多普勒影响有偏移。第二步是多普勒维FFT也叫Doppler FFT。对每个距离bin沿chirp轴方向取128个复数点做FFT。这128个点之间的相位变化反映的就是目标多普勒频率。这一步做完就得到Range-Doppler Map简称RDM是雷达感知的核心数据。为什么顺序是先距离后多普勒因为数据在内存里最自然的排布是“chirp采样点连续”先做距离FFT可以逐行处理、缓存友好。而多普勒FFT需要按列取数如果直接在原数组上做内存跳跃比较大性能好的做法是先做距离FFT再把矩阵转置让chirp维变成连续排布再做列方向FFT。C里伪代码大概是这样的constexpr int kRangeBins 256; constexpr int kChirps 128; // frame 用 [chirp][range_sample] 布局 std::vectorComplex frame(kChirps * kRangeBins); // 1. 距离维 FFT for (int chirp 0; chirp kChirps; chirp) { Complex* row frame.data() chirp * kRangeBins; ApplyWindow(row, kRangeBins); // 汉明窗/布莱克曼窗 Fft(row, kRangeBins); } // 2. 转置让 chirp 维连续 std::vectorComplex transposed(kChirps * kRangeBins); for (int r 0; r kRangeBins; r) for (int c 0; c kChirps; c) transposed[r * kChirps c] frame[c * kRangeBins r]; // 3. 多普勒维 FFT for (int r 0; r kRangeBins; r) { Complex* col transposed.data() r * kChirps; ApplyWindow(col, kChirps); Fft(col, kChirps); }加窗这一步千万别省。FFT本身有个特性频谱泄漏。不做窗强目标的旁瓣会把弱目标盖住。距离维用汉明窗多普勒维同样用汉明窗旁瓣能压到-40dB左右代价是主瓣稍微变宽距离和速度分辨率略降但换来的动态范围很值。2.3 峰值bin怎么换算成速度多普勒维FFT做完每个距离bin上都有一个多普勒谱。目标峰值所在的多普勒bin换算成频率再换算成速度。多普勒维FFT的频率分辨率取决于总观测时间频率分辨率Δf 1 / (N * T_chirp)其中N是chirp数T_chirp是chirp起始间隔。再通过f_d 2v / λ得到速度分辨率Δv λ / (2 * N * T_chirp)最大不模糊速度则受奈奎斯特采样定律限制一个周期至少采两个点才能分辨频率正负所以v_max λ / (4 * T_chirp)举个例子24GHz波长λ约0.0125m如果T_chirp100μs做128个chirpv_max 0.0125 / (4 * 100e-6) 31.25m/s约112km/hΔv 0.0125 / (2 * 128 * 100e-6) ≈ 0.488m/s约1.76km/h想要测更高速可以把T_chirp缩短但最大探测距离会受限想要更高的速度分辨率可以增加chirp数延长帧时间。这组参数在实际工程里就是要反复权衡的。三角波调制又是另一套算法上升沿得到f_up下降沿得到f_down距离和速度分别用和差解出R (f_up f_down) * c / (4S) v (f_down - f_up) * λ / 4这招在目标个数少的时候好用多个目标配对会出组合爆炸现代雷达更喜欢用锯齿波快chirp序列做二维FFT省心。2.4 速度维上还有一个容易被忽略的“零多普勒”RDM做出来后正中间或者最边缘的那一行对应的是多普勒频率为0的目标也就是静止目标。人眼能分辨这是墙体、护栏但算法上如果不处理它永远是最大峰值。处理手法很简单把的速度bin上幅度置零或大幅衰减。这一步在CFAR之前做能显著减少虚警。但注意不要把完全静止的目标也一刀切比如某些场景要检测静止行人就得保留零多普勒附近的能量换用距离维和幅度阈值筛选。3. 24GHz毫米波雷达模块40米测速的实测细节3.1 模块选型直接出结果和输出中频完全是两条路市面上的24GHz雷达模块分两类。一类内部集成了信号处理和测速测距算法直接通过串口输出目标列表拿过来就能用适合做产品验证另一类只把收发前端、混频器和中频输出做出来RAW数据自己采算法自己写适合做算法研究和定制开发。做测速原理研究的建议选后面这类带I/Q输出或ADC数据输出的模块。看着多费了事但你能拿到原始中频数据可以自己做Range FFT、Doppler FFT、CFAR对雷达原理的理解完全是另一个深度。整机模块虽然快但一旦出现目标漏检你不知道是射频问题、算法问题还是参数配置问题。选型时重点看几个参数发射功率、调制带宽、噪声系数、相位噪声。24GHz模块调制带宽一般能做到200MHz到250MHz距离分辨率0.6米到0.75米。发射功率决定探测距离常见方案输出功率在10dBm到14dBm之间配合适增益天线40米探测不算难。3.2 实测参数怎么配一份可以直接抄的配置表我之前用一套24GHz模块做过道路目标测速实验核心参数大概是这样参数数值说明中心频率24.125 GHz常见ISM频段调制带宽250 MHz距离分辨率约0.6米chirp周期100 μs决定最大不模糊速度chirp数量128决定速度分辨率ADC采样率4 Msps最大中频约2 MHz单chirp采样点数256距离FFT点数帧率约50 Hz128个chirp加上处理开销这套配置下理论最大不模糊速度31.25m/s速度分辨率约0.49m/s距离分辨率0.6m。实际测试中10米到40米的行人、自行车、汽车目标都能稳定出点。低速目标如果速度低于0.5m/s在RDM上会和零多普勒bin连在一起处理时要小心。测速精度方面单帧FFT峰值bin的量化误差较大速度可能跳1.76km/h一档。要提升精度可以在多普勒维峰值附近做抛物线插值速度精度能提高一个数量级但稳定性和信噪比相关。信噪比低时插值结果抖动反而不如不插值这个需要在实测里根据场景取舍。3.3 24GHz测速常见的“假目标”都从哪来实测中很多假目标来自天线的直接耦合。发射天线和接收天线之间距离太近发射信号会直接耦合进接收通道在零距离附近产生一个巨大能量这个能量在距离维FFT上占据前面几个bin经过多普勒FFT后还会在多个速度bin上产生泄漏。解决方法一是硬件上做隔离收发天线间距放宽必要时加屏蔽墙二是在算法上做背景对消静态场景下先采集一帧噪声基底然后实时帧减去平均背景。注意背景要定期更新因为温度变化会改变天线耦合的相位固定的背景减法用久了反而产生新的假目标。还有一个常见来源是电源纹波。24GHz的VCO对电源很敏感电源上几十毫伏的纹波直接体现在发射信号相位噪声上RDM上表现为整个多普勒轴都有底板噪声抬高。做实验时用线性电源或者低噪声LDO给射频前端供电比什么算法优化都立竿见影。4. 4D毫米波雷达和多目标检测从测速到感知4.1 4D雷达多出来的那一维是什么传统毫米波雷达能输出距离、速度、水平方位角通常叫3D雷达。4D雷达在水平方位角之外增加了俯仰角测量能够区分同一距离、同一速度、不同高度的目标。这意味着雷达不只是告诉你“前方10米有个目标”而是告诉你“前方10米、左侧2米、离地1.5米有个目标”。4D雷达背后靠的是MIMO天线阵列和多通道接收。多发多收形成一个虚拟孔径水平维和垂直维都可以做波束形成或者DOA估计。这类雷达输出的是点云一个目标可能对应多个点每个点带距离、速度、水平角、俯仰角和幅度信息和激光雷达点云形式接近但点云密度低得多。4D雷达对复杂场景的意义很大。比如宽敞道路上方的限高杆普通雷达会当成一个目标4D雷达能看出它离地高度判断车辆能不能通过桥下行驶时桥面反射和目标反射混在一起有了俯仰角就能把两个反射来源分开。《4D雷达》这个词在最近非常热但坦白讲很多4D雷达实际点云质量不如成熟3D雷达。如果做项目优先把3D雷达的RDM和CFAR做好再考虑加DOA和聚类也不用一上来非要选4D方案。4.2 CFAR目标检测多目标场景下如何判断“这里有目标”雷达目标检测不是拿着RDM找一个最大峰值就完事因为噪声底不是均匀的。近距地面杂波可能让一部分距离bin的底噪抬高远处天空方向底噪又很低。全局固定阈值要么漏检要么虚警一堆。恒虚警率CFAR是通用解法。它的思路是对每个待检测点保留若干保护单元在保护单元外取若干参考单元统计参考单元的均值乘以一个系数作为门限。如果待检测点幅度超过门限判为目标。CA-CFAR是最常用的形式适合底噪比较均匀的场景如果近处有强杂波改用OS-CFAR排序后取中间值抗强目标遮蔽能力更好。参考单元和保护单元大小怎么定如果距离维一个目标占据2~3个bin参考单元取16~24个保护单元取2~4个。取值太小门限跟着目标自身走目标被吃掉太大又对底噪变化不敏感边缘目标检测不出来。CFAR参数是整个雷达算法里调参体验最“玄学”的部分建议在采集真实数据后的离线数据集上调不要拿到现场比划。目标检测做完还要做凝聚。一个目标在RDM上可能横跨多个bin取局部最大值对应的索引作为目标的位置速度值并用周围bin做加权质心输出一个更平滑的点。多目标时再用聚类算法把相近的点归成一簇常见的有距离速度二维聚类或者加水平角三维聚类。4.3 点云输出之后怎么和摄像头数据对齐4D雷达点云虽然稀疏但它天然带有速度和距离很适合和摄像头融合。融合的前提是时间同步和空间同步这是两个完全不同的工程问题。时间同步保证雷达数据和图像数据对应同一时刻。雷达点云通常是10到30Hz输出摄像头是25到30帧时间戳很难完全对齐。最简单的办法是放弃硬同步做时间戳最近邻匹配图像帧到来时取时间戳最近的雷达帧。如果目标是高速移动的这会导致几十毫秒的误差反映在投影上就是目标偏离图像框几个像素到几十个像素。精度要求高的场景需要插值外推运动状态。空间同步解决的是“雷达坐标系的点投到图像哪个像素坐标”。需要先对雷达和摄像头做联合标定得到雷达坐标系到相机坐标系的旋转矩阵R和平移向量t然后用相机内参做透视投影x_img f_x * X_cam / Z_cam c_x y_img f_y * Y_cam / Z_cam c_y标定实操有个坑摄像头标定用的棋盘格角点普通雷达很难捕捉到强回波因为角点不是金属反射体。工程上通常把金属角反射器放在棋盘格平面上同时被摄像头识别和雷达探测到然后用多组对应点求解外参。角反射器的位置精度直接决定标定精度这一步做不好后面所有融合结果都飘。5. 雷达与摄像头目标时空同步的工程要点5.1 时间同步先定“谁是主时钟”做雷达和摄像头融合项目第一件事不是算法而是统一时间基准。如果雷达有自己的系统时钟摄像头用自己的NTP时间两个时钟不同步标定参数再准也没用。硬同步方案中常用PPS秒脉冲或外部触发信号。雷达收到上升沿后开始输出一帧摄像头曝光时刻也由同一触发源控制两者时间对齐精度可以达到亚毫秒级。但硬同步需要硬件支持很多模组没有预留触发引脚。软同步方案更常见给每个雷达帧和图像帧打上统一主时钟的时间戳然后在融合模块里做时间对齐。例如摄像头帧率30fps间隔33ms雷达帧率20Hz间隔50ms。每一帧图像到达时找到时间戳最接近的雷达点云。目标运动速度不高的情况下这种方案足够稳逻辑也简单。再进一步可以对雷达目标做运动外推用目标当前速度和上一帧位置把点云外推到图像曝光时刻。这在车速较高的车路协同场景很有用能把目标位置误差从半米降到十几厘米量级代价是外推需要足够平滑的速度估计。5.2 空间同步的关键是标定场景设计空间同步最终落到一个投影变换关系。目标从雷达坐标系进入图像坐标顺序是雷达坐标 → 世界坐标或相机坐标 → 图像像素坐标。工程上直接把雷达坐标变换到相机坐标写成一个4x4外参矩阵然后用相机内参投影。标定流程一般是摄像头标定内参得到焦距和主点在场景里放置多个角反射器确保能被雷达检测到用摄像头检测角反射器位置得到像素坐标用雷达获得角反射器在雷达坐标系下的三维坐标用PnP算法求解雷达到相机的外参R和t。角反射器数量至少放6到8个分布在远近高低不同位置不要全堆在同一平面。否则求解外参时退化误差在某一方向特别大。标定完要留一个验证集把雷达点投影到图像上用肉眼判断是否贴合对应目标。这一步能发现标定结果的系统性偏移。5.3 融合闭环之后怎么判断雷达测速是否可靠雷达测速和摄像头测速是互补的摄像头通过目标在图像上的像素位移估计速度误差和距离强相关远距离时很不准雷达直接测多普勒速度精度不受距离影响。融合后一般做法是用雷达目标做位置和速度的预测用图像检测框分类做属性修正。判断融合是否成立先做一个最简单的统计在每帧图像中把雷达点投影进去统计投影点是否落在对应目标检测框内。落在框内的比例就是“雷达-视觉关联率”。这个指标做到80%以上基本可以说明时间同步和空间同步都是对劲的。如果关联率低排查顺序是先检查时间戳延迟再检查外参最后检查雷达点云本身是否有系统性距离偏移。很多时候不是标定错了而是雷达测距本身有系统偏差比如天线延迟没有校准所有距离都统一偏大几十厘米。6. 常见问题与排查技巧实录6.1 问题速查表现象可能原因处理方向速度显示折叠80km/h显示成负值目标速度超过v_max缩短T_chirp或提高测速范围低速目标速度跳变剧烈速度分辨率不足增加chirp数或做多普勒插值RDM上固定距离出现密集杂波天线耦合或温漂背景残留重新采集背景并做对消测距结果所有目标偏大天线/混频器延迟未校准标定中量测固定补偿值远处目标时有时无CFAR门限过高或信噪比不足降低门限系数检查发射功率静止目标在多个速度bin有能量相位噪声或电源纹波过大换低纹波电源检查VCO供电高速目标旁出现“假速度”镜像频率/欠采样提高采样率检查抗混叠滤波摄像头投影偏移一个大方向外参标定不准重新采集角反射器标定点6.2 实测现场踩过的几个坑先说供电。24GHz雷达模块对电源噪声特别敏感尤其是直接调制VCO供电的电源。有一次测得速度总是跳来跳去排除了半天发现是笔记本USB供电的纹波干扰换成锂电池供电后现象消失。做雷达实验电源部分值得第一批检查。再说启动校准。大多数24GHz模块上电后需要一段时间让锁相环稳定前几十帧数据不能直接用。Firmware开始传数据就拼命调参数容易被假数据带偏。好的习惯是上电后等500ms到1秒先采集一段只含噪声的数据估算噪声基底再开始目标检测。最后聊一下FFT插值。速度维FFT的峰值bin本身只能精确到分辨率级别可以通过对峰值附近的幅度做抛物线拟合得到更细的位置。但信噪比低于15dB时抛物线插值的抖动反而比直接取bin还要大因为噪声会让旁瓣幅度随机起伏。实际项目中我一般先看信噪比低于阈值就直接取峰值bin高于阈值才做插值简单粗暴但很管用。我个人做了半年24GHz模块后最大的体会是雷达算法难的不是哪一步独门绝技而是每一步都踩在物理约束上。调参之前先算一遍最大测速范围、速度分辨率、距离分辨率很多问题从参数表里就能提前暴露出来。如果刚开始做别急着上4D雷达、多传感器融合先拿一个带原始中频输出的24G模块把Range-Doppler热力图跑出来目标往里一走、一动你立刻能感受到FMCW从频域里“看见”目标的那种直观。后面再上CFAR、点云、融合都是水到渠成的事。