做雷达感知的人,应该都对 FMCW 这三个字母不陌生。FMCW(Frequency Modulated Continuous Wave,线性调频连续波)是毫米波雷达最常用的信号体制,从 24GHz 的工业测距模块到 77GHz 的车载前向雷达,核心原理其实是一样的。这篇我打算用说人话的篇幅,把 FMCW 怎么测距、怎么测速、为什么要做 FFT,以及参数怎么定讲明白。这是“原理一”,适合刚接触毫米波雷达的工程师、学生,也适合那些已经在调模块但总觉得原理差点意思的朋友。
很多刚开始接触雷达的人,一上来就背公式、调 FFT,结果波形出来了却解释不了峰值为什么在那,换个场景数据就乱了。问题往往出在没把 FMCW 的物理过程真正过一遍。这篇文章不会堆一堆数学,而是从信号怎么发出去、怎么被接收、怎么变成你看到的数据开始,一步步把链路走通。看完之后你再去看那些 C++ FFT 程序、4D 毫米波雷达的测角方案,或者摄像头与雷达做时空同步时为什么要对时间戳和坐标系,都会清晰非常多。
1. 先搞懂 FMCW 在雷达家族里的位置
1.1 脉冲雷达和 FMCW 的本质区别
雷达的波形体制可以粗分成两大类:脉冲雷达和连续波雷达。脉冲雷达像闪光灯拍照,每隔一段时间发一个很窄的高能量脉冲,然后等回波。通过计算脉冲发出到接收的时间差,就能得到目标距离,这个时间差对应的就是光速下的往返路程。原理很直观,但它需要很高的峰值功率,因为能量集中在很短的脉冲里,硬件上要承受高压大电流,近距离盲区也比较大。
FMCW 走的是另一条路。它不发射短促的脉冲,而是持续发射频率随时间线性变化的信号,也就是常说的 Chirp 信号。它从 24GHz 扫到 24.2GHz,只需要一个几十毫瓦量级的发射功率就能完成几十米甚至上百米的测距,中近距离测量能力很强。早期很多做过脉冲雷达的人会觉得连续波没法测距,因为没有明显的时间戳,不知道回波是哪个时刻发出去的。FMCW 的聪明之处在于,它把时间信息编码在了频率变化里,通过收发频率的差值来反推距离。本质上就是用频率给时间“打标记”。
| 对比项 | 脉冲雷达 | FMCW 雷达 |
|---|---|---|
| 发射波形 | 窄脉冲,峰值功率高 | 连续线性调频,峰值功率低 |
| 测距原理 | 脉冲时间差 | 收发频率差 |
| 近距离盲区 | 明显,受脉冲宽度限制 | 很小,贴近安装即可工作 |
| 硬件复杂度 | 高压发射链路,成本高 | 低电压射频链路,集成度高 |
| 典型场景 | 远程警戒、气象、航空 | 汽车、工业测距、人体感知 |
1.2 为什么现代感知系统偏爱 FMCW
现在的车载雷达、工业雷达、生命体征检测雷达,几乎清一色是 FMCW。一方面是因为半导体工艺让毫米波频段的射频前端集成度越来越高,一颗芯片就能完成多个收发通道;另一方面是因为 FMCW 本身就适合做高精度的中近距离测量。
我在实际项目里最直观的感受是,FMCW 对信噪比的要求比脉冲体制宽松很多。因为它是连续发射,回波能量不断累积,不需要瞬间大功率,而且目标的多普勒信息天然包含在相位里,测速非常方便。还有一个细节是,连续波的频谱宽度可以通过调频带宽来设计,想要更高的距离分辨率就把带宽做大,这在 79GHz 频段甚至能做到厘米级。对车来说,前方两个目标是否能分成两个点,直接关系决策系统判断;对生命体征检测来说,胸腔毫米级的起伏能不能被捕捉到,也取决于距离分辨率和相位的利用能力。
所以你会发现,FMCW 并不是一种“过时”的波形,它恰恰成了现代毫米波雷达的主流。理解了它的原理,再去接触 4D 毫米波雷达、摄像头与雷达融合,底层逻辑都是通的。
2. 从一条扫频曲线看 FMCW 测距原理
2.1 Chirp 信号与中频信号的来龙去脉
FMCW 雷达发射的信号频率不是固定的,而是跟着时间线性增加。频率随时间的变化率叫调频斜率,通常用 S 表示,S = B / Tc,其中 B 是扫频带宽,Tc 是单个 chirp 的持续时间。举个例子,24GHz 雷达模块工作带宽 200MHz,一个 chirp 扫 100 微秒,那么 S 就是每秒 2×10^12 Hz,换句话说,每秒频率上升 2THz,这个斜率很快,但接收端有能力处理。
信号发出去之后遇到目标反射回来,接收到的回波是发射信号的延迟副本。目标越远,延迟时间 τ 越大,τ = 2R / c。发射信号和接收信号同时送到混频器,混频器输出两个信号的频率差,这个差频信号称为中频信号或拍频信号。由于发射信号的频率一直在线性变化,延迟 τ 时间内发射信号已经多走了一段频偏,这段频偏就是 S×τ。这就是 FMCW 测距的最核心思想:把距离信息转换成了频率信息。
可以用一个双人合唱来类比。你在台上唱歌,旁边有一个收音机在放你的声音但有一点点延迟,两路声音叠加在一起就会出现“打架”的拍音。FMCW 的混频器干的也是类似的事,只不过一路是发射信号,一路是带延迟的回波,两者频率差异越大,拍音的音调就越高。目标越远,回波延迟越大,拍音越高,测音调就知道距离了。
2.2 用中频频率反推目标距离,公式怎么来的
如果目标在距离 R 处,回波延迟 τ = 2R / c,中频信号频率 f_IF 就等于 S × τ。代入之后:
f_IF = S × 2R / c = 2 S R / c
反过来就能解出距离:
R = c × f_IF / (2S)
这个公式是 FMCW 测距的基础,你可以把它理解成一把尺子:S 定了,每赫兹频率差对应多少米就定了。假设 S = 2MHz/us,即 2×10^12 Hz/s,目标在 40m 处,往返延迟大约是 2×40 / (3×10^8),也就是 266.7ns,中频频率就是 2×10^12 × 266.7×10^-9 ≈ 533.4kHz。一个几百 kHz 的音频段信号,处理起来非常轻松,普通 ADC 就能覆盖。
实际操作中还有一个容易被忽略的点:中频信号通常经过低通滤波后再进入 ADC,低通滤波器的截止频率要留够余量,不然会滤掉远距离目标的拍频成分。你可能会觉得反正采样率高一点就行,但采样率直接关系到 ADC 成本、数据处理量和功率消耗,做产品选型时要权衡,这一点我在后面参数设计部分会展开。
2.3 藏在相位里的毫米级线索:生命体征检测为何可行
很多人问,FMCW 距离分辨率只有几十厘米甚至一米,为什么还能做生命体征检测,检测人胸膛几毫米的起伏?答案就在中频信号的相位里。
当目标在一个距离 bin 内做微小位移时,回波延迟 τ 的变化非常小,小到频率上几乎看不出差别,但相位变化很明显。中频信号表达式里有一项和距离成正比的相位项,大约等于 4πR/λ,λ 是毫米波波长。以 24GHz 为例,波长 12.5mm,胸腔起伏如果是 2mm,相位变化会超过 1 弧度,这在复数信号上能看得出来。所以生命体征雷达提取的不是距离峰值的移动,而是目标所在距离 bin 上复数信号的相位随时间的变化。
这个细节很重要。做生命体征检测项目时,如果只画距离 FFT 的幅度谱,你会发现呼吸引起的波形几乎看不见;要取峰值处的复数数据,做相位解缠,再滤波,才能看到干净的呼吸和心跳波形。这也是为什么很多方案里会用 I/Q 两路数据,而不是简单只取幅度。可以说,FMCW 的相位信息把它的应用从测距拓展到了微动感知,这也是热词里“毫米波雷达生命体征”能成立的物理基础。
3. 测速原理与 FFT 在 FMCW 中的作用
3.1 多普勒效应如何叠加到中频信号上
FMCW 测速依赖多普勒效应。当目标相对雷达有径向运动时,回波信号除了有距离延迟,还会叠加一个多普勒频移。不过 FMCW 测速的方式和纯连续波雷达不完全一样。纯连续波雷达发射单频信号,靠多普勒频移直接测速度,但测不了距离;FMCW 因为发射信号本身就在调频,多普勒信息会叠加在拍频上,需要想办法分离距离和速度的贡献。
静止目标的拍频只取决于距离延迟;运动目标的拍频则等于距离延迟项 S×2R/c 加上多普勒频移项。拍频频率 f_b = f_r ± f_d,正负号取决于目标朝雷达靠近还是远离。实际系统里有两种常见处理:一种是用三角波调制,上扫频和下扫频分别得到 f_b_up = f_r - f_d 和 f_b_down = f_r + f_d,两者联立解出距离和速度;另一种是帧内多个 chirp,先做距离 FFT,再沿 chirp 方向做速度 FFT,也就是后面要说的 2D-FFT 方案。车载雷达主流用后者。
3.2 快慢时间维与 Range-Doppler Map
在一帧里连续发射多个完全相同的 chirp,每个 chirp 采样后做一次距离 FFT,会在对应的距离 bin 上得到一个复数峰值。如果目标是匀速运动的,那么不同 chirp 之间目标虽然还在同一个距离 bin 附近,但它的相位在逐渐变化。这个相位变化的速率正比于多普勒频率 f_d,而 f_d = 2v/λ。
于是可以把每个距离 bin 在不同 chirp 上的复数序列再拿来做一次 FFT。第一次 FFT 叫快时间维 FFT,对应距离;第二次沿 chirp 序号方向做 FFT,叫慢时间维 FFT,对应多普勒速度。出来的二维矩阵就是 Range-Doppler Map,横轴是距离 bin,纵轴是速度 bin,每个峰值代表一个目标的位置和速度。二维 FFT 做出来的图,在调试车载雷达时几乎天天看,是 FMCW 测速测距最标准的呈现方式。
我在实际开发 C++ 程序时,往往会先留意坐标系和数组排布。ADC 采样数据是 chirp 优先还是 sample 优先,直接影响 FFT 的方向和复杂度。常见的做法是先铺成一个大 buffer,第一个维度放采样点,第二个维度放 chirp 序号,先对每行做距离 FFT,再对每列做速度 FFT。如果 buffer 排布搞反,性能会差很多,缓存命中率也会很难看。
3.3 实际 C++ 工程里 FFT 怎么用才不踩坑
热词里有“毫米波雷达 c++ fft 程序”,这里给一段非常简化的处理框架,说明 FFT 在 FMCW 里是怎么位的。实际工程里你大概率会用现成的 FFT 库,比如 FFTW、KissFFT,或者芯片厂商自带的 DSP 库,但前处理和后处理逻辑是一致的。ADC 采到中频信号后,先做直流去除和加窗,再做距离 FFT;距离 FFT 结果做幅值计算后找峰值,同时保留复数数据用于后续相位分析。
#include <vector> #include <cmath> // 把中频采样点做Hamming窗处理后交给FFT void prepareFrame(std::vector<float>& samples) { size_t N = samples.size(); for (size_t i = 0; i < N; ++i) { float w = 0.54f - 0.46f * std::cos(2.0f * M_PI * i / (N - 1)); samples[i] *= w; } } // 找到距离FFT结果的主要峰值索引 size_t findPeakIndex(const std::vector<float>& mag) { size_t idx = 0; float maxVal = mag[0]; for (size_t i = 1; i < mag.size(); ++i) { float v = mag[i]; if (v > maxVal) { maxVal = v; idx = i; } } return idx; }这段代码里有个关键点:FFT 之前必须先加窗。你不加窗,目标能量会泄漏到相邻频点,弱目标可能直接被旁瓣淹没。Hamming 窗是我最常用的,因为它简单、主瓣不宽、旁瓣抑制够用;如果要区分两个非常接近的目标,可以考虑 Blackman-Harris,但主瓣会宽一点,近距离分辨时会吃亏。加窗是一种“以主瓣宽度换旁瓣抑制”的工程取舍,不是越多越好。
距离 FFT 之后,每个 bin 对应的频率间隔是 Fs / N,Fs 是采样率,N 是单 chirp 采样点数。把 bin 索引乘上频率分辨率,再套 R = c×f_IF/(2S) 的公式,就能把频率映射成距离。我见过不少初学朋友卡在这里,FFT 结果出来了却不知道 bin 和米之间的关系,因为少了一步频率定标。这一步不要只记公式,要在代码里显式算出来,最好写成一个函数,方便后来换参数。
4. 距离分辨率、最大探测距离和参数设计的账本
4.1 距离分辨率为什么由带宽决定
FMCW 的距离分辨率指的是雷达能把两个距离很近的目标区分开的最小间隔。根据傅里叶变换的性质,单个 chirp 持续时间内,中频信号实际是有限长的正弦波,频谱主瓣宽度约为 1/Tc。由于 f_IF = S×2R/c,频率分辨极限对应到距离上就是:
ΔR = c / (2B)
这个公式非常关键。B 是扫频带宽,和 Tc 没有关系。换句话说,你 chirp 扫得再久,如果带宽不够大,距离分辨率照样上不去。24GHz 的 ISM 频段一般能用的带宽在 200MHz 左右,对应距离分辨率约 0.75m;而汽车毫米波雷达常用 77GHz 频段,带宽能做到 1GHz 以上,分辨率能到 0.15m 甚至更小。
在做目标检测时,这个差距非常明显。77GHz 雷达能分清两辆前后相差 30cm 的车,而 24GHz 模块面对 1m 内的两个目标,融合成一个点是常有的事。如果你的场景是做智能座舱手势识别,需要识别手在身体前的微小移动,带宽不够就会很难受。这也是为什么很多感知方案宁愿换 60GHz 或 77GHz,也不死磕 24GHz 的原因。
4.2 最大探测距离受什么限制
很多人以为最大探测距离主要由发射功率决定,这只是其中一个因素。FMCW 里有一个更直接的硬约束:中频信号的最高频率不能超过 ADC 采样率的一半。因为中频频率和距离线性相关,所以采样率决定了最大无模糊距离,即 Rmax = Fs × c / (4S)。如果你把 S 设得太大,可能几十米以外的目标产生的拍频已经超过奈奎斯特频率,随后就会被混叠成近处目标,形成虚假目标。
实际操作中,Rmax 这个公式用得非常谨慎。比如采样率 Fs = 10MHz,S = 2MHz/us,那么理论最大距离是 10×10^6×3×10^8/(4×2×10^12) = 375m,看起来很大,但实际系统根本到不了这么远。因为随着距离增加,回波能量按四次方衰减,信噪比才是最大探测距离的真正瓶颈。常规 24GHz 模块标称 40m,算出来的拍频只有几百 kHz,ADC 轻松覆盖,真正卡你的是发射功率、天线增益、接收机噪声系数和目标的雷达散射截面。
所以参数设计时要分两步看:先用采样率和 S 保证系统不会出现距离模糊;再通过链路预算计算信噪比,确认在某距离上能不能检测到目标。这两个都满足,标称探测距离才有意义。很多模块标了 40m,实际在空旷走廊里测人也只有二十几米,多半不是因为公式不对,而是目标的反射截面太小,信噪比不够。
4.3 24GHz 40m 模块实例:把参数算给你看
拿热词里的“24ghz 毫米波雷达模块 40m”来做一个完整参数设计例子。假设可用扫频带宽 B = 200MHz,chirp 时长 Tc = 100us,那么 S = B / Tc = 2MHz/us。目标 40m 处,拍频 f_IF 大约 533kHz,ADC 采样率设 5MHz 绰绰有余,还能留出余量处理更近处的强反射。
再看距离分辨率,B=200MHz 时 ΔR = c/(2B) = 0.75m。这意味着两个相距 0.75m 以内的目标在距离维度上就分不开了。如果你做的是人形目标检测,这个分辨率够用;如果做车载防撞,就必须上带宽更大的频段。速度方面,如果一帧 64 个 chirp,帧周期做的短一些,速度分辨率大概能做到零点几米每秒。具体就要看有多少个慢时间采样点,FFT 的长度越长速度分辨率越高,但帧率会下降,实时测速时要注意平衡。
| 参数 | 数值 | 说明 |
|---|---|---|
| 中心频率 | 24GHz | ISM 频段,波长约 12.5mm |
| 扫频带宽 B | 200MHz | 距离分辨率 0.75m |
| Chirp 时长 Tc | 100us | 决定调频斜率 S |
| 调频斜率 S | 2MHz/us | 频率变化速率 |
| ADC 采样率 Fs | 5MHz | 远大于 40m 处拍频 533kHz |
| 理论最大距离 | 375m | 受采样率限制的无模糊距离 |
| 实际探测距离 | 40m | 受发射功率、信噪比限制 |
这套参数是典型的低成本 24GHz 模块设计,性价比很高。如果换到 77GHz 车载雷达,带宽做到 1GHz,距离分辨率提升到 15cm,但射频前端和中频处理复杂度也会跟着上来。不同频段的取舍,最后都会落在物理带宽、硬件成本和应用需求三者的平衡上。
5. 工程调试中常见的坑与排查思路
5.1 距离维 FFT 前的信号调理
第一个高频坑是直流偏置。混频器输出信号往往带有很大的直流分量,这个分量在 FFT 后会变成 0Hz 附近的一个大峰,如果目标本身离得很近,它的拍频很小,很容易被直流峰盖住。解决方法是硬件上加高通滤波,软件上先对采样序列做均值相减,或者用一个高通 IIR 滤波器把直流去掉。我在调 24GHz 模块时,经常遇到近距离目标被误判为空,去完直流后立刻能看到目标峰。
第二个坑是加窗。有些刚写 FFT 程序的人图省事,直接把原始数据扔进 FFT,结果远处弱目标被强目标的旁瓣盖掉。加窗不是可有可无的操作,尤其在多目标场景下,它决定了你能否分辨微弱目标。加窗后幅度会有损失,Hamming 窗会带来约 1.4dB 的损耗,小目标检测时会稍微吃点亏,但换成漏检问题更麻烦。
第三个坑是频率定标。FFT 输出的 bin 索引换算到距离时,如果漏掉 S 和 Fs 的参数换算,距离会整体偏差。我习惯把 S、Fs、N、c 全部写成常量并附上单位注释,每次改参数后先算一遍静止目标在已知位置的峰值,确认距离对了再继续调算法。
5.2 多目标、杂波与多径
多目标情况下,距离 FFT 会有多个峰,每个峰对应一个目标。但真实环境里还有墙、地面、金属护栏这类强反射体,它们产生的峰可能比真实目标还要大。静态杂波可以用 MTI 或者帧间差分来抑制,也可以做一个背景相消:在无目标场景采集一帧数据,把它的复数谱记下来,后续每帧减去这个背景。这个方法简单有效,但前提是雷达安装位置固定,如果雷达本身在动,就得换杂波图方案。
多径是一个更隐蔽的麻烦事。比如雷达在测试,目标旁边正好有一块金属板,电磁波可以直接打到目标再回来,也可以先打到金属板再反射到目标,再原路返回。多径会产生额外的虚假峰,通常出现在目标距离乘以某个整数倍的位置,让数据看起来像“幽灵目标”。我遇到多径问题时,一般先挪动物体位置,看虚假峰是否按两倍距离的规律移动,如果是,大概率就是多径。
还有一个常见现象是目标走动导致距离 bin 跨越。运动目标在一帧里如果移动超过半个距离分辨率,距离 FFT 的峰会在多个 chirp 之间漂移,慢时间维 FFT 做出来速度谱就会比较糊。这时候需要更小的 chirp 时长,或者对每个 chirp 的距离峰先做峰值对齐再提取相位。这也是为什么高动态场景下,参数设计时不仅要看分辨率,还要看最大不模糊速度和目标最大加速度。
5.3 从原理到应用:生命体征、车载与多传感器融合
说回热词里的几个关键词。生命体征检测用到的就是前面提到的相位提取,而不是距离 FFT 的幅度峰值。我做一个呼吸检测 demo 时,第一步先检测人体位置,第二步在对应的距离 bin 上取复数相位时间序列,第三步用带通滤波把 0.1~0.5Hz 的呼吸信号和 0.8~2Hz 的心跳分量分离。中间最要小心的是相位跳变,需要做相位解缠,否则会看到不连续的跳变点。
车载场景下的 4D 毫米波雷达,就是多个发射通道和接收通道通过 MIMO 机制合成虚拟阵列,在距离、速度之外再增加方位角和俯仰角的估计能力。这个方向已经完全建立在 FMCW 的二维 FFT 基础上,只是在维度上继续往上加。而摄像头与毫米波雷达做目标时空同步时,核心难点在于两边的采样频率不同、坐标系不同,时间戳对齐往往要用插值和滤波器外推,空间上要做标定矩阵。FMCW 输出的是距离、速度、角度点云,摄像头输出的是 RGB 图像,两者融合前必须先把目标 ID 和时间戳配对好。这些都是原理一之后的进阶内容,但底层都是先理解以下这件事:雷达告诉你目标在哪、移动多快,摄像头告诉你目标长什么样。
6. 一些上手建议和个人体会
6.1 先从仿真开始,再碰硬件
如果你刚接触 FMCW,我强烈建议先写一个简单的 Python 或 MATLAB 仿真,按照上面那组参数生成发射信号、目标回波、中频信号,再做 FFT 看看峰值。这个流程走完,你对 FMCW 的理解会比直接调模块深刻很多。仿真里能随意改带宽、采样率、目标距离,亲手观察峰值位置怎么变,慢慢就对公式有了直觉。
仿真做通了再碰硬件。我最初用开发板调 24GHz 模块时,采集一帧数据回来,先在电脑上用脚本做 FFT,确认每个步骤输出都符合预期,再移植到 C++ 里。这样能减少很多排查时间。保持同样的处理链路,后续换传感器只是换参数的问题。
6.2 多留存几组基线参数
调试过程中不要只调一组参数。我会把同一场景下的多组带宽、chirp 时长、采样率组合记录下来,对比它们在距离分辨率、最大探测距离和信噪比上的表现。特别是做车载或者机器人避障应用时,不同安装高度、不同地面材质都会影响多径杂波,预留几组参数预案能让你现场快速切方案。
另外,我会定期回测静止目标。雷达模块在室内外温度变化时,中频信号幅度和噪声底噪会有变化,先用角反射器校准一次,确认距离峰和理论值误差在允许范围内,再做下一轮标定。这个小习惯帮我挡掉过不少环境引起的数据异常。
如果你准备往毫米波方向深入,建议把距离 FFT、速度 FFT、恒虚警检测(CFAR)、目标聚类、跟踪滤波这几块依次吃透。FMCW 原理看着简单,但每个环节都有很多细节值得抠。这篇先把测距测速的根扎稳,后面无论是 4D 成像还是多传感器融合,都能顺着这条主线往下走。