3. 雷达信号处理链
各位同学,今天我们来啃一块硬骨头——毫米波雷达的信号处理链。说实话,我刚入行那会儿,看着这一串缩写(ADC、FFT、CFAR、DOA)也是头皮发麻。但后来我发现,只要把这条链上的每个环节拆开来看,其实没那么玄乎。
这条链说白了就是:把天线收到的模拟回波,变成我们能用来定位的数字信息。我习惯把它分成五个步骤,每一步都有它的脾气。
核心逻辑: 原始模拟信号 → 数字离散化 → 距离维分析 → 速度维分析 → 目标检测 → 角度估计
3.1 ADC采样:从模拟世界到数字世界的第一步
ADC(模数转换)是整个信号处理链的入口。天线接收到的回波是连续的模拟信号,但我们的处理器只认0和1。ADC的作用,就是按照一定的速率对这个连续信号「拍照」,拍成一个个离散的数字点。
采样率怎么定? 这里有个硬规矩——奈奎斯特定理。采样率至少要是信号最高频率的两倍。我见过有人为了省成本把采样率压得很低,结果目标距离模糊得一塌糊涂。嗯,省下来的钱全花在调试上了。
我的经验: 实际项目中,我一般会把采样率留出20%~30%的余量。比如理论需要2MHz,我会设到2.5MHz。多出来的这点余量,能帮你挡住不少高频噪声的混叠问题。
ADC的另一个关键参数是量化位数。12位还是14位?这取决于你的动态范围需求。如果场景里既有近处的大目标(比如卡车),又有远处的小目标(比如行人),位数低了,小目标就被量化噪声淹没了。
3.2 1D-FFT:把时间信号变成距离信息
ADC采样完,我们得到的是时域信号。但雷达想要的是「距离」。怎么从时间到距离?靠傅里叶变换。
1D-FFT(一维快速傅里叶变换)是对每个chirp(调频脉冲)的采样点做FFT。为什么能测距?因为发射信号和回波信号之间存在频率差,这个差值和距离成正比。FFT能把不同频率的成分分离开,每个频率bin就对应一个距离门。
// 伪代码示例:1D-FFT处理
for each chirp in frame:
// 对每个chirp的ADC采样数据做FFT
range_fft_result = FFT(adc_samples, N_fft);
// 取模得到幅度谱
range_magnitude = abs(range_fft_result);
// 存储到距离-脉冲矩阵
range_doppler_matrix[:, chirp_idx] = range_magnitude;
这里有个细节:窗函数。直接做FFT会有频谱泄露,旁瓣会干扰相邻距离门的目标检测。我习惯加一个汉宁窗或者布莱克曼窗。代价是主瓣稍微变宽一点,但旁瓣能压下去20~30dB,值了。
3.3 2D-FFT:把距离信息变成速度信息
1D-FFT做完,我们有了距离信息。但目标在动,怎么测速?
2D-FFT的思路是这样的:对同一个距离门,在不同chirp之间再做一次FFT。因为运动目标的多普勒频移会体现在chirp之间的相位变化上。第二次FFT就把这个相位变化提取出来了,每个多普勒bin对应一个速度。
为什么会这样?你想想看,一个静止目标,每个chirp的回波相位是一样的。但运动目标不一样,它在每个chirp之间移动了一点点距离,导致相位在累积变化。这个变化率就是速度。
| 维度 | 第一次FFT(1D) | 第二次FFT(2D) |
|---|---|---|
| 输入 | 单个chirp的ADC采样点 | 同一距离门的所有chirp |
| 输出 | 距离-幅度谱 | 距离-多普勒图(RD图) |
| 物理意义 | 目标距离 | 目标速度 |
| 分辨率 | c/(2*B),B为带宽 | λ/(2*T_frame),T_frame为帧周期 |
注意: 2D-FFT做完后,我们得到的是距离-多普勒图(RD图)。这张图是后续所有检测的基础。我曾经在调试时发现RD图上有一条亮线贯穿所有距离门,排查了半天才发现是电源纹波耦合进了ADC参考电压。所以,RD图的质量直接反映了硬件底噪水平。
3.4 CFAR检测:从噪声中揪出真正的目标
RD图出来了,上面有山峰有低谷。哪些是目标?哪些是噪声?
CFAR(恒虚警率检测)就是干这个的。它的核心思想是:动态计算每个检测单元周围的噪声水平,然后设定一个自适应阈值。超过阈值的,判为目标;没超过的,判为噪声。
CFAR有几种常见变体:
- CA-CFAR(单元平均):取检测单元两侧的参考窗,计算平均噪声功率。简单,但多目标场景下容易互相遮蔽。
- OS-CFAR(有序统计):对参考窗内的功率排序,取第k个值作为噪声估计。抗干扰能力强,但计算量大。
- SO-CFAR/GO-CFAR:分别取两侧参考窗的最小值/最大值。用于处理边缘场景。
我个人习惯用OS-CFAR。为什么?因为自动驾驶场景里经常出现多个目标挨得很近的情况,CA-CFAR会把旁边的目标也算进噪声里,导致漏检。OS-CFAR虽然慢一点,但鲁棒性好很多。
避坑指南: 我曾经在高速场景下用CA-CFAR,结果两个并排行驶的卡车互相遮蔽,系统只检测到一个。后来换成OS-CFAR,问题解决。另外,参考窗的大小也要根据场景调整——城区场景目标密集,参考窗可以小一点;高速场景目标稀疏,参考窗可以大一点。
3.5 DOA估计:确定目标的方向
CFAR检测告诉我们「哪里有目标」,但没告诉我们「目标在哪个方向」。DOA(波达方向估计)就是来解决这个问题的。
DOA估计依赖多根接收天线。不同天线接收到的同一个目标的回波,存在相位差。这个相位差和目标的到达角(AoA)直接相关。通过比较天线间的相位差,就能算出角度。
常用的DOA方法有:
- 数字波束形成(DBF):对多天线数据做FFT,每个角度bin对应一个波束指向。简单,但角度分辨率受限于天线数量。
- MUSIC算法:基于子空间分解,能突破天线数量的分辨率限制。但计算量大,且需要精确的天线校准。
- ESPRIT算法:利用天线阵列的旋转不变性,不需要精确的阵列流型。比MUSIC快,但精度略低。
在嵌入式平台上,我一般用DBF。为什么?因为MUSIC和ESPRIT虽然精度高,但实时性很难保证。TI的AWR系列芯片内部集成了硬件加速器,做DBF几乎不占CPU时间。如果你用FPGA,可以考虑MUSIC,但要做好资源规划。
// DOA估计的简化流程(DBF方法)
// 假设有M根接收天线,CFAR检测到了K个目标
for each target k:
// 提取该目标在M根天线上的复数值
complex signal[M] = extract_signal(rd_map, target_k, antenna_indices);
// 对M个复数值做FFT(角度FFT)
complex angle_spectrum = FFT(signal, M);
// 找到峰值对应的角度bin
int peak_bin = find_peak(angle_spectrum);
// 将bin索引映射到实际角度
float angle = bin_to_angle(peak_bin, M);
关键点: DOA估计的精度受天线间距影响。标准做法是天线间距取半波长(λ/2)。间距大了会有栅瓣(角度模糊),间距小了角度分辨率不够。我见过有人为了省天线面积把间距缩小到λ/4,结果角度分辨率直接砍半,远距离目标的角度误差大到没法用。
好了,以上就是雷达信号处理链的五个核心环节。从ADC采样到DOA估计,每一步都有它的物理意义和工程陷阱。做自动驾驶定位,这条链上的任何一个环节出问题,最终都会反映在定位精度上。所以,别嫌麻烦,每个环节都要吃透。