本文编辑: @调皮连续波 ,保持关注调皮哥,获得更多雷达学习资料和建议!
大家好,我是调皮哥,今天继续给大家分享干货,助力大家轻松、快乐、有方向地学习雷达。
通常,我们都是采用Matlab进行雷达系统设计,或者进行相关的算法仿真。Matlab的确是一个十分强大的工具,但随着越来越多的雷达er 开始使用Python进行雷达设计,我们不得不对基于Python的FMCW雷达信号处理仿真做一次详细的介绍,以便于后来的雷达初学者能够了解到更全面的信息,开拓视野。
本文的主要内容如下:
一、距离检测
(一)距离检测原理
调制连续波雷达也称为调频连续波(FMCW) 雷达,是一种使用频率调制技术测量目标距离的系统。
在频率调制中,电磁波的频率随时间线性增加。换言之,发射频率将以恒定的速率变化,这种频率随时间线性增加的信号称为“啁啾(Chirp) ”。FMCW系统测量发射和反射信号频率间的瞬时差 ,也叫做中频信号、差频信号、差拍信号 ,它与时间差 成正比,可用于估计目标的距离。
下图(左)显示了啁啾信号的频率与时间的关系,右图显示了频率随时间线性增加的啁啾信号的幅度与时间的关系。啁啾信号的特征在于起始频率( )、带宽( ) 和持续时间( ), 啁啾信号 的斜率定义啁啾信号 上升的速率,斜率为 。
雷达前方的单个目标会产生一个恒定频率的中频信号(IF signal),频率由下式给出: 其中, 是目标与雷达的距离,单位为 , 是光速,单位为 m/s。因此,我们可以通过测量IF信号经过(DFT)FFT后的频率来估计目标的距离。
本文关于原理部分的介绍十分简单,关于更细节的内容可以阅读之前分享的文章:雷达原理 | 用MATLAB信号处理是如何解算目标的距离和速度信息的?
(二)距离检测Python仿真
这里我用的Python开发平台是Spyder最新版本,属于开源软件。虽然没有Pycharm那么强大,库没有那么多,但对于简单的程序仿真完全足够了,软件安装也简单,没有Python基础的人也就一个星期就学会这个工具了,有了Matlab基础的人直接就可以上手了。(Spyder下载链接:https://www./)
教程以及代码和之前分享的Matlab差不多,详情可见: 干货:FMCW雷达系统信号处理建模与仿真(含MATLAB代码)
步骤1:雷达参数设置
设置雷达系统的基本参数。
#Radar parameters setting maxR = 200 #Maximum range rangeRes = 1 #Range resolution maxV = 70 #Maximum speed fc = 77e9 #Carrier frequency c = 3e8 #Speed of light r0 = 100 #Target distance v0 = 70 #Target speed B = c/ ( 2 * rangeRes) #Bandwidth Tchirp = 5.5 * 2 * maxR/ c #Chirp time endle_time = 6.3e-6 slope = B/ Tchirp #Chirp slope f_IFmax = ( slope* 2 * maxR) / c #Maximum IF frequency f_IF = ( slope* 2 * r0) / c #Current IF frequency Nd = 128 #Number of chirp Nr = 1024 #Numnber ADC sampling points vres = ( c/ fc) / ( 2 * Nd* ( Tchirp+ endle_time)) #Speed resolution Fs = Nr/ Tchirp #Sampling rate
步骤2:Tx 信号模型
假设Tx信号是频率随时间线性变化的余弦信号。
t = np. linspace( 0 , Nd* Tchirp, Nr* Nd) #Time of Tx and Rx angle_freq = fc* t+ ( slope* t* t) / 2 #Tx signal angle speed freq = fc + slope* t #Tx frequency Tx = np. cos( 2 * np. pi* angle_freq) #Waveform of Tx
步骤3:Rx 信号模型
Rx波形可以从Tx波形和延迟时间计算出来。
td = 2 * r0/ c freqRx = fc + slope* ( t) Rx = np. cos( 2 * np. pi* ( fc* ( t- td) + ( slope* ( t- td) * ( t- td)) / 2 ))
步骤4:中频信号模型
根据处理,假设中频信号可以用cos((2*pi*wt*t-2*pi*wr*t))表示。
IF_angle_freq = fc*t+(slope*t*t)/2 - ((fc*(t-td) + (slope*(t-td)*(t-td))/2)) freqIF = slope*td IFx = np.cos(-(2*np.pi*(fc*(t-td) + (slope*(t-td)*(t-td))/2))+(2*np.pi*angle_freq))
步骤5:中频信号的FFT
在这一步中,我们通过中频信号的 FFT 计算中频信号的频率。
IF_angle_freq = fc*t+(slope*t*t)/2 - ((fc*(t-td) + (slope*(t-td)*(t-td))/2)) freqIF = slope*td IFx = np.cos(-(2*np.pi*(fc*(t-td) + (slope*(t-td)*(t-td))/2))+(2*np.pi*angle_freq))
步骤6:随时间变化的频谱图
在这一步中,将计算随时间变化的频谱图。
我们可以看到,单帧周期内由于目标位移引起的IF信号频率变化在频谱图中很难区分,因此我们需要通过相位变化 来检测微小的位移和速度。
完整的python源代码如下:
import numpy as npimport matplotlib. pyplot as pltfrom numpy import fftfrom mpl_toolkits. mplot3d import Axes3D#Radar parameters setting maxR = 200 rangeRes = 1 maxV = 70 fc = 77e9 c = 3e8 r0 = 100 v0 = 70 B = c/ ( 2 * rangeRes) Tchirp = 5.5 * 2 * maxR/ c endle_time = 6.3e-6 slope = B/ Tchirp f_IFmax = ( slope* 2 * maxR) / c f_IF = ( slope* 2 * r0) / c Nd = 128 Nr = 1024 vres = ( c/ fc) / ( 2 * Nd* ( Tchirp+ endle_time)) Fs = Nr/ Tchirp #Tx = np.zeros(1,len(t)) #Rx = np.zeros(1,len(t)) #Mix = np.zeros(1,len(t)) #Tx波函数参数 t = np. linspace( 0 , Nd* Tchirp, Nr* Nd) #发射信号和接收信号的采样时间 angle_freq = fc* t+ ( slope* t* t) / 2 #角频率 freq = fc + slope* t #频率
Tx = np. cos( 2 * np. pi* angle_freq) #发射波形函数
plt. subplot( 4 , 2 , 1 ) plt. plot( t[ 0 : 1024 ], Tx[ 0 : 1024 ]) plt. xlabel( 'Time' ) plt. ylabel( 'Amplitude' ) plt. title( 'Tx Signal' ) plt. subplot( 4 , 2 , 3 ) plt. plot( t[ 0 : 1024 ], freq[ 0 : 1024 ]) plt. xlabel( 'Time' ) plt. ylabel( 'Frequency' ) plt. title( 'Tx F-T' ) r0 = r0+ v0* t#Rx波函数参数 td = 2 * r0/ c tx = t freqRx = fc + slope* ( t) Rx = np. cos( 2 * np. pi* ( fc* ( t- td) + ( slope* ( t- td) * ( t- td)) / 2 )) #接受波形函数 plt. subplot( 4 , 2 , 2 ) plt. plot( t[ 0 : 1024 ], Rx[ 0 : 1024 ]) plt. xlabel( 'Time' ) plt. ylabel( 'Amplitude' )
plt. title( 'Rx Signal' )
plt. subplot( 4 , 2 , 3 ) plt. plot( t[ 0 : 1024 ] + td[ 0 : 1024 ], freqRx[ 0 : 1024 ]) plt. xlabel( 'Time' ) plt. ylabel( 'Frequency' ) plt. title( 'Chirp F-T' ) #IF信号函数参数 IF_angle_freq = fc* t+ ( slope* t* t) / 2 - (( fc* ( t- td) + ( slope* ( t- td) * ( t- td)) / 2 )) freqIF = slope* td
IFx = np. cos( - ( 2 * np. pi* ( fc* ( t- td) + ( slope* ( t- td) * ( t- td)) / 2 )) + ( 2 * np. pi* angle_freq))
plt. subplot( 4 , 2 , 4 ) plt. plot( t[ 0 : 1024 ], IFx[ 0 : 1024 ]) plt. xlabel( 'Time' ) plt. ylabel( 'Amplitude' ) plt. title( 'IFx Signal' ) #Range FFT doppler = 10 * np. log10( np. abs( np. fft. fft( IFx[ 0 : 1024 ]))) frequency = np. fft. fftfreq( 1024 , 1 / Fs)
range = frequency* c/ ( 2 * slope)
plt. subplot( 4 , 2 , 5 ) plt. plot( range[ 0 : 512 ], doppler[ 0 : 512 ]) plt. xlabel( 'Frequency->Distance' ) plt. ylabel( 'Amplitude' ) plt. title( 'IF Signal FFT' ) #2D plot plt. subplot( 4 , 2 , 6 ) plt. specgram( IFx, 1024 , Fs) plt. xlabel( 'Time' ) plt. ylabel( 'Frequency' ) plt. title( 'Spectogram' ) plt. tight_layout( pad= 3 , w_pad= 0.05 , h_pad= 0.05 ) plt. show()
运行后全部的结果如下:
二、速度检测
(一)速度 检测原理
微小范围的移动很难通过距离频率关系来检测,如下图所示,在帧期间 频谱中没有发现明显的偏移。此外,如果有多个距离相同的目标,我们无法通过距离频率关系来区分它们,因为它们在频谱中具有相同的中频频率。
但是,我们可以通过测量IF信号的相位变化 来检测这些微运目标,并区分不同的目标,通过相位变化估计速度的基本思想如下:
(二)速度 检测Python仿真
一维速度估计:
步骤1:速维度数据提取
每个啁啾提取一个采样点,对于具有 128 个啁啾的帧,将有 128 个点的列表。
chirpamp = [] chirpnum = 1 while ( chirpnum<= Nd): strat = ( chirpnum-1 ) * 1024 end = chirpnum* 1024 chirpamp. append( IFx[( chirpnum-1 ) * 1024 ]) chirpnum = chirpnum + 1
步骤2:相位差和速度的速度维度 FFT
doppler = 10 * np. log10( np. abs( np. fft. fft( chirpamp))) FFTfrequency = np. fft. fftfreq( Nd, 1 / Fs) velocity = 5 * np. arange( 0 , Nd) / 3
2D FFT 和速度-距离关系
Z_fft2 = abs( np. fft. fft2( mat2D)) Data_fft2 = Z_fft2[ 0 : 64 , 0 : 512 ]
本节完整代码如下,使用时将下面的代码续接在距离检测仿真代码之后,即可运行:
#Range Spectogram plt. subplot( 4 , 2 , 6 ) plt. specgram( IFx, 1024 , Fs) plt. xlabel( 'Time' ) plt. ylabel( 'Frequency' ) plt. title( 'Range-Frequency Spectogram' ) plt. show() #Speed Calculate #速度维数据提取 chirpamp = [] chirpnum = 1 while ( chirpnum<= Nd): strat = ( chirpnum-1 ) * 1024 end = chirpnum* 1024 chirpamp. append( IFx[( chirpnum-1 ) * 1024 ]) chirpnum = chirpnum + 1 #速度维做FFT得到相位差 doppler = 10 * np. log10( np. abs( np. fft. fft( chirpamp))) FFTfrequency = np. fft. fftfreq( Nd, 1 / Fs) velocity = 5 * np. arange( 0 , Nd) / 3 #plt.subplot(4,2,7) plt. plot( velocity[ 0 : int( Nd/ 2 )], doppler[ 0 : int( Nd/ 2 )]) plt. xlabel( 'Velocity' ) plt. ylabel( 'Amplitude' ) plt. title( 'IF Velocity FFT' ) plt. show() #2D plot mat2D= np. zeros(( Nd, Nr)) i = 0 while ( i< Nd): mat2D[ i, :] = IFx[ i* 1024 :( i+ 1 ) * 1024 ] i = i + 1 #plt.matshow(mat2D) #plt.title('Original data') #图形绘制,需要修改一下才好看,这里就留个大家自行修改了。 Z_fft2 = abs( np. fft. fft2( mat2D)) Data_fft2 = Z_fft2[ 0 : 64 , 0 : 512 ] #plt.subplot(4,2,8) plt. imshow( Data_fft2) plt. xlabel( "Range" ) plt. ylabel( "Velocity" ) plt. title( 'Velocity-Range 2D FFT' ) plt. tight_layout( pad= 3 , w_pad= 0.05 , h_pad= 0.05 ) plt. show()
三、学习扩展
上述只是一个简单的示例程序,读者可以参考调皮哥之前分享的Matlab代码自行增加,例如静态杂波滤除、CFAR检测、DOA估计,以及其他的各种雷达信号处理算法仿真 等,主动权完全在大家的手中,请按照自己的想法去创造吧。
学习雷达是一个理论结合实践的过程,尤其要重视实践的过程,在实践中的每一个问题及其解决方案,都是十分宝贵的学习经验。不论是做研究还是找工作,都要重视学习知识、提出问题、解决问题、复盘总结等能力。人生在世,学习时间尤其宝贵,望珍惜。
参考资料
【1】https://community./t5/Knowledge-Base-Articles/FMCW-radar-working-principle-simulation-based-on-python-Chapter-1-Distance/ta-p/366803
【2】https://community./t5/Knowledge-Base-Articles/FMCW-radar-working-principle-simulation-based-on-python-Chapter-2-Velocity/ta-p/367214