【二】FMCW雷达距离检测的实现 【二】FMCW雷达距离检测的实现

【二】FMCW雷达距离检测的实现

注:这里的距离检测适用于FMCW雷达,而不是Pulse LFM雷达。

基本思路

FMCW雷达发射的扫频信号频率随时间线性上升。接收到的回波信号是发射信号在一段时间 Δt\Delta t 之后的延迟信号。将发射信号与接收信号混频后,会产生一个频率恒定的中频信号,称为拍频 (fbf_b)。而目标越远,回波延迟 Δt\Delta t 越大,发射和接收信号之间的频率差 fbf_b 就越高 。因此通过检测fbf_b 的大小即可得到距离。

去除直流偏置

假设已经得到了某个天线16×128的接收信号,令为变量mat。详情见英飞凌毫米波雷达接收数据的格式

avgs = np.average(mat,1).reshape(config.num_chirps,1)
mat = mat - avgs

FFT运算

加窗

由于FFT是有限长的,这会导致频谱泄露的情况,加窗可以压制旁瓣,虽然会稍微牺牲一点分辨率,但能更容易发现大目标旁边的微弱小目标。

在这里我们加的是Blackman-Harris 窗

mat = np.multiply(mat,signal.windows.blackmanharris(config.chirp.num_samples).reshape(1,config.chirp.num_samples))

TODO:不同窗函数的特性和应用场景?

补零

zp1 = np.pad(mat,((0,0),(0,config.chirp.num_samples)),'constant') # 补零

在 samples维度末尾填充一倍长度的零。补零并不会提高雷达物理上的“分辨率”,但它增加了频率轴上的采样点密度,使 FFT 后的频谱图更加平滑,有助于更精确地定位反射峰值的中心。

执行FFT

range_fft = np.fft.fft(zp1)/config.chirp.num_samples
range_fft = 2*range_fft[:,range(int(config.chirp.num_samples))]

沿着快时间(Samples)轴进行 FFT,并只取前一半。为什么只取前面一半呢?

这是因为对于任何长度为 NN实数序列 x[n]x[n],其离散傅里叶变换(DFT)结果 X[k]X[k] 满足 X[k]=X[Nk]X[k] = X^*[N-k] 由于BGT60TR13C 给出的是实数信号,因此根据上面的性质,经过FFT得到的频谱是中心对称的。后一半数据(负频率部分)是前一半的镜像,不包含额外信息,因此直接舍弃。乘以 2 是为了保持原始信号的振幅量级,补偿由于舍弃负频率带来的幅度损失。如下图所示。

Pasted image 20260428152142

Pasted image 20260428152151

计算谱图

range_fft_abs = abs(range_fft)
distance_data = range_fft_abs.sum(axis=0)

对FFT运算得到的距离谱图取模,在chirp维度将幅度求和,聚合能量,找峰值就可以得到谱(如上图图2所示)。

当然还有一步,就是将index转换为真实距离。公式如下:

Δd(单格分辨率)=cNsamples2BsNFFT(单位:m)\Delta d\text{(单格分辨率)}= \frac{c\cdot N_\text{samples}}{2B_s\cdot N_\text{FFT}}\text{(单位:m)}

其中NFFTN_\text{FFT}为在这里为256(因为补了128个零,总共256点FFT)。根据本文的参数配置计算得到Δd=0.0375\Delta d=0.0375,也就是一格代表3.75cm。将坐标进行映射即可。在本实验中我们补零的数量等于NsamplesN_\text{samples},因此有NFFT=2×NsamplesN_\text{FFT}=2\times N_\text{samples},即

Δd(单格分辨率)=c4Bs(单位:m)\Delta d\text{(单格分辨率)}= \frac{c}{4B_s}\text{(单位:m)}
index_to_distance_cm = 3e8 * config.chirp.num_samples / (2 * bandwidth_hz * config.chirp.num_samples * 2) * 100 # in cm
print(f"index_to_distance_cm={index_to_distance_cm:.2f} cm")
range_bins = np.arange(config.chirp.num_samples) * index_to_distance_cm

寻找波峰

完成谱图构建后,最后就是找峰值作为波峰。在上面的图中我们发现有两个峰值,但实际上靠近0的波峰是一个伪峰,它属于直流泄露,大致是由于天线间耦合导致的。在这里我们暂时不深入探究它出现的原因和解决方案,我们直接屏蔽前8个index,在第9个index开始寻峰。

range_bins = np.arange(config.chirp.num_samples) * index_to_distance_cm # 映射坐标
skip = 8
distance_peak = np.argmax(distance_data[skip:])
distance_peak_cm = index_to_distance_cm * (distance_peak + skip)
print(f"Distance Peak: {distance_peak_cm:.2f} cm") # Distance Peak: 37.50 cm

至此,测距功能就完成了。

参考文献

Infineon RFS SDK Documentation Python Wrapper部分。


← Back to blog