提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
汽车 FMCW 雷达可以精确测量车辆周边障碍物以及车辆与其他车辆的相对距离和相对速度,也因此汽车毫米波雷达成为汽车自动驾驶应用中(例如如停车辅助,变道辅助,自动刹车和防撞)非常重要的传感器。雷达相对于摄像头和激光雷达一个重要优势是毫米波雷达不受环境条件(比如雨雪雾,灰尘,烟雾)的影响,是全天侯传感器,即便在完全黑暗的环境下以及强太阳光照射下仍能正常工作。尽管雷达技术有很多优点,但在很多情况下,汽车制造商仍然使用摄像头作为主要传
感器,一个主要原因是毫米波雷达的角度分辨率以及距离分辨率低。本文详细描述了一种用于汽车毫米波雷达的高距离分辨率,高无模糊速度FMCW 波形设计,在常规的FMCW 波形设计中,为了提高距离分辨率,往往需要采用高的扫频带宽,同时为了保证远的探测距离,因此需要更高的距离维 FFT 的点数。在 ADC 采样速率一定的情况下,这意味着更长的 chirp 周期,而更长的 chirp 周期往往导致更低的最大无模糊速度,因此为了解决高距离分辨率和最大无模糊速度这对矛盾,本文提出了一种将一个长 chirp 拆分成数段级联短 阶跃chirp 来保证高无模糊速度,在数字处理端通过将数段短 chirp 级联恢复成一个长 chirp实现高距离分辨率和远的探测距离。
一、常规波形设计
在本设计中采用的设计参数如下表所示,一个Frame由128个chirp组成,每个chirp采用20MSPS的ADC采样512个点,chirp起始扫描频率为77GHz,扫频带宽为150MHz,chirp和chirp之间的间隔时间为35us。
Parameter | Value |
---|---|
samples_per_chirp | 512 |
chirps_per_frame | 128 |
start_freq | 77GHz |
chirp_bandwideth | 150MHz |
stop_freq | 77.15GHz |
adc_sample_rate | 20MSPS |
chirp_to_chirp_time | 35us |
range_resolution | 1m |
velocity_resolution | 0.434m/s |
max_range | 256m |
max_unambigous_velocity | 27.78m/s |
波形设计的示意图如下,其中512个采样点对应着chirp的active时间,chirp的reset时间用于VCO回拨到起始频率,两个chirp的起点之间的间隔chirp_to_chirp_time为一个chirp的持续时间,包含active,reset以及chirp之间的间隔时间。
在本设计中,我们将目标的Range index设置为8,Doppler Index设置为30,对应Range-Doppler热图和Range_FFT和Doppler_FFT如下图所示:
二、级联阶跃chirp
在FMCW常规波形设计中,无模糊最大速度反比于chirp_to_chirp_time,也因此如果想要获取更大的无模糊速度,需要更短的chirp_to_chirp_time,也意味着更短的active时间,在ADC采样率固定的情况下,意味着更少的ADC采样点数,在更少的ADC采样点数情况下,为了保证采样距离,因此需要牺牲距离分辨率,也即降低扫频带宽。
在常规波形设计中,距离分比率和最大无模糊速度是一对矛盾,为了保持高的无模糊速度,往往牺牲距离分辨率,因此迫切的需要一种既能保证高的无模糊速度,又能保持高的距离分辨率的波形设计,本文提出了一种阶跃波形设计,将一个高分辨率的长chirp拆分成数段短的阶跃chirp,短的chirp_to_chirp_time意味着更高的无模糊速度,通过数字信号处理将数段短的阶跃chirp进行连接获取长的chirp,相当于延长了扫频带宽,可以带来更高的距离分辨率,级联阶跃chirp示意图如下:
1阶跃chirp为什么要重叠?
在阶跃chirp示意图中chirp1的起始频率要低于chirp0的终止频率,也就是相邻chirp之间扫频带宽要有重叠。实际上,如果雷达前方都是静止物体,那么chirp1 的起始频率可以等于chirp0的终止频率,然后在数字端将chirp1的512个ADC采样点直接附加于chirp0的512点之后即可,因为雷达前方都是静止物体,不会有物体速度引入的相位不连续,chirp1的头和chirp0的尾可以直接相连,不会有任何问题。
但是如果雷达前方的物体有速度,那么就不能将chirp1的头和chirp0的尾进行直接相连,物体速度引起的在chirp1的头和chirp0的尾上有相位不连续,直接相连会引入一个阶跃相应,污染整个Range_FFT,因此需要进行相位补偿。为便于分析,我们假设目标距离雷达的径向距离为S,目标速度为V,chirp0的起始频率为77GHz,终止频率为77.15GHz,扫频带宽为150MHz,chirp1的起始频率为77.075GHz,正好为于chirp0的中间频率,也即对chirp0来讲512个ADC采样点,第256个采样点对应的频率77.075GHz。由于chirp1的起始点频率也为77.075GHz,chirp1的起始点和chirp0的中间点之间的时间间隔为t_compensated=chirp_to_chirp_time/2,也即整半个chirp周期时间,那么在t_compensated时间内,目标移动了V*t_compensated距离相对于目标距离S,其相当于延长了雷达回波的风行时间,故而增加了中频回波信号的相位,其等效载波频率增加了
start_freq * V * t_compensated/2/S, 增加的频率对应ADC采样点数为
samples_delayed=start_freq * V * t_compensated/2/S/frequency_slope/sample_interval
,
其中frequency_slope对应于chirp的扫频斜率,对应我们设计就是150MHz/(samples_per_chirp * sample_interval) 其中sample_interval是ADC的采样间隔,上述公式中samples_delayed是采样点偏移,也就是我们在进行chirp1 和chirp0的级联时相对静止目标的级联点应该偏移的ADC采样点数。
在上图中,如果是静止目标,我们可以按照如下np.concatenate((chirp0[:],chirp1[256:]))进行级联,但是由于目标速度V,这里我们假定为正向速度,那么因为目标速度而导致相位增加,在chirp0上等效于更高的扫频频率,因此对应级联公式为np.concatenate((chirp0[:],chirp1[256-Samples_delayed:]))。
2 阶跃频率限制
综合以上分析,我们chirp1和chirp0之间的频率阶跃不能太大,chirp1的起始频率必须低于chirp0的终止频率,其二chirp1的起始频率低于chirp0的终止频率的幅度,取决于目标的速度,要大于samples_delayed的最大值,要能够补偿。其次级联的chirp数量不能太多,在本设计中,是4个chirp进行级联,如果chirp级联过多,会导致目标测速不准,并且会引起doppler维的频谱扩展。
我们本设计用例的Range-Doppler热图和Range_FFT和Doppler_FFT如下图所示:
从图中可以看到,doppler维的信息,并没有因为chirp阶跃而变差。
我们chirp0到chirp3,这4个chirp进行级联后得到,我们得到了一个1304点长chirp,其相对于512点的短chirp来讲,chirp长度扩展1304/512=2.55,也可以认为,我们的扫频带宽从150MHz增加到150*1304/512=382MHz,距离分辨率从1米提高到39cm。级联后的chirp如下图所示,从图中我们也看出经过我们相位补偿后,调整samples_delayed个样本点拼接后,相位连续。
3 实际操作
如果在实际应用场景中,有很多个目标,每个目标的运动速度都不一样,那么该如何补偿?我的建议是尽量缩短chirp1的初始采样点和chirp0末尾采样点之间的时间间隔,这个时间越短越好,越短就意味着可以不用进行补偿,如果时间为0,那么因为速度引入的相位变化也为0,也就没必要进行chirp拼接点的调整,本文是了详细介绍拼接原理,选择是chirp1的起始频率等于chirp0的中间频率,实际操作中chirp1的起始点频率等于chirp0末尾10到20点进行拼接。其次,总拼接chirp的频率阶跃不能太大,太大会引起目标测量速度计算错误,偏正向速度,即正向速度变点的更大,原因是阶跃频率的增加引入的额外相位增加。
4.仿真Python代码
# -*- coding: utf-8 -*-
"""
Created on Tue Sep 5 14:47:27 2023
@author: DELL
"""
'''
主脚本不允许相对import,只允许绝对路径
'''
from simulation.simulation import trapezoid_phase,get_one_sample
from dsp.fft_on_series import *
from scipy import constants
import numpy as np
import matplotlib.pyplot as plt
'''1 list parameters here'''
samples_per_chirp=512
chirps_per_frame=128
start_freq=77e9
chirp_bandwidth=0.15e9
stop_freq=start_freq+chirp_bandwidth
adc_sample_rate=20e6
chirp_to_chirp_time=35e-6
sample_interval=1/adc_sample_rate
center_frequency=(start_freq+stop_freq)/2
range_resolution=(constants.c)/2/(stop_freq-start_freq)
velocity_resolution=(constants.c)/(center_frequency)/4/chirp_to_chirp_time/(chirps_per_frame/2)
frequency_slope=(stop_freq-start_freq)/(samples_per_chirp*sample_interval)
##target parameters here
'''2. normal chirp'''
target_range=8*range_resolution
target_velocity=30*velocity_resolution
start_freq=77e9
#target range and target velocity should be declared for every simulation
frame_data=np.zeros((chirps_per_frame,samples_per_chirp))
for c in range(chirps_per_frame):
for s in range(samples_per_chirp):
tof_time_of_target=2*target_range/(constants.c)
frame_data[c,s]=get_one_sample(start_freq,frequency_slope, tof_time_of_target)
target_range=target_range+target_velocity*sample_interval
start_freq+=frequency_slope*sample_interval
target_range+=target_velocity*(chirp_to_chirp_time-samples_per_chirp*sample_interval)
start_freq=77e9
range_fft = np.apply_along_axis(func1d=fft_spectrum_on_series,
axis=1,
arr=frame_data,
dc_remove_flag=True)
doppler_fft = np.apply_along_axis(func1d=fft_spectrum_on_series,
axis=0,
arr=range_fft,
dc_remove_flag=True)
'''3. stepped chirp'''
#in order to prevent the doppler spread caused by the stepped frequency, we have 4 stepped chirp in one group
stepped_chirps_in_one_group=4
target_range=8*range_resolution
target_velocity=30*velocity_resolution
start_freq=77e9
frame_data_stepped=np.zeros((chirps_per_frame,samples_per_chirp))
for c in range(chirps_per_frame):
start_freq=77e9+(c%stepped_chirps_in_one_group)*chirp_bandwidth/2
for s in range(samples_per_chirp):
tof_time_of_target=2*target_range/(constants.c)
frame_data_stepped[c,s]=get_one_sample(start_freq,frequency_slope, tof_time_of_target)
target_range=target_range+target_velocity*sample_interval
start_freq+=frequency_slope*sample_interval
target_range+=target_velocity*(chirp_to_chirp_time-samples_per_chirp*sample_interval)
range_fft_stepped = np.apply_along_axis(func1d=fft_spectrum_on_series,
axis=1,
arr=frame_data_stepped,
dc_remove_flag=True)
doppler_fft_stepped = np.apply_along_axis(func1d=fft_spectrum_on_series,
axis=0,
arr=range_fft_stepped,
dc_remove_flag=True)
concatenated_series=frame_data_stepped[0,:]
# for c in range(num_chirps_per_frame-2,-1,-1):
# concatenated_series=np.concatenate((frame_data[c,:chirp_start_freq_shift_value],concatenated_series))
samples_delayed=np.ceil(start_freq*target_velocity*chirp_to_chirp_time/2/target_range/frequency_slope/sample_interval)
samples_delayed=int(samples_delayed)
for c in range(1,stepped_chirps_in_one_group):
concatenated_series=np.concatenate((concatenated_series,frame_data_stepped[c,samples_per_chirp//2-samples_delayed:]))
'''4.plot'''
plt.close("all")
fig1=plt.figure("High Resolution Stepped Chirp",figsize=(12,8))
fig1.suptitle('High Resolution Stepped Chirp\nhongsheng.wang@avnet.com', fontsize=12)
ax1=fig1.add_subplot(311)
ax2=fig1.add_subplot(312)
ax3=fig1.add_subplot(313)
ax1.set_title(f"Normal Chirp Doppler Heatmap")
ax1.set_xlabel("Range Index")
ax1.set_ylabel("Doppler Index")
ax2.set_title(f"Range FFT")
ax2.set_xlabel("Range Index")
ax2.set_ylabel("Doppler Index")
#ax2.set_xlabel("Heartbeat Rate in BPM")
ax3.set_title(f"Doppler FFT ")
ax3.set_xlabel("Range Index")
ax3.set_ylabel("Doppler Index")
fig1.tight_layout()
ax1.imshow(np.abs(doppler_fft[:,:samples_per_chirp//2]))
ax2.plot(np.abs(doppler_fft[30,:samples_per_chirp//2]))
ax3.plot(np.abs(doppler_fft[:,8]))
#ax2.imshow(np.abs(doppler_fft_stepped))
#ax3.plot(frame_data[0,:],label="normal frame data")
#ax3.plot(concatenated_series,label="concatenated adc data")
#ax3.imshow(np.abs(doppler_fft_stepped_chirp))
总结
本文章提出了一种阶跃级联chirp设计,在不牺牲最大无模糊速度的前提下,将数个短的chirp,如本例中chirp0到chirp3拼接成一个长chirp,拼接原则,一个是控制chirp0的最后一个采样点,和chirp1之间第一个采样点的时间间隔,这个时间越小越好,这个时间如果长,那么目标速度会引入额外的相位增长,为了补偿这个相位增长,需要移动chirp拼接点。其次严格控制chirp级联个数,以及总的阶跃频率,防止错误的目标速度计算。