
FMCW这五个字母对做毫米波雷达的人来说几乎就跟吃饭喝水一样日常。但“日常”不意味着“简单”我见过不少刚入门的同学甚至做了两年方案的工程师对FMCW的理解还停留在“发射一个扫频波混频后做FFT就有距离”这种层面。可真要自己去配一个24GHz模块的chirp参数、去调40m距离检测阈值、去写一版C FFT程序或者把雷达目标数据和摄像头做时空同步时就开始抓瞎了。这篇文章是“FMCW毫米波雷达原理”系列的第一篇我打算把从波形设计、混频中频、二维FFT到目标检测与多传感器融合的链路一次性讲透重点解释那些原理图上看不出来、只有动手调板子才能体会到的细节。适合三类人看刚接触毫米波雷达的在校学生、准备用24GHz/77GHz雷达做产品开发的工程师、以及正在做多传感器融合项目、想搞明白雷达输出点云背后逻辑的同事。放心数学不会太难但我会把每一步为什么这么算、算出来代表什么讲清楚。1. 为什么测距测速都用FMCW——先从体制选择说起1.1 脉冲、CW、FMCW三种体制的对比雷达体制这件事很多教材喜欢绕我直接给结论。毫米波民用雷达市场里你见到的95%以上其实就三种波形脉冲波、单频连续波CW、调频连续波FMCW。脉冲雷达原理特别好理解发一个短脉冲等它碰到目标反射回来根据发射和接收的时间差乘以光速再除以2就是距离。听起来简单但工程上非常难受——需要很高的峰值发射功率要有收发开关来做收发隔离近距离盲区还大。在24GHz和77GHz这种频段想用半导体工艺把脉冲雷达做到低功耗、小体积、低成本很难。单频连续波雷达也就是CW雷达只发射一个固定频率的波。目标只要在动就会产生多普勒频移所以CW雷达测速极准很多交警用的测速仪就是它。但CW雷达测不了距离因为回波相位在0到2π之间不断循环你不知道目标离你多远只知道它在靠近还是远离。说白了CW是“速度专家”却是“距离瞎子”。FMCW则把两者结合起来了发射频率随时间线性变化的连续波回波和本振混频后产生的差频频率直接和距离挂钩而连续两个chirp之间的相位变化又反映了速度。一套前端距离、速度全都能测再加上多个接收天线还能测角度。这也是为什么FMCW几乎统一了民用毫米波雷达市场。1.2 FMCW并非万能代价与边界说FMCW好但不代表它没有短板。最大的问题是距离和速度的耦合当场景中同时存在多个目标而你只用单斜率的三角波或锯齿波时距离和多普勒信息会混叠在同一个中频信号里这就是很多人说的“距离-多普勒模糊”。要解开这个耦合你就得用多斜率chirp或者慢时间相参积累来做二维修正算法复杂度一下就上来了。另一个容易被忽略的问题是FMCW对信号源的线性度要求极高。理想情况下发射频率应该随时间完美线性上升但实际VCO压控振荡器的调频曲线通常有一点S形弯曲。如果线性度不够混频出来的中频就不再是单一频率而是被展宽了距离谱上原本锐利的峰就会变糊距离分辨率恶化得特别明显。所以选体制这件事得看你到底要解决什么问题只测速度CW成本更低要极高的距离分辨率考虑更宽的调制带宽或者干脆换超宽带体制但如果你做的是24GHz人体存在感知、40m车辆检测、77GHz车载前向雷达FMCW确实是不二之选。我自己的经验是先定指标再挑波形而不是上来就默认FMCW。2. 线性调频与中频信号一次混频背后藏着什么2.1 Chirp参数B、Tc、S到底怎么设FMCW里一个最基本的波形单元叫“chirp”中文常译作“线性调频脉冲”但注意它并不是脉冲它是一个频率随时间线性增加的连续正弦波片段。这个chirp有两个关键参数扫频带宽B扫频时长Tc两者一除就得到调频斜率S B / Tc。这三个参数是雷达设计中最早的决策点因为它们彼此牵制。比如你想提高距离分辨率那就需要加大带宽B可一旦B变大在同样的Tc里斜率S也会变大而S变大意味着同样的目标距离会产生更高的中频频率ADC采样率就得跟着往上提功耗和成本都上涨。拿24GHz ISM频段来举例常见可用带宽是250MHz左右也就是从24.00GHz到24.25GHz这一段。如果Tc取128微秒那么S 250MHz / 128us算下来大约是1.95e12 Hz/s。这个数量级的调频斜率在工程上很常见既不会给VCO太大压力也能保持中频在一个合理的低频范围内。记住一点就好在设计波形时S决定了同样距离下中频频率的高低等价于控制了后端模拟和ADC的难度。2.2 差频信号与距离的线性映射现在波形发射出去了它碰到目标反射回来经过一段时间的空中往返到达接收天线。由于发射频率一直在变化到达雷达接收端的回波它的瞬时频率和当前正在发射的信号瞬时频率就有了一个差值。这个差值就是“差频”也叫中频频率。假设目标距离为R那么回波延迟τ 2R/c其中c是光速。因为发射频率在延迟τ内变化了S乘以τ这么多所以中频频率等于f_b S × τ (B / Tc) × (2R / c)这就是FMCW测距的最核心公式。可以看到中频频率和距离是严格线性关系只要你对中频做一次傅里叶变换找到谱峰对应的频率距离就出来了。这里有个非常容易让新手犯迷糊的点为什么这里是“频差”而不是“相位差”因为FMCW每次发一个chirp回波回来时发射端的频率已经“走”了一段两者频率不同。混频器把接收信号和本振信号相乘经过低通滤波后留下这个频率差。这个频率差一般在几百kHz到几MHz之间远低于射频端的24GHz或77GHzADC可以很容易地采样。实际调板子时你会在示波器上看到中频输出是一个正弦波频率随目标距离变化。如果你把天线对准一面墙距离固定中频就是一个稳定的正弦有人挥手过去中频频率会快速变化。这个信号看起来很“干净”但恰恰是这种干净让人容易忽略背后的非线性问题。2.3 多普勒频移叠加目标的距离和速度如何同时求解如果目标静止中频频率就只有一个S × 2R/c这一项。但如果目标在动回波还会叠加一个多普勒频移。多普勒频移的大小是f_d 2v / λ其中v是径向速度λ是波长。拿24GHz雷达来说波长大约是12.5mm如果一个目标以10m/s的速度靠近多普勒频移大约是1600Hz。这个数值和几百kHz的距离中频相比小很多但你不能忽略它因为它会造成测距偏差。处理这个耦合工程上有两套主流思路。一套是用三角波调制上扫频和下扫频分别得到两个中频表达式f_up f_r - f_df_down f_r f_d。把两者相加再除以2得到距离频率f_r相减得到多普勒频率f_d距离和速度就都解出来了。另一套是现在最流行的快速chirp序列也就是发一连串完全相同的chirp在每一个chirp上先做距离维FFT然后看同一个距离门里不同chirp之间的相位变化。这个相位变化同样包含多普勒信息再用第二个FFT把它提取出来。这两套思路不存在绝对的谁优谁劣三角波只需要单次测量就能解耦但多目标时容易配对错乱快速chirp序列在距离-速度二维谱上更清晰非常方便后续做CFAR目标检测。现在的商用车载雷达、4D毫米波雷达几乎都是用快速chirp序列。2.4 距离、速度分辨率的物理极限分辨率这个概念决定了两个相隔多近的目标还能被你区分开。FMCW的距离分辨率由扫频带宽B决定ΔR c / (2B)注意这里跟Tc无关跟FFT点数也无关只和调制带宽有关。带宽250MHz时ΔR约等于0.6m。这意味着两个距离相差小于0.6m的目标在距离谱上会融合成一个大峰谁也认不出谁。想提升到0.3m带宽就得翻倍到500MHz这在24GHz频段挺紧张在77GHz频段则相对宽裕这也是车载雷达偏爱77GHz的原因之一。速度分辨率则由相参积累时长决定通常等于Δv λ / (2 × M × Tc)其中M是chirp数量M×Tc就是总的处理时间。可以看到chirp发得越多、整体观察时间越长速度分辨率越高但这会降低雷达的帧率实时性会变差。有一个核心trade-off是新手最容易忽略的最大不模糊速度v_max λ / (4Tc)。Tc越大v_max越小。你想提高距离信噪比增大Tc结果可能速度糊了你想看得远又想要高速度量程两件事往往是冲突的。好的波形参数设计就是在系统指标、功耗、帧率和成本之间反复折中的结果不存在一键生成的万能参数。3. 从模拟前端到二维FFT信号处理链路拆解3.1 数据组织快时间、慢时间与二维矩阵进入数字域的第一步是把ADC采样出来的中频信号组织成一个二维矩阵。这里面的概念我建议所有做雷达的同学必须彻底搞清楚因为它贯穿后续所有算法。ADC在一个chirp持续时间内连续采样N个点这N个点叫做“快时间”维因为采样速度非常快通常每秒几兆甚至几十兆次。这一行数据经过距离维FFT后就变成了一条距离谱。接着雷达切换到下一个chirp再采N个点又得到一行距离谱。把M个chirp按次序往下排就得到一个N×M的复数矩阵行是快时间距离列是慢时间速度。我在带新人时特别喜欢让他在纸上画这个矩阵很多后来做4D雷达点云处理的工程师算法逻辑理不清最后追根溯源就是二维数据排布没吃透。比如距离傅里叶变换是作用在每一行上的而速度傅里叶变换是作用在每一列上的。如果你在代码里把这俩维度搞反了出来的谱图一定是乱的。实际操作中这个矩阵的规模很现实地受内存限制。比如N256、M64用float复数存储大约就是128KB还说得过去但如果你用的是77GHz高分辨率雷达N1024、M256单帧数据就到2MB以上嵌入式平台上的DMA搬运和FFT计算开销都要提前评估。3.2 距离维FFT第一个FFT到底在算什么距离维FFT的本质是对快时间维度的中频信号做频谱分析。因为中频频率与距离一一对应频谱上的每个频点自然就映射为某个距离门。具体计算步骤很直接。假设ADC采样率是fs采样N个点那么FFT后频率分辨率是Δf fs / N第k个频点对应的物理频率是f_k k × Δf。把它代入距离公式R_k c × f_k / (2S) c × k × fs / (2 × S × N)这就是为什么在程序里你只需要一行代码把FFT输出的索引k换算成距离就完事了。但真正做工程时有三个坑我几乎每次都会被问到。第一一定要先对时域数据加窗。矩形窗的旁瓣是-13dB一个小目标旁边很可能藏着的大目标旁瓣会把小目标盖住。至少加一个Hamming窗或Hanning窗旁瓣能压到-40dB左右。当然代价是主瓣变宽距离分辨率轻微下降但工程上这是绝对值得的。第二DC分量也就是频谱上0频附近那根极高的谱线如果不先去掉直流偏置它会淹没近距目标的信号。最简单的方法在FFT前把数据的均值减掉。第三FFT栅栏效应。真实目标频率往往落在两个FFT bin之间也就是“骑墙”此时谱峰会变钝、幅度被低估。处理办法是zero-padding把N点数据补零到更大的点数再做FFT比如做4倍零填充频谱会被插值变得更平滑目标位置估算也更准。3.3 速度维FFT慢时间里的相位扩散距离维FFT做完每个chirp得到一条距离谱。假设目标在第k个距离门理想情况下这个目标在所有chirp里都落在同一距离门。但目标在动回波的相位会在chirp之间发生线性变化。这个相位变化量是Δφ 4π × v × Tc / λ只要把某个距离门上的复数序列提出来沿着慢时间维再做一次FFT就能把这个相位变化率提取出来变成多普勒频率再换算成速度。这一步就叫做速度维FFT或多普勒FFT。工程上的坑在于相位是周期的如果目标速度太快跨chirp相位差超过2π速度就会模糊。也就是前面说到的最大不模糊速度v_max。当你在速度谱上看到一个峰贴在最边缘的位置先别急着认为目标真的有那么快很可能它已经翻折了。解决手段无非两个缩短Tc把v_max撑大但代价是距离中频变高、信噪比下降或者用多组不同的Tc去验证真实目标的速度在不同配置下应该一致模糊峰则会跳变。二维FFT处理完你会得到一张距离-多普勒图也常叫Range-Doppler MapRDM。这张图就是后续所有检测算法的主战场目标检测、静态杂波抑制、微动特征提取都是在RDM上做文章。3.4 从1D到4D角度估计与MIMO虚拟阵列如果你只想要距离和速度单天线就够了。但你想知道目标在哪个方位角就必须用多个接收天线。不同天线收到的回波会有相位差这个相位差由到达角AOA决定。假设两个接收天线间距为d目标到达角为θ则两路信号的相位差是2π × d × sinθ / λ。对多个天线的同一距离-多普勒峰做一次FFT或者用数字波束形成扫描角度就能估计出目标的方位角。这里有一个教科书反复强调但实际踩过才会记住的点天线间距d要尽量等于λ/2。因为sinθ的取值范围是-1到1如果d大于λ/2相位差就会超过2π角度谱里会出现栅瓣相当于把目标复制到错误的角度上。你看到两个同样强度的目标以为是两辆车其实是同一个人在角度上发生了混叠。4D毫米波雷达所谓的“4D”就是在距离、速度、方位角之外再加上俯仰角。要在俯仰方向也有分辨力必须布一个二维天线阵列。但每增加一个虚拟通道成本和数据量都上一个台阶所以工程上常常用MIMO体制让多个发射天线分时或编码发射等效扩展出更多虚拟接收通道。这背后牵扯到波形正交性设计、阵列流形标定等问题以后我可以单开一篇细讲。原理上4D雷达不是玄学就是天线阵列加上三维参数估计的常规组合。4. 从原理到落地24GHz模块、生命体征检测与多传感器融合4.1 实例推算24GHz模块做40m目标检测需要什么参数网上你搜索“24GHz毫米波雷达模块40m”能搜出一堆接近这个规格的产品。我拿其中一个常见配置来推演大家就能理解参数到底怎么定出来的。假设模块扫频带宽B250MHzchirp时长为Tc128us我们算一下40m处目标的中频频率。回波延迟τ 2×40 / 3e8大约是266.7纳秒。调频斜率S 250MHz / 128us ≈ 1.95e12 Hz/s。所以差频频率为f_b 1.95e12 × 2.67e-7 ≈ 520kHz这意味着ADC采样率至少要到1.04Msps工程上取2到5倍余量也就是2到5Msps比较稳妥。为什么要有余量因为40m处目标动的速度如果很快中频上还会叠加多普勒频移你得给后端的抗混叠滤波器留出过渡带不能让最高有用频率贴着fs/2。再来核算距离分辨率ΔR c/(2B) 3e8 / (2×250e6) 0.6m。这意味着两个相距0.6m以内的目标在距离维上会叠在一起。对40m外的大目标来说这个分辨率还不错但如果你想分辨行人的前后距离就有些力不从心。所以很多24GHz模块宣传“40m检测”往往指的是能发现目标存在而不是精确到厘米的测距。不过这里有个容易被忽略的现实问题在24GHz频段40m处一个小行人的雷达截面积RCS可能只有0.1到1平方米回波极其微弱。即便硬件上链路预算算得通回波很可能淹没在噪声和杂波里。工程上通常用两个办法提升一是增加chirp数M用更多慢时间脉冲做相参积累把信噪比抬上来二是做非相参积累或CFAR检测把虚警率压下去。切记标称“40m检测距离”和“稳定检测40m处的行人”是两个完全不同的指标跟客户沟通时一定要确认清楚对方说的是哪个。4.2 生命体征雷达为什么难点在相位而非幅度FMCW雷达还可以做生命体征检测这也是近期特别火的应用方向比如车内儿童存在检测、睡眠监护。一个成年人的胸腔随呼吸和心跳起伏位移幅度大约在0.1到2毫米之间。对比一下24GHz雷达波长约12.5mm1mm的位移引起的相位变化大约是2π×1/12.5≈0.5弧度其实不算小。问题在于这个位移产生的幅度变化微乎其微直接看中频信号幅度根本看不出来。所以提取生命体征的关键是相位级处理。处理流程大致这样先做距离维FFT找到人体所在的距离门再提取这个距离门上复信号的相位做相位解缠因为相位会从-π跳到π不展开就没法连续跟踪位移接着做带通滤波呼吸频率一般在0.2到0.5Hz心跳在0.8到2Hz两者频率接近但呼吸往往更强烈谐波还会串到心跳频段。这是我踩过最多坑的地方。第一静态杂波必须清理干净不然相位里混进了墙体反射和雷达内部的直流偏置波形会很脏。第二人体不可能完全静止一瞬间的体动幅度远大于呼吸起伏会让相位曲线产生巨大的尖峰。我的做法是先做一个能量检测检测到体动时暂时冻结生命体征参数更新等信号回归平稳再恢复。第三不要期望用FFT直接把呼吸和心跳两个峰分得干干净净。呼吸谐波经常跟心跳峰重叠工程上更需要的是自适应滤波或谱估计方法比如VMD、CWT而不是单纯看频谱峰值。4.3 摄像头与毫米波雷达目标时空同步做多传感器融合时最常见的一条技术路径就是摄像头和毫米波雷达做目标级融合这也是“百度摄像头与毫米波雷达目标时空同步”这类搜索热词背后的真实需求。这里有个前提必须明确摄像头输出的是二维像素坐标加检测框雷达输出的是三维空间点加速度两者要做融合必须先做空间对齐和时间对齐。时间同步这块核心问题是两者帧率不一致。摄像头通常25或30FPS雷达通常10到20FPS且各自有处理延迟。实际操作中我先给每一帧数据打上统一的时间戳然后以高帧率传感器的时间为基准对低帧率传感器做插值或外推。最简单实用的方案是假设目标在短时间内匀速运动用上一帧的速度预测当前时刻的位置再和当前帧的检测结果做最近邻关联。空间对齐的挑战更大。我见过太多团队把外参标定不当回事随便用激光尺量一下雷达和相机的位置偏移就完事结果融合出来的目标坐标在画面里怎么都对不上。正规做法是用标定板或角反射器在不同距离和角度下采集雷达点云与相机检测框的对应关系然后用最小二乘或者PnP求解两个传感器坐标系之间的旋转平移矩阵。这一步我建议留足时间标定误差会直接导致最后画在视频上的目标框偏出车一个车身而这个问题光靠算法是救不回来的。5. 工程实现中的高频坑与排查思路5.1 从模拟前端到二维FFT常见问题速查表我根据自己调不同平台毫米波雷达的经历整理了下面这些高频问题。很多时候算法看起来怎么都不对最后追根溯源都是这些小细节。现象可能原因排查建议距离谱上0频附近有巨大尖峰直流偏置未去除或近距强反射FFT前减去均值观察近距目标是否饱和谱峰分裂成两半VCO调频非线性太差或加窗过度测量真实发射波形做线性度校准降低窗函数滚降目标距离明显偏移中频叠加了多普勒频移使用上下扫频联合解算或先测速再修正距离速度谱边缘出现假目标速度模糊翻折检查v_max是否覆盖量程缩短Tc再验证角度谱出现重复对称峰天线间距大于λ/2引起栅瓣检查天线排布确认d≤λ/2目标在距离维上抖动相位噪声、电源纹波干扰VCO检查供电纹波观察中频信号底噪IQ信号镜像目标I/Q两路幅相不平衡做校准补偿这就是典型的镜像干扰这张表不能覆盖所有问题但覆盖了我在项目里见过的最常见的90%。如果你遇到的现象不在这张表里最可靠的办法是先把中频原始数据导出到PC用Python或MATLAB离线分析。离线比在线排查舒服得多你可以逐步打印中间结果看到底是第一个FFT错了还是第二个FFT错了。5.2 C FFT程序落地库选型与代码细节很多人在搜“毫米波雷达C FFT程序”说明到了写代码的阶段。坦白讲在自己工程里手写一个FFT其实没有必要成熟好用的库随手就能集成。嵌入式平台推荐KissFFT它实现简洁、依赖少在ARM Cortex-M上跑很顺手PC端处理离线数据推荐FFTW性能极致支持任意长度变换。如果你的平台不允许引入第三方库再考虑自己写Radix-2实现但一定要先拿纯正弦波做单元测试。用FFT时有几个细节值得单独强调。第一FFT输入输出都是复数中频ADC采样出来其实是单个实信号你需要把它填成复数的实部虚部填0或者用两次采样构建复数来节省带宽。第二做完FFT后频率轴的前半段是正频率后半段是负频率如果你要画距离谱图记得做fftshift把DC分量移到中心不然图会左右对调。第三如果目标距离很近中频频率很低此时FFT输出前几个bin受到DC泄漏干扰最严重可以考虑在硬件上引入一个小的固定中频偏置把目标搬到不受DC影响的频段。一个简化版的C测距核心步骤大概长这样// 伪代码距离维FFT关键步骤 const int N 256; fftw_complex* in (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * N); fftw_complex* out (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * N); // 拷贝ADC采样数据实部为IQ数据中I路虚部为Q路 for (int i 0; i N; i) { in[i][0] iq_data[i].I; in[i][1] iq_data[i].Q; } fftw_plan p fftw_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE); fftw_execute(p); // 第k个频点对应的距离R k * fs / N * c / (2*S) double fs 5e6; // ADC采样率 5MHz double S 1.95e12; // 调频斜率 250MHz/128us double c 3e8; double range_bin_size (fs / N) * c / (2 * S); // 注意FFT结果需要对幅度取模并跳过DC附近的bin这段代码你拿着改一改就能跑但要提醒一点FFTW默认是多线程优化过的在嵌入式平台不一定可用如果切到KissFFT接口完全不同但思路一样。代码里千万别忘记释放内存和销毁plan内存泄漏在长时间运行的雷达程序里是非常隐蔽的Bug。5.3 排障思路先怀疑波形再怀疑算法最后聊一下排障顺序。很多初学者遇到测距不准第一反应是去调FFT、换窗函数、加滤波器搞了半天发现没用最后检查才知道是雷达的配置文件里扫频带宽跟实际硬件不一致。我的习惯是任何软件问题排查前先确认三件事波形参数是不是真正写进寄存器了、ADC采样率是不是和配置一致、混频后的中频信号是不是在合理的幅度范围内。这三件事只需要一个示波器或一台PC读寄存器就能确认但能省掉后面一整天的算法调试时间。如果波形参数都正常再看信号链路中间结果。先看时域中频有没有饱和或削顶再看距离FFT结果里有没有清晰的谱峰然后看速度FFT结果最后才轮到检测和跟踪逻辑。这条链路就像剥洋葱一层一层来每层都打印或画出中间输出问题出在哪一层一目了然。千万不要一上来就盯着最后输出的目标轨迹猜原因那样只会浪费时间。写在最后的一个小建议做雷达系统设计和做纯视觉算法思维模式不太一样。视觉系统里很多东西可以用大模型硬凑但雷达每一行代码背后都对应着物理参数差一个符号、少一个相位结果就是天差地别。我个人的体会是学FMCW原理最好的办法不是只看公式而是买一块几十块钱的24GHz雷达模块自己写一版数据采集程序把中频原始数据抓出来在电脑上一步步处理亲眼看到距离谱峰随着手移动而变化。那种感觉比看十篇原理文章都来得深刻。做嵌入式实现的同事建议先把离线数据链跑通再上板因为板上能调试的手段太有限了。好了这篇先到这里下一篇我准备深入讲三角波与快速chirp序列在多目标场景下的优劣以及距离-速度配对的具体实现方式。