极简 FMCW 毫米波雷达 Matlab 仿真
文章目录
-
引言
- FMCW 雷达基本原理及其在距离测量中的应用
- 基于 MATLAB 的距离测量仿真研究
-
- 定义雷达相关参数
- 生成发射与接收波形
- 接收信号的处理与分析——用于距离测量
-
FMCW 雷达基本原理的具体阐述及其在速度测量中的应用
-
基于 MATLAB 平台的数值模拟研究用于速度测量
-
FMCW 雷达工作原理的具体说明以及其在目标识别过程中的应用
-
基于 MATLAB 平台的数值模拟研究用于目标识别过程
引言
本文的目的在于通过信号视角构建一个简单的FMCW毫米波雷达模型,并以此为基础深入理解其工作机制及其基本理论。在学习过程中,我们不仅会系统地了解毫米波雷达的工作流程和工作原理,在这过程中还特别注重结合MATLAB代码逐步进行仿真实验来加深对相关数字信号处理技术的理解。
代码参考链接:该源码实现了基于雷达信号处理的智能目标识别算法(具体描述)
FMCW 雷达基本原理——如何测距
TI 的这篇文献阐述得非常出色,并非易读之作
一个电磁波发送出去后与外界物体发生碰撞并反射回来,在反射回来的波与发送出去的波之间必定存在时间差这一因素是我们测定距离的关键所在。这种特性使得FMCW(Frequency-Modulated Continuous-Wave, 频率调制连续波)雷达能够有效捕捉信号并进行距离测量。该雷达系统采用持续变化的正弦波形作为载波信号,在接收端通过分析信号频率的变化来实现精确的距离测定。

采用频率学视角分析这个波形时,则可以看出其呈现出随时间线性增加的趋势。具体而言,在时域中观察该信号会发现其呈现出随时间线性增加的趋势;数学上可表示为f(t)=f_0+\Delta f\cdot t(其中f_0代表初始时刻的频率值;\Delta f表示单位时间内频率的变化量)。基于上述方程可绘制出该信号的时间域特性曲线如图所示

接收到来的信号其与发送信号之间存在时间延迟如图所示此时观察到在同一时间点两者的频率偏差一致这表明在接收阶段我们需要通过某种方式精确获取这一频率偏差从而确定两者之间的距离为了确定两者之间的距离已知这一频偏值和图像中的斜率变化趋势则可推导出τ值电磁波在其介质中的传播速度通常接近光速c=299792458 m/s因此距离由上述计算可得

当前的核心问题是确定频率范围的具体界限。通常情况下,在车载毫米波雷达中使用的频段主要集中在24 GHz和77 GHz这两个范围内。这一现象主要由频谱资源受限、测量精度要求以及传感器物理尺寸等因素共同导致。那么如果将起始频率定在77 GHz,则截止频率应该设定在何处?两者之间的跨度即决定了毫米波雷达的工作带宽。
在图中所呈现的纵坐标范围对应的就是雷达系统中的带宽指标;这一数值直接反映了雷达的距离分辨率。然而,在使用 chirp 信号时需要注意的是,在这里我们实际上是在讨论三个关键参数:带宽、周期和斜率中的任意两个参数被确定时,则整个波形就被唯一地确定下来了。
我们先来看雷达的最大作用距离:
R_{max}≤\frac{cT_{chirp}}{2}
在理论上最大的作用距离仅仅是在最理想条件下的一种假设,在信号数学意义下的一种决定式,在这种情况下真实的最大作用距离则需从功率的角度进行评估。对于该式的理解也较为简便,在图中蓝点持续向右移动直至发送端与接收端的信号分别处于完全不重叠的时间段。
下面来探讨雷达的距离分辨率问题,在面对多体发射波时会呈现特定特征具体表现为图中的现象我们可以想象一下若两物体之间的距离非常短暂其对应的频谱成分也会极为接近这可能导致在频域中难以区分它们

研究表明,在对回波信号进行长时间观测的情况下,在信号处理后可以获得更好的频率分辨效果。通常情况下,在长度为 T 的时间段内进行观测所形成的观测窗口能够分辨出相隔至少 \frac{1}{T} Hz 的不同频率成分。

MATLAB仿真——测距
定义雷达参数
定义基本的雷达参数,包括:
- 光传播速度值为 c = 3\times 10^8 \, m/s
- 最大测距范围为 200 米(该参数将影响扫频周期 Tchirp 的设置)
- 目标运动速率为 -20 米每秒
- 监测的目标最大距离为 110 米
- 测距精度为 1 米(该参数由观测窗口 T 决定,影响的是测量带宽)
%% Radar Specifications
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Frequency of operation = 77GHz
% Max Range = 200m
% Range Resolution = 1 m
% Max Velocity = 100 m/s
%%%%%%%%%%%%%%%%%%%%%%%%%%%
c = 3e8;
range = 110;
vel = -20;
max_range = 200;
range_res = 1;
max_vel = 100;
代码解读
下面定义单周期chirp波形的基本参数:
- 通过计算得到了FMCW波形的带宽B
- 扫频时间
- 斜率
这三个关键参数(准确地说是其中任意两个)共同决定了连续调频波的波形;chirp信号所构成的结果由其三角波组成。
%% FMCW Waveform Generation
% *%TODO* :
%Design the FMCW waveform by giving the specs of each of its parameters.
% Calculate the Bandwidth (B), Chirp Time (Tchirp) and Slope (slope) of the FMCW
% chirp using the requirements above.
B = c / (2*range_res);
Tchirp = 5.5 * 2 * (max_range/c) ;
slope = B/Tchirp;
代码解读
下面定义chirp序列的一些参数:
- 工作频率:77 GHz,并非独立存在的单一信号特征
- Nd 是描述该序列中采样点数量的关键参数
- Nr 是一个用于描述每个周期内采样点数量的关键参数
%Operating carrier frequency of Radar
fc= 77e9; %carrier freq
%The number of chirps in one sequence. Its ideal to have 2^ value for the ease of running the FFT
%for Doppler Estimation.
Nd=128; % #of doppler cells OR #of sent periods % number of chirps
%The number of samples on each chirp.
Nr=2^15; %for length of time OR # of range cells
代码解读
下面定义了后续所需要的一些向量空间,包括:
- 时间轴从零开始至chirp完整序列的时间段内包含 Nr×Nd 个数据点
- 接收端(Rx)、发送端(Tx)以及混合信号(Mix)将基于该时间段内的采样点生成向量
- rt代表任一时刻的发射距离其值由起始位置坐标运动速度矢量及当前时间共同确定
- td代表信号传播过程中的时延等于两倍该距离值除以光速常数
% Timestamp for running the displacement scenario for every sample on each
% chirp
t=linspace(0,Nd*Tchirp,Nr*Nd); %total time for samples
%Creating the vectors for Tx, Rx and Mix based on the total samples input.
Tx=zeros(1,length(t)); %transmitted signal
Rx=zeros(1,length(t)); %received signal
Mix = zeros(1,length(t)); %beat signal
%Similar vectors for range_covered and time delay.
r_t=zeros(1,length(t));
td=zeros(1,length(t));
代码解读
生成发射及接收波形
现在可以生成chrip波形了:
- 发射信号:cos(2π(f_c⋅t(i)+slope⋅t(i)^2/2))
- 接收信号对应于发送信号的相移:cos(2π(f_c⋅(t(i)−t_d(i))+slope⋅(t(i)−t_d(i))^2/2))
%% Signal generation and Moving Target simulation
% Running the radar scenario over the time.
for i=1:length(t)
% *%TODO*
%For each time stamp update the Range of the Target for constant velocity.
r_t(i) = range + (vel*t(i));
td(i) = (2 * r_t(i)) / c;
% *%TODO* :
%For each time sample we need update the transmitted and
%received signal.
Tx(i) = cos(2*pi*(fc*t(i) + (slope*t(i)^2)/2 ) );
Rx(i) = cos(2*pi*(fc*(t(i) -td(i)) + (slope * (t(i)-td(i))^2)/2 ) );
% *%TODO* :
%Now by mixing the Transmit and Receive generate the beat signal
%This is done by element wise matrix multiplication of Transmit and
%Receiver Signal
Mix(i) = Tx(i) .* Rx(i);
end
代码解读
绘制信号:
- 在时域难以准确区分77 GHz和77.15 GHz这两个频率点的情况下,我们采用 chirp 信号并对其计算 FFT 结果来进行频谱分析。
- 通过Matlab的 FFT 函数可以得到一个复数数组,在此基础上我们可以通过采样率推导出频率域函数的横坐标值;接着通过对 FFT 结果取模运算来获得纵坐标的幅度信息。
- 通过下图我们可以清晰地观察到 Tx 在频谱上的具体分布情况。
% 绘制一个chrip的Tx信号的频率域结果
signal_fft = fft(Tx, Nr);
N = length(signal_fft);
Fs=Nr/Tchirp;
f = (0:N-1)*(Fs/N);
plot(f(1:N/2), abs(signal_fft(1:N/2)));
title('Single-Sided Amplitude Spectrum');
xlabel('Frequency (Hz)');
ylabel('|FFT|');
% 绘制混频后的信号的第一个脉冲
plot(t(1:1*Nr), Mix(1:1*Nr));
title('Beat Signal');
xlabel('Time');
ylabel('Amplitude');
代码解读

接收信号的处理——测距
为了处理接收到并经过混频处理的信号数据,我们采用了快速傅里叶变换(FFT)算法。为了计算基波频率作为基准,在此基础上进一步分析其频率特性以便确定目标物体的基本参数值。随后利用该频率差异计算出目标物体与传感器之间的距离,在编码过程中生成频谱分析图形,并将横轴刻度转换为对应的实际距离数值。测试结果表明所获得的距离测量值与理论预期高度一致
%% RANGE MEASUREMENT
% *%TODO* :
%reshape the vector into Nr*Nd array. Nr and Nd here would also define the size of
%Range and Doppler FFT respectively.
Mix = reshape(Mix, [Nr, Nd]);
MixT = Mix';
dim = 2;
% fft运算并输出频谱图,这里只打印4行
signal_fft = fft(MixT, Nr, dim);
P2 = abs(signal_fft/Nr);
P1 = P2(:,1:Nr/2+1);
P1(:,2:end-1) = 2*P1(:,2:end-1);
% figure;
% for i=1:4
% subplot(4,1,i)
% plot(0:(Fs/Nr):(Fs/2-Fs/Nr),P1(i,1:Nr/2))
% title("Row " + num2str(i) + " in the Frequency Domain")
% end
% 计算距离并直接体现在横坐标上,这里只打印4行
rowRange = (0:(Fs/Nr):(Fs/2-Fs/Nr))*c/slope/2;
figure;
for i=1:4
subplot(4,1,i)
plot(rowRange,P1(i,1:Nr/2))
xlim([0,200]);
xlabel('Range [m]');
title("Row " + num2str(i) + " Range")
end
代码解读

FMCW 雷达基本原理——如何测速
从上文可以看出,在不同时间点上由于时间间隔较短输出峰值位置并未发生变化但未能展示出此时所对应的相位角我们正是通过观察各相位差来进行测速工作这里我们采用了2D FFT算法来进行速度计算这一技术在视频链接中也有很好的应用实例2D FFT本质上是对一组信号从不同角度进行分析

MATLAB仿真——测速
为了实现对 2D FFT 的处理过程,我们需要将我们的混频后数据通过 reshape 技术重组为由多个时段性 chirp 信号构成的数据集。这种处理方法使得我们可以从横向和纵向两个维度执行 FFT 分析。随后这段代码执行了一系列的空间域到频率域的变换,并最终生成了一个三维空间中的二维傅里叶变换图像
%% RANGE DOPPLER RESPONSE
% The 2D FFT implementation is already provided here. This will run a 2DFFT
% on the mixed signal (beat signal) output and generate a range doppler
% map.You will implement CFAR on the generated RDM
% Range Doppler Map Generation.
% The output of the 2D FFT is an image that has reponse in the range and
% doppler FFT bins. So, it is important to convert the axis from bin sizes
% to range and doppler based on their Max values.
Mix=reshape(Mix,[Nr,Nd]);
% 2D FFT using the FFT size for both dimensions.
signal_fft2 = fft2(Mix,Nr,Nd);
% Taking just one side of signal from Range dimension.
signal_fft2 = signal_fft2(1:Nr/2,1:Nd);
signal_fft2 = fftshift (signal_fft2);
RDM = abs(signal_fft2);
RDM = 10*log10(RDM) ; % 转换为分贝单位
%use the surf function to plot the output of 2DFFT and to show axis in both
%dimensions
doppler_axis = linspace(-100,100,Nd);
range_axis = linspace(-200,200,Nr/2)*((Nr/2)/400);
figure,surf(doppler_axis,range_axis,RDM,'EdgeColor', 'none');
title('Amplitude and Range From FFT2');
xlabel('Speed');
ylabel('Range');
zlabel('Amplitude');
代码解读

FMCW 雷达基本原理——雷达目标检测
刚获取了2D FFT结果,并未完成目标检测任务。在判定过程中可能出现两种类型的误报:一种是在无目标的情况下误判为有目标(虚警),另一种是在有目标的情况下误判为无目标(漏报)。而该系统的目标检测方法基于阈值设定——当雷达回波强度超过设定阈值时,则认为实现了对物体的探测;反之则视为噪声干扰。

恒虚警率(CFAR)算法的基本要素包括以下几个关键部分:
参考窗口(Reference Window) :CFAR算法依赖于一个用于估计背景噪声或杂波统计特性的参考窗口。该窗口通常选择位于无目标存在的区域。
测试单元(Cell Under Test, CUT) 定义为该区域用于检测目标的存在与否。采用CFAR算法时,系统会通过比较该区域的响应与基于参考窗口计算出的噪声水平来判断是否存在目标。
噪声估计:在给定的参考窗口中进行。算法将通过计算手段来评估噪声水平。具体而言,这些方法通常包括计算平均值,中位数以及采用其他统计指标以达到降噪效果
阈值计算:基于噪声估计的结果,CFAR算法将计算出相应的阈值。当测试单元的响应高于该阈值时,则可能导致目标被检测出来。
阈值偏移(Threshold Offset):为满足信噪比和检测概率需求,在特定系统性能要求下调整阈值。
判定和识别:通过将测试单元的响应与预设的阈值进行对比分析。当测得的响应数值超过设定阈值时,表明系统可能成功检测到了目标;反之,则判断为环境干扰或杂波影响。
保护区域(Guard Cells):可能在测试单元周围设置保护区域以避免与参考窗口或相邻单元产生干扰。
工作区(Training Window) :这部分用于估计噪声的基准窗口通常位于与测试单元隔绝的位置。
边界处理:当处理位于矩阵边界的测试单元时,通常需要采取特殊措施。由于这些区域通常缺乏足够的参考数据窗口。
CFAR算法的输出结果可以表现为二值图像或矩阵的形式,用于标识目标是否存在.其中1代表目标被检测到的情况,0则表示未检测到目标.
算法类型 :种类繁多的去噪声自适应滤波器(CFAR)算法包括细胞平均型CFAR(CA-CFAR)、最大值维持型CFAR(MCFAR)以及排序统计型CFAR(OS-CFAR)等多种类型。每一种算法都有独特的噪声估计方式和相应的阈值计算方法。
MATLAB仿真——雷达目标检测
将这段代码复制粘贴到这里。其流程极为相似于CFAR的基本要素,请GPT协助阅读一下:
- 初始化参数: n_train_cells 和 n_train_bands 确定了用于噪声估计的训练单元在距离和多普勒维度上的数量。n_guard_cells 和 n_guard_bands 确定了测试单元(CUT)周围的保护单元数量,以避免边缘效应。offset 是加在噪声估计上的一个偏移量,用于调整最终的检测阈值。noise_level 是一个向量,用于存储每次迭代中训练单元的噪声水平。
- 归一化RDM: RDM 被归一化,可能是为了在后续处理中避免数值过大或过小。
- 滑动窗口: 双重 for 循环在RDM上滑动CUT,同时在边缘留出训练和保护单元的余量。
- 噪声估计: 内层双重 for 循环遍历训练单元,如果单元不在CUT的保护区域内,则累加其噪声水平(从分贝转换为线性单位)。
- 计算阈值: 计算所有训练单元的平均噪声水平,然后转换回分贝单位,并加上偏移量以确定阈值。
- CUT的检测: 对于每个CUT,将其信号水平与阈值进行比较。如果CUT的信号水平大于阈值,则标记为1(检测到目标),否则标记为0(未检测到目标)。
- 处理边缘情况: 由于CUT不能位于矩阵边缘,因此处理后的RDM会比原始的RDM小。将未被阈值化处理的单元格设置为0。
- 显示CFAR输出: 使用 surf 函数显示经过CA-CFAR滤波后的RDM,并添加了图形的标题、轴标签和视角设置。
%% CFAR implementation
%Slide Window through the complete Range Doppler Map
% *%TODO* :
%Select the number of Training Cells in both the dimensions.
n_train_cells = 10;
n_train_bands = 8;
% *%TODO* :
%Select the number of Guard Cells in both dimensions around the Cell under
%test (CUT) for accurate estimation
n_guard_cells = 4;
n_guard_bands = 4;
% *%TODO* :
% offset the threshold by SNR value in dB
offset = 1.4;
% *%TODO* :
%Create a vector to store noise_level for each iteration on training cells
noise_level = zeros(1,1);
% *%TODO* :
%design a loop such that it slides the CUT across range doppler map by
%giving margins at the edges for Training and Guard Cells.
%For every iteration sum the signal level within all the training
%cells. To sum convert the value from logarithmic to linear using db2pow
%function. Average the summed values for all of the training%cells used. After averaging convert it back to logarithimic using pow2db.
%Further add the offset to it to determine the threshold. Next, compare the
%signal under CUT with this threshold. If the CUT level > threshold assign
%it a value of 1, else equate it to 0.
% Use RDM[x,y] as the matrix from the output of 2D FFT for implementing
% CFAR
RDM = RDM / max(RDM(:));
for row0 = n_train_cells + n_guard_cells + 1 : (Nr/2) - (n_train_cells + n_guard_cells)
for col0 = n_train_bands + n_guard_bands + 1 : (Nd) - (n_train_bands + n_guard_bands)
%Create a vector to store noise_level for each iteration on training cells
noise_level = zeros(1, 1);
for row1 = row0 - (n_train_cells + n_guard_cells) : row0 + (n_train_cells + n_guard_cells)
for col1 = col0 - (n_train_bands + n_guard_bands) : col0 + (n_train_bands + n_guard_bands)
if (abs(row0 - row1) > n_guard_cells || abs(col0 - col1) > n_guard_bands)
noise_level = noise_level + db2pow(RDM(row1, col1));
end
end
end
% Calculate threshold from noise average then add the offset
thresh = pow2db(noise_level / (2 * (n_train_bands + n_guard_bands + 1) * 2 * (n_train_cells + n_guard_cells + 1) - (n_guard_cells * n_guard_bands) - 1));
thresh = thresh + offset;
CUT = RDM(row1,col1);
if (CUT < thresh)
RDM(row0, col0) = 0;
else
RDM(row0, col0) = 1;
end
end
end
% *%TODO* :
% The process above will generate a thresholded block, which is smaller
%than the Range Doppler Map as the CUT cannot be located at the edges of
%matrix. Hence,few cells will not be thresholded. To keep the map size same
% set those values to 0.
RDM(RDM~=0 & RDM~=1) = 0;
% *%TODO* :
%display the CFAR output using the Surf function like we did for Range
%Doppler Response output.
figure('Name', 'CA-CFAR Filtered RDM')
surf(doppler_axis, range_axis, RDM);
%colorbar;
title( 'CA-CFAR Filtered RDM surface plot');
xlabel('Speed');
ylabel('Range');
zlabel('Normalized Amplitude');
view(315, 45);
代码解读
