基于FMCW雷达的测距、测速与测角原理与实现
基于FMCW雷达的测距、测速与测角原理与实现
摘要
线性调频连续波(FMCW)雷达通过发射线性扫频的上斜(或上/下交替)chirp,并对回波与本振信号拍频解调,得到与目标距离和速度相关的拍频与慢时间多普勒信息;配合多天线阵列的空间处理,实现距离–速度–角度联合估计。本文给出从波形到处理链的关键方程、分辨率与无模糊条件、以及工程设计要点。
1. 波形与回波模型
1.1 线性调频上斜 chirp
stx(t)=exp { j 2π(fc t+12S t2)},0≤t<Tc s_{\mathrm{tx}}(t)=\exp\!\Big\{\,j\,2\pi\big(f_c\,t+\tfrac{1}{2}S\,t^{2}\big)\Big\},\qquad 0\le t<T_c stx(t)=exp{j2π(fct+21St2)},0≤t<Tc
-
stx(t)s_\mathrm{tx}(t)stx(t):发射信号;
-
fcf_cfc:载频HzHzHz;
-
S=BTcS=\tfrac{B}{T_c}S=TcB:调频斜率(Hz/s),BBB 为扫频带宽HzHzHz,TcT_cTc 为单个 chirp 时长sss;
-
ttt:快时间sss;
-
j=−1j=\sqrt{-1}j=−1。
1.2 解调(拍频)信号
距离为 RRR、径向速度为 vvv 的点目标,其回波延迟 τ=2R/c\tau=2R/cτ=2R/c,多普勒 fD=2v/λf_D=2v/\lambdafD=2v/λ。与本振拍频后近似得到
x(t)≈A exp { j 2π(Sτ⏟fb t+fD t+ϕ0)}
x(t)\approx A\,\exp\!\Big\{\,j\,2\pi\big(\underbrace{S\tau}_{f_b}\,t+f_D\,t+\phi_0\big)\Big\}
x(t)≈Aexp{j2π(fbSτt+fDt+ϕ0)}
-
x(t)x(t)x(t):解调(拍频)信号;
-
AAA:复幅度(含路径损耗与RCS);
-
τ=2R/c\tau=2R/cτ=2R/c:往返时延sss,ccc 为光速m/sm/sm/s;
-
fb=Sτf_b=S\taufb=Sτ:拍频HzHzHz,与距离成正比;
-
fD=2v/λf_D=2v/\lambdafD=2v/λ:多普勒频移HzHzHz,λ=c/fc\lambda=c/f_cλ=c/fc为波长mmm;
-
ϕ0\phi_0ϕ0:常数相位;
-
近似假设:单个 chirp 内 RRR 变化很小(小速度、小加速度)。
2. 测距(Range)
2.1 距离–拍频映射
R=cfb2S. R=\frac{cf_b}{2S}. R=2Scfb.
-
RRR:目标距离mmm;
-
fbf_bfb:拍频HzHzHz;
-
SSS:斜率Hz/sHz/sHz/s;
-
ccc:光速m/sm/sm/s。
2.2 距离分辨率
ΔR=c2B. \Delta R=\frac{c}{2B}. ΔR=2Bc.
-
ΔR\Delta RΔR:距离分辨率mmm;
-
BBB:单个 chirp 的扫频带宽HzHzHz;
-
ccc:光速m/sm/sm/s。
2.3 最大无模糊距离(采样导致的)
拍频需小于 Nyquist:fb<fs/2f_b<f_s/2fb<fs/2,得
Rmax=cfs4S.
R_\text{max}=\frac{cf_s}{4S}.
Rmax=4Scfs.
-
RmaxR_\text{max}Rmax:最大无模糊距离mmm;
-
fsf_sfs:ADC 采样率HzHzHz;
-
其他符号同前。
注:实际还受 IF 带宽、前端抗混叠滤波器、模拟中频范围等限制。
3. 测速(Velocity)
采用 N 个 chirp 的慢时间序列,对同一距离 bin 沿 chirp 维做 DFT,得到慢时间多普勒谱。
3.1 多普勒–速度映射
v=λ2fD. v=\frac{\lambda}{2}f_D. v=2λfD.
-
vvv:径向速度m/sm/sm/s;
-
fDf_DfD:慢时间估计出的多普勒频率HzHzHz;
-
λ=c/fc\lambda=c/f_cλ=c/fc:波长mmm。
3.2 速度分辨率
慢时间 PRF 为 fr=1/Trf_\text{r}=1/T_rfr=1/Tr(相邻 chirp 起始间隔 TrT_rTr,通常 Tr≈Tc)T_r\approx T_c)Tr≈Tc),N 点 DFT:
Δv=λ2⋅frN.(7)
\Delta v=\frac{\lambda}{2}\cdot\frac{f_\text{r}}{N}.
\tag{7}
Δv=2λ⋅Nfr.(7)
-
Δv\Delta vΔv:速度分辨率(m/s);
-
λ\lambdaλ:波长(m);
-
frf_\text{r}fr:慢时间采样率(PRF,Hz);
-
NNN:用于多普勒 FFT 的 chirp 数。
3.3 最大无模糊速度
多普勒落在 (−fr2,fr2)(-\tfrac{f_\text{r}}{2},\tfrac{f_\text{r}}{2})(−2fr,2fr)内,得
∣v∣<λ4fr.
|v|<\frac{\lambda}{4}f_\text{r}.
∣v∣<4λfr.
-
∣v∣|v|∣v∣:速度绝对值(m/s);
-
λ\lambdaλ:波长(m);
-
frf_\text{r}fr:PRF(Hz)。
交替上/下扫(triangular FMCW)可分离距离拍频与多普勒,提高抗耦合能力与无模糊范围。
4. 测角(Angle)
采用 M 元均匀线阵(ULA),阵元间距 d≈λ/2d\approx \lambda/2d≈λ/2。到达角 θ\thetaθ 的阵列流形为
a(θ)=[1, ej2πdλsinθ, …, ej2π(M−1)dλsinθ]T.
\mathbf{a}(\theta)=
\begin{bmatrix}
1,~e^{j2\pi\frac{d}{\lambda}\sin\theta},~\ldots,~e^{j2\pi\frac{(M-1)d}{\lambda}\sin\theta}
\end{bmatrix}^{T}.
a(θ)=[1, ej2πλdsinθ, …, ej2πλ(M−1)dsinθ]T.
-
a(θ)\mathbf{a}(\theta)a(θ):阵列导向向量(M×1)(M\times 1)(M×1);
-
θ\thetaθ:方位角(deg 或 rad);
-
ddd:阵元间距(m);
-
MMM:阵元数;
-
λ\lambdaλ:波长(m)。
4.1 FFT 波束形成角度谱
对同一 (range,doppler)(\text{range},\text{doppler})(range,doppler) 单元的阵列快照 x∈CM×1\mathbf{x}\in\mathbb{C}^{M\times 1}x∈CM×1,
PFFT(θ)=∣w(θ)Hx∣2,w(θ)=a(θ)∣a(θ)∣.
P_\text{FFT}(\theta)=\big|\mathbf{w}(\theta)^{H}\mathbf{x}\big|^2,\quad
\mathbf{w}(\theta)=\frac{\mathbf{a}(\theta)}{|\mathbf{a}(\theta)|}.
PFFT(θ)=w(θ)Hx2,w(θ)=∣a(θ)∣a(θ).
-
PFFT(θ)P_\text{FFT}(\theta)PFFT(θ):FFT/波束形成角度谱;
-
w(θ)\mathbf{w}(\theta)w(θ):方向 θ\thetaθ 的波束权;
-
x\mathbf{x}x:阵列观测向量;
-
(⋅)H(\cdot)^H(⋅)H:共轭转置;
-
∣⋅∣|\cdot|∣⋅∣:欧氏范数。
4.2 MUSIC 超分辨角度谱(可选)
估计协方差 Rxx\mathbf{R}_{xx}Rxx,分解得到噪声子空间 En\mathbf{E}_nEn 后
PMUSIC(θ)=1a(θ)HEnEnHa(θ).(11)
P_\text{MUSIC}(\theta)=\frac{1}{\mathbf{a}(\theta)^{H}\mathbf{E}_n\mathbf{E}_n^{H}\mathbf{a}(\theta)}.
\tag{11}
PMUSIC(θ)=a(θ)HEnEnHa(θ)1.(11)
-
PMUSIC(θ)P_\text{MUSIC}(\theta)PMUSIC(θ):MUSIC 伪谱;
-
a(θ)\mathbf{a}(\theta)a(θ):阵列导向向量;
-
En\mathbf{E}_nEn:噪声子空间基向量矩阵;
-
(⋅)H(\cdot)^H(⋅)H:共轭转置。
4.3 角度分辨率(波束主瓣近似)
Δθ≈0.886λMd,(rad)或Δθ≈50.8∘λMd. \Delta\theta \approx \frac{0.886\lambda}{Md},(\text{rad})\quad\text{或}\quad \Delta\theta \approx \frac{50.8^\circ\lambda}{Md}. Δθ≈Md0.886λ,(rad)或Δθ≈Md50.8∘λ.
-
Δθ\Delta\thetaΔθ:角度分辨率;
-
λ\lambdaλ:波长;
-
MMM:阵元数;
-
ddd:阵元间距;
-
系数 0.886 为均匀线阵近似主瓣宽度常用经验值。
5. 处理链(2D-FFT + CFAR + 角度谱)
5.1 二维 FFT(距离–多普勒)
对解调数据立方体 (Rx)×(chirp)×(sample)\text{(Rx)}\times\text{(chirp)}\times\text{(sample)}(Rx)×(chirp)×(sample),先沿快时间做 NrN_rNr 点 FFT、再沿慢时间做 NdN_dNd 点 FFT:
X[k,n]=Fslow Ffastx[m] ,k=0…Nd−1, n=0…Nr−1.
X[k,n]=\mathcal{F}_\text{slow}{\ \mathcal{F}_\text{fast}{x[m]}\ },\quad
k=0\ldots N_d-1,\ n=0\ldots N_r-1.
X[k,n]=Fslow Ffastx[m] ,k=0…Nd−1, n=0…Nr−1.
-
x[m]x[m]x[m]:第 m 个快时间采样(或向量);
-
nnn:距离 FFT bin 索引;
-
kkk:多普勒 FFT bin 索引;
-
Ffast,Fslow\mathcal{F}_\text{fast},\mathcal{F}_\text{slow}Ffast,Fslow:快/慢时间 FFT 运算;
-
Nr,NdN_r,N_dNr,Nd:距离/多普勒 FFT 大小。
5.2 无检测门限的能量图与非相干合成
多天线非相干融合用于检测(抑制相位不一致影响):
RD[k,n]=∑m=1M∣Xm[k,n]∣2.(14)
\mathrm{RD}[k,n]=\sum_{m=1}^{M}\big|X_m[k,n]\big|^2.
\tag{14}
RD[k,n]=m=1∑MXm[k,n]2.(14)
-
RD[k,n]\mathrm{RD}[k,n]RD[k,n]:距离–多普勒能量图;
-
Xm[k,n]X_m[k,n]Xm[k,n]:第 m 个接收通道在 (k,n)(k,n)(k,n) 处的复谱值;
-
MMM:接收通道数。
5.3 CA-CFAR 阈值(二维均值估计近似)
令参考单元数为 NrefN_\mathrm{ref}Nref、期望虚警率 PfaP_\mathrm{fa}Pfa,则放缩系数 α\alphaα 近似为
α=Nref(Pfa−1/Nref−1).(15)
\alpha = N_\mathrm{ref}\Big(P_\mathrm{fa}^{-1/N_\mathrm{ref}}-1\Big).
\tag{15}
α=Nref(Pfa−1/Nref−1).(15)
-
α\alphaα:CFAR 阈值放缩系数;
-
NrefN_\mathrm{ref}Nref:参考单元数(不含保护单元);
-
PfaP_\mathrm{fa}Pfa:目标虚警概率。
5.4 角度谱切片(RA 图)
对选定 (k,n)(k,n)(k,n) 处取阵列快照 xk,n\mathbf{x}_{k,n}xk,n,计算角度谱并在角度–距离平面显示:
RA(θ,n)=∣w(θ)Hxk∗(n), n∣2,k∗(n)=argmaxk RD[k,n]
\mathrm{RA}(\theta,n)=\big|\mathbf{w}(\theta)^{H}\mathbf{x}_{k^{*}(n),\,n}\big|^{2},\qquad
k^{*}(n)=\arg\max_{k}\,\mathrm{RD}[k,n]
RA(θ,n)=w(θ)Hxk∗(n),n2,k∗(n)=argkmaxRD[k,n]
-
RA(θ,n)\mathrm{RA}(\theta,n)RA(θ,n):角度–距离谱(每个距离选用能量最大的多普勒切片);
-
xk,n\mathbf{x}_{k,n}xk,n:在 (k,n)(k,n)(k,n) 处的阵列观测向量;
-
w(θ)\mathbf{w}(\theta)w(θ):波束形成权;
-
k∗(n)k^*(n)k∗(n):距离 bin (n) 上能量最大的多普勒 bin。
6. 关键约束、分辨率与耦合
6.1 距离–速度耦合(单上斜)
若只用上斜 chirp,拍频含有速度项,近似
fb≈Sτ+fD.(17)
f_b \approx S\tau + f_D.
\tag{17}
fb≈Sτ+fD.(17)
-
fbf_bfb:拍频;
-
SτS\tauSτ:与距离成正比项;
-
fDf_DfD:多普勒项。
采用 上/下扫配对或 多帧慢时间处理可减弱耦合:上/下扫的 fbf_bfb 对 fDf_DfD符号相反,可线性消去 fDf_DfD 得距离,再以慢时间多普勒求速度。
6.2 距离窗泄漏与定标
距离 FFT 前加窗(Hann/Hamming)降低旁瓣;定标需考虑 TX/RX 通道幅相一致性、IF 带宽与采样链路、ADC 时钟偏差 等。
7. 参数设计与工程指南
-
距离分辨率:由带宽决定,ΔR=c/(2B)\Delta R=c/(2B)ΔR=c/(2B)——若需 0.15 m 分辨率,带宽需 B≈1B\approx 1B≈1 GHz。
-
速度分辨率:增大 chirp 数 N 或 PRF 降低 Δv\Delta vΔv。
-
无模糊距离/速度:给出上限,工程上还要考虑 IF/模数链路实际范围。
-
测角性能:增大阵元数 MMM 或孔径 MdM_dMd 提升分辨率;阵元间距宜 ≤λ/2\le \lambda/2≤λ/2 防止栅瓣。
-
检测门限:根据场景回波统计与 PfaP_\mathrm{fa}Pfa 选择 Nref,αN_\mathrm{ref},\alphaNref,α,目标稀疏时可用 OS-CFAR。
-
稳健性:目标加速度导致慢时间相位弯曲,可用 Keystone 校正或更高阶模型;强杂波/多径下建议做 空时自适应 或 MIMO 多通道正交培训。
MATLAB代码
%% ============================================================% FMCW Radar: Range / Velocity / Angle All-in-One Demo% - Angle–Range uses per-range strongest Doppler slice% - Legends + Truth Annotations on RD, RA, 3D% Single-file, one-click runnable% Tested: R2020b+ (no special toolboxes required)% =============================================================clear; clc; close all;%% ----------------------- User Parameters -----------------------% Radar & waveformc = 3e8; % speed of lightfc = 77e9; % carrier frequency (Hz)lambda = c/fc;BW = 1e9; % sweep bandwidth (Hz)Tc = 40e-6; % chirp duration (s)S = BW/Tc; % chirp slope (Hz/s)fs = 20e6; % ADC sampling rate (Hz)Ns = round(fs*Tc); % samples per chirpNchirp = 128; % number of chirps (slow-time)Tx = 1; % 1-Tx (TDM off)Rx = 8; % number of Rx (ULA)d = lambda/2; % element spacing% Scene (multi-target): [R(m), v(m/s), azimuth(deg), RCS/amp]targets = [...40, -10, -10, 1.0; % T155, 8, 20, 0.8; % T285, 0, 5, 0.6 % T3];SNR_dB = 20; % SNR of dechirped baseband% Processing paramsNfft_r = 2^nextpow2(Ns*2); % range FFT size (zero-pad)Nfft_d = 2^nextpow2(Nchirp*2); % doppler FFT sizeNfft_a = 256; % angle FFT size (beamforming)use_MUSIC = true; % also compute MUSIC AoA (optional)MUSIC_K = size(targets,1); % number of sources assumed for MUSICguard_r = 2; train_r = 8; % 2D-CFAR params (range)guard_d = 2; train_d = 8; % 2D-CFAR params (doppler)Pfa = 1e-3; % CFAR false alarm% Derived limitsR_max = fs*c/(2*S); % unambiguous rangeV_max = lambda/(4*Tc); % +/- V_max unambiguousfprintf('Unambiguous Range ~ %.1f m, Unambiguous Velocity ~ +/- %.1f m/s\n',...R_max, V_max);%% ----------------------- Time & Grids -------------------------t_fast = (0:Ns-1)/fs; % fast-time within a chirpn_slow = (0:Nchirp-1).'; % chirp index (slow-time)f_fast = (0:Nfft_r-1)*(fs/Nfft_r); % beat freq axis (0..fs)R_axis = c * f_fast / (2*S); % beat freq -> range% Slow-time (Doppler) axis: PRF = 1/Tc, centeredf_doppler = (-Nfft_d/2:Nfft_d/2-1)*(1/(Tc*Nfft_d));V_axis = (lambda/2) * f_doppler;% Angle axis for Rx-ULA (broadside 0 deg; left negative)mu_axis = linspace(-1,1,Nfft_a);ang_axis = asind(mu_axis);%% ----------------------- Signal Simulation --------------------% Data cube: Rx x Nchirp x Ns (dechirped baseband)X = zeros(Rx, Nchirp, Ns);for k = 1:size(targets,1)R0 = targets(k,1);vk = targets(k,2);thet = targets(k,3) * pi/180;amp = targets(k,4);Rn = R0 + vk * n_slow * Tc; % Nchirp x 1tau = 2 * Rn / c; % Nchirp x 1fd = 2*vk/lambda; % Doppler (Hz)m_idx = (0:Rx-1).';phi_arr_m = 2*pi * (m_idx * d * sin(thet) / lambda); % Rx x 1S_tau = S * tau; % Nchirp x 1[S_tau_mat, t_fast_mat] = ndgrid(S_tau, t_fast);[n_slow_mat, ~] = ndgrid(n_slow, t_fast);phase_nt = 2*pi*((S_tau_mat + fd).*t_fast_mat + fd .* n_slow_mat * Tc); % Nchirp x Nsfor m = 1:RxX(m,:,:) = squeeze(X(m,:,:)) + amp * exp(1j*(phase_nt + phi_arr_m(m)));endend% Add AWGNsig_pow = mean(abs(X(:)).^2);noise_pw = sig_pow / (10^(SNR_dB/10));noise = sqrt(noise_pw/2) * (randn(size(X)) + 1j*randn(size(X)));X = X + noise;%% ----------------------- Range FFT ----------------------------win_r = hann(Ns).';X_r = zeros(Rx, Nchirp, Nfft_r);for m = 1:Rxfor n = 1:Nchirpx = squeeze(X(m,n,:)).' .* win_r;X_r(m,n,:) = fft(x, Nfft_r);endendvalid_r = R_axis <= R_max;R_hat = R_axis(valid_r);Nr = numel(R_hat);%% ----------------------- Doppler FFT (fixed) ------------------win_d = hann(Nchirp);Nd = Nfft_d;X_rd = zeros(Rx, Nd, Nr); % Rx x Nd x Nrfor m = 1:RxXr = squeeze(X_r(m,:,:)); % Nchirp x Nfft_rXr = Xr(:, valid_r); % Nchirp x NrXr = Xr .* repmat(win_d, 1, size(Xr,2));Xrd = fftshift(fft(Xr, Nd, 1), 1); % Nd x NrX_rd(m,:,:) = reshape(Xrd, [1, size(Xrd,1), size(Xrd,2)]);end% Non-coherent sum over Rx for detectionRD = squeeze(sum(abs(X_rd).^2, 1)); % Nd x Nr%% ----------------------- 2D-CFAR ------------------------------mag = RD;Nref = (2*train_r*2*train_d);alpha = ca_cfar_alpha(Nref, Pfa);det_map = false(Nd, Nr);for id = 1+train_d+guard_d : Nd - (train_d+guard_d)d_idx = [id-(train_d+guard_d):id-guard_d-1, id+guard_d+1:id+train_d+guard_d];for ir = 1+train_r+guard_r : Nr - (train_r+guard_r)r_idx = [ir-(train_r+guard_r):ir-guard_r-1, ir+guard_r+1:ir+train_r+guard_r];noise_est = mean(mag(d_idx, r_idx), 'all');if mag(id, ir) > alpha * (noise_est + eps)det_map(id, ir) = true;endendendpeak_idx = nms_peaks(mag, det_map, [3 3]); % [id, ir]%% ----------------------- Angle Estimation ---------------------est_list = []; % [R, V, AoA_FFT, Mag, AoA_MUSIC]for p = 1:size(peak_idx,1)id = peak_idx(p,1); % doppler binir = peak_idx(p,2); % range binfd_hat = f_doppler(id);V_est = (lambda/2) * fd_hat;R_est = R_hat(ir);x_m = squeeze(X_rd(:, id, ir)); % Rx x 1 snapshotang_spectrum = abs(fftshift(fft(x_m, Nfft_a))).^2;[~, ia] = max(ang_spectrum);ang_fft = ang_axis(ia);ang_music = NaN;if use_MUSIC && Rx >= (MUSIC_K+1)ang_music = music_aoa(x_m, d, lambda, Nfft_a, MUSIC_K);endest_list = [est_list; R_est, V_est, ang_fft, norm(x_m), ang_music]; %#ok<AGROW>end%% ----------------------- Truth (for annotations) ---------------R_true = targets(:,1);v_true = targets(:,2);th_true = targets(:,3);fd_true = 2*v_true/lambda; % Hz%% ----------------------- Visualization ------------------------% 1) Range profileRP = squeeze(sum(sum(abs(X_r(:,:,valid_r)).^2, 1), 2)); % 1 x Nrfigure; plot(R_hat, 10*log10(RP/max(RP)+1e-12), 'LineWidth',1.3);grid on; xlabel('Range (m)'); ylabel('Normalized Power (dB)');title('Range Profile');% 2) Range-Doppler map + detections + TRUTH + LEGENDfigure;imagesc(R_hat, f_doppler, 10*log10(mag./max(mag(:))+1e-12));axis xy; colorbar; xlabel('Range (m)'); ylabel('Doppler (Hz)');title('Range-Doppler Map (sum over Rx)');hold on;hDet = [];if ~isempty(peak_idx)hDet = scatter(R_hat(peak_idx(:,2)), f_doppler(peak_idx(:,1)), 40, 'w', 'filled', ...'DisplayName','Detections');endhTruth = plot(R_true, fd_true, 'p', 'MarkerSize', 12, 'MarkerEdgeColor', 'k', ...'MarkerFaceColor', [1 1 0], 'LineWidth', 1.5, 'DisplayName','Truth');for i = 1:numel(R_true)text(R_true(i)+0.5, fd_true(i), sprintf('T%d', i), ...'Color', 'k', 'FontWeight', 'bold', 'VerticalAlignment', 'middle');end% Legendif isempty(hDet)legend(hTruth, 'Location','best');elselegend([hDet, hTruth], {'Detections','Truth'}, 'Location','best');endhold off;% 3) Angle spectrum for top-1 detection (FFT beamforming)if ~isempty(peak_idx)id = peak_idx(1,1); ir = peak_idx(1,2);x_m = squeeze(X_rd(:, id, ir));ang_spec = abs(fftshift(fft(x_m, Nfft_a))).^2;ang_spec = ang_spec / max(ang_spec + 1e-12);figure; plot(ang_axis, 10*log10(ang_spec+1e-12), 'LineWidth',1.3); grid on;xlabel('Azimuth (deg)'); ylabel('dB');title('Angle Spectrum (Top-1, FFT Beamforming)');end% 4) Angle–Range 2D Map using "per-range strongest Doppler slice" + TRUTH + LEGEND[~, id_max_per_r] = max(RD, [], 1); % 1 x Nr (each range bin's strongest Doppler bin index)RA = zeros(Nfft_a, Nr);for ir = 1:Nrx_m = squeeze(X_rd(:, id_max_per_r(ir), ir)); % Rx x 1ang_spec = abs(fftshift(fft(x_m, Nfft_a))).^2; % Nfft_a x 1RA(:, ir) = ang_spec;endRA = RA / (max(RA(:)) + 1e-12);figure;imagesc(R_hat, ang_axis, 10*log10(RA + 1e-12));axis xy; colorbar; xlabel('Range (m)'); ylabel('Azimuth (deg)');title('Angle–Range Map (per-range strongest Doppler slice)');hold on;% truth overlay: only plot if target's fd is close to the chosen slice at its nearest range bindf = abs(f_doppler(2) - f_doppler(1)); % Doppler frequency resolutiontol = 1.5*df; % tolerance: ~1.5 binstruth_mask = false(size(R_true));for i = 1:numel(R_true)[~, ir0] = min(abs(R_hat - R_true(i))); % nearest range-bin to target rangefd_slice = f_doppler(id_max_per_r(ir0)); % doppler slice used for this rangetruth_mask(i) = abs(fd_true(i) - fd_slice) <= tol;endhTruthRA = plot(R_true(truth_mask), th_true(truth_mask), 'p', 'MarkerSize', 11, ...'MarkerEdgeColor','k','MarkerFaceColor',[1 1 0],'LineWidth',1.3, 'DisplayName','Truth near slice');for i = 1:numel(R_true)if truth_mask(i)text(R_true(i)+0.5, th_true(i), sprintf('T%d',i), ...'Color','k','FontWeight','bold','VerticalAlignment','middle');endendlegend(hTruthRA, 'Location','best');hold off;% 5) 3D Scatter of Detections in (Range, Velocity, Angle) + TRUTH + LEGENDif ~isempty(est_list)ang_use = est_list(:,5); % prefer MUSIC if availablenan_idx = isnan(ang_use);ang_use(nan_idx) = est_list(nan_idx,3); % fallback to FFT AoAmag_lin = est_list(:,4);mag_db = 20*log10(mag_lin / (max(mag_lin)+1e-12));sz = 30 + 70*(mag_lin / (max(mag_lin)+1e-12)); % marker size by magnitudefigure;hDet3 = scatter3(est_list(:,1), est_list(:,2), ang_use, sz, mag_db, 'filled', ...'DisplayName','Detections');grid on; xlabel('Range (m)'); ylabel('Velocity (m/s)'); zlabel('Azimuth (deg)');title('3D Detection Cloud: Range–Velocity–Angle');cb = colorbar; cb.Label.String = 'Magnitude (dB, relative)';view(45,25);hold on;hTruth3 = plot3(R_true, v_true, th_true, 'p', 'MarkerSize', 12, ...'MarkerEdgeColor','k','MarkerFaceColor',[1 1 0], 'LineWidth',1.5, ...'DisplayName','Truth');for i = 1:numel(R_true)text(R_true(i), v_true(i), th_true(i)+1.0, sprintf('T%d',i), ...'Color','k','FontWeight','bold');endlegend([hDet3 hTruth3], {'Detections','Truth'}, 'Location','best');hold off;end%% ----------------------- Print Detections ---------------------if isempty(est_list)fprintf('No detections. Try lowering threshold (increase Pfa) or raising SNR.\n');else% Sort by magnitude (desc)[~, ord] = sort(est_list(:,4), 'descend');est_sorted = est_list(ord,:);fprintf('\nDetections (after 2D-CFAR + AoA):\n');if use_MUSICfprintf(' %9s %10s %10s %10s %12s %10s\n','Range(m)','Vel(m/s)','AoA_FFT','Mag','AoA_MUSIC','Mag(dB)');for i=1:size(est_sorted,1)mag_db = 20*log10(est_sorted(i,4)/(max(est_sorted(:,4))+1e-12));fprintf(' %9.2f %10.2f %10.1f %10.2f %12.1f %10.1f\n', ...est_sorted(i,1), est_sorted(i,2), est_sorted(i,3), est_sorted(i,4), est_sorted(i,5), mag_db);endelsefprintf(' %9s %10s %10s %10s %10s\n','Range(m)','Vel(m/s)','AoA_FFT','Mag','Mag(dB)');for i=1:size(est_sorted,1)mag_db = 20*log10(est_sorted(i,4)/(max(est_sorted(:,4))+1e-12));fprintf(' %9.2f %10.2f %10.1f %10.2f %10.1f\n', ...est_sorted(i,1), est_sorted(i,2), est_sorted(i,3), est_sorted(i,4), mag_db);endendend%% ----------------------- Helper Functions ---------------------function alpha = ca_cfar_alpha(Nref, Pfa)% Return CA-CFAR scaling alpha for given reference cells and Pfa% Using approximate formula: Pfa = (1+alpha/Nref)^(-Nref)% => alpha = Nref * (Pfa^(-1/Nref) - 1)alpha = Nref * (Pfa^(-1/Nref) - 1);endfunction peaks = nms_peaks(mag, det_map, nms_sz)% Simple Non-Maximum Suppression on det_map using local neighborhood nms_sz% mag: Nd x Nr, det_map: logical same size, nms_sz = [h w][H, W] = size(mag);hh = floor(nms_sz(1)/2);ww = floor(nms_sz(2)/2);idx = find(det_map);keep = true(size(idx));for k = 1:length(idx)if ~keep(k), continue; end[r, c] = ind2sub([H,W], idx(k));r1 = max(1, r-hh); r2 = min(H, r+hh);c1 = max(1, c-ww); c2 = min(W, c+ww);patch = mag(r1:r2, c1:c2);if mag(r,c) < max(patch(:)) - epskeep(k) = false;continue;end[rr, cc] = find(det_map(r1:r2, c1:c2));rr = rr + (r1-1); cc = cc + (c1-1);nbr_lin = sub2ind([H,W], rr, cc);for t = 1:numel(nbr_lin)if nbr_lin(t) == idx(k), continue; endj = find(idx == nbr_lin(t), 1);if ~isempty(j), keep(j) = false; endendendsel = idx(keep);[rr2, cc2] = ind2sub([H,W], sel);peaks = [rr2, cc2];endfunction ang_hat = music_aoa(x_m, d, lambda, Nfft_a, K)% x_m: Rx x 1 snapshot at a single range-doppler bin% Returns peak of MUSIC spectrum (deg)M = numel(x_m);Rxx = (x_m * x_m')/M;Rxx = Rxx + (1e-3*trace(Rxx)/M)*eye(M);[V, D] = eig((Rxx+Rxx')/2);[~, idx] = sort(real(diag(D)), 'ascend');K = min(K, M-1);En = V(:, idx(1:M-K));mu_axis = linspace(-1,1, Nfft_a);P = zeros(1, Nfft_a);m = (0:M-1).';for i = 1:Nfft_aa = exp(1j*2*pi*(m*d/lambda)*mu_axis(i));denom = real(a'*(En*En')*a);if denom <= 0, denom = eps; endP(i) = 1 / denom;end[~, ia] = max(P);ang_hat = asind(mu_axis(ia));end
8. 结论
FMCW 雷达通过单帧 2D-FFT与阵列角度谱即可获得可靠的 R–V–AoA 估计;带宽、PRF、阵列孔径直接决定分辨率与无模糊范围。工程实现应兼顾前端链路、校准与检测门限设计,以在复杂环境中保持稳健性能。