第06篇:干涉仪与相位差测向

一、作用:用"相位尺"量角度
上一篇文章中,Watson-Watt 利用两个正交天线的幅度比来测向,简单可靠,但精度有限------当天线方向图在峰值附近变平缓时,幅度对角度的敏感度急剧下降。
如果我们要实现 0.01° 量级的超高精度测向,必须换一把更精密的"尺子"。
这把尺子就是相位。
干涉仪(Interferometer) 利用两个(或多个)间距为 ddd 的天线,测量同一信号到达两个天线时的相位差 Δϕ\Delta\phiΔϕ。由于电磁波到达两个天线的路径长度不同,相位差与来波方向 θ\thetaθ 之间存在确定的几何关系。相位差每变化 2π2\pi2π,对应路径差变化一个波长------这个极短的距离尺度,赋予了干涉仪极高的角度敏感度。
本篇核心作用 :从双天线干涉仪的基本公式出发,推导相位差与角度的关系,揭示相位模糊问题(当基线超过半波长时出现),并用多基线解模糊。最终通过蒙特卡洛仿真验证干涉仪测向的 CRLB,并与 Watson-Watt 做精度对比。
二、原理:数学上发生了什么?
2.1 双天线干涉仪的基本几何
考虑两个天线,间距为 ddd,来波方向与阵列法线夹角为 θ\thetaθ(远场平面波假设)。
两个天线接收到的信号路径差为:
ΔR=d⋅sinθ\Delta R = d \cdot \sin\thetaΔR=d⋅sinθ
对应的相位差为:
Δϕ=2πλ⋅d⋅sinθ=2π⋅dλ⋅sinθ\Delta\phi = \frac{2\pi}{\lambda} \cdot d \cdot \sin\theta = 2\pi \cdot \frac{d}{\lambda} \cdot \sin\thetaΔϕ=λ2π⋅d⋅sinθ=2π⋅λd⋅sinθ
其中 λ=c/f0\lambda = c/f_0λ=c/f0 是信号波长。
由此可以反解出来波方向:
θ^=arcsin(Δϕ⋅λ2πd)=arcsin(Δϕ2π⋅d/λ)\hat{\theta} = \arcsin\left( \frac{\Delta\phi \cdot \lambda}{2\pi d} \right) = \arcsin\left( \frac{\Delta\phi}{2\pi \cdot d/\lambda} \right)θ^=arcsin(2πdΔϕ⋅λ)=arcsin(2π⋅d/λΔϕ)
2.2 相位模糊:干涉仪的"阿喀琉斯之踵"
相位差 Δϕ\Delta\phiΔϕ 的测量范围是 −π,π-\\pi, \\pi−π,π(相位只能测到 2π2\pi2π 的模)。当 d/λ>0.5d/\lambda > 0.5d/λ>0.5 时,真实的相位差可能超过 π\piπ,此时测量值会发生卷绕(wrap):
Δϕmeasured=wrap(Δϕtrue)=Δϕtrue−2πk\Delta\phi_{\text{measured}} = \text{wrap}(\Delta\phi_{\text{true}}) = \Delta\phi_{\text{true}} - 2\pi kΔϕmeasured=wrap(Δϕtrue)=Δϕtrue−2πk
其中 kkk 是未知的整数。这意味着同一个相位差测量值可能对应多个不同的来波方向------这就是相位模糊。
- d/λ≤0.5d/\lambda \leq 0.5d/λ≤0.5:无模糊,但精度低(基线短,相位对角度的变化率小)。
- d/λ>0.5d/\lambda > 0.5d/λ>0.5:精度高,但存在模糊。
解决方案 :使用多基线------长基线提供高精度,短基线提供无模糊粗估计,逐级解模糊。
2.3 多基线解模糊
假设我们有 LLL 个天线,间距分别为 d1,d2,...,dL−1d_1, d_2, \ldots, d_{L-1}d1,d2,...,dL−1。最常用的配置是双基线 :一个短基线(d1/λ≤0.5d_1/\lambda \leq 0.5d1/λ≤0.5,无模糊)和一个长基线(d2/λ≫0.5d_2/\lambda \gg 0.5d2/λ≫0.5,高精度)。
解模糊步骤:
- 用短基线得到粗估计 θ^coarse\hat{\theta}_{\text{coarse}}θ^coarse(无模糊)。
- 由粗估计预测长基线的相位差:Δϕ2,pred=2π(d2/λ)sinθ^coarse\Delta\phi_{2,\text{pred}} = 2\pi (d_2/\lambda) \sin\hat{\theta}_{\text{coarse}}Δϕ2,pred=2π(d2/λ)sinθ^coarse。
- 计算长基线测量的模糊整数:k=round(Δϕ2,pred−Δϕ2,meas2π)k = \text{round}\left( \frac{\Delta\phi_{2,\text{pred}} - \Delta\phi_{2,\text{meas}}}{2\pi} \right)k=round(2πΔϕ2,pred−Δϕ2,meas)。
- 解模糊后的相位差:Δϕ2,unamb=Δϕ2,meas+2πk\Delta\phi_{2,\text{unamb}} = \Delta\phi_{2,\text{meas}} + 2\pi kΔϕ2,unamb=Δϕ2,meas+2πk。
- 用解模糊后的相位差得到高精度估计。
2.4 相位差估计的 CRLB
对于加性高斯白噪声环境,相位差估计的克拉美-罗下限为:
σΔϕ2≥12Mξ\sigma_{\Delta\phi}^2 \geq \frac{1}{2M\xi}σΔϕ2≥2Mξ1
其中 MMM 是时间带宽积,ξ\xiξ 是信噪比。角度估计的 CRLB 通过相位差对角度求导得到:
∂Δϕ∂θ=2πdλcosθ\frac{\partial \Delta\phi}{\partial \theta} = 2\pi \frac{d}{\lambda} \cos\theta∂θ∂Δϕ=2πλdcosθ
因此:
σθ2≥σΔϕ2(∂Δϕ∂θ)2=12Mξ⋅(2πdλcosθ)2\sigma_\theta^2 \geq \frac{\sigma_{\Delta\phi}^2}{\left( \frac{\partial \Delta\phi}{\partial \theta} \right)^2} = \frac{1}{2M\xi \cdot \left( 2\pi \frac{d}{\lambda} \cos\theta \right)^2}σθ2≥(∂θ∂Δϕ)2σΔϕ2=2Mξ⋅(2πλdcosθ)21
关键洞察:基线越长(d/λd/\lambdad/λ 越大),角度精度越高 ,但模糊问题也越严重。在 θ=0\theta = 0θ=0(正对法线)时精度最高;在 θ=±90°\theta = \pm 90°θ=±90° 时精度最差(cosθ→0\cos\theta \to 0cosθ→0,相位差对角度的变化率趋零)。
三、完整代码(可直接运行)
本代码复现了原书 ch7_drawFigures 中干涉仪部分的核心内容(图7.11、7.12、7.14),包含:
- 干涉仪方向图 :不同 d/λd/\lambdad/λ 下的响应曲线
- 相位差与角度的关系:展示卷绕现象
- 双基线解模糊算法:完整的解模糊流程
- 蒙特卡洛仿真 :验证 CRLB 并与 Watson-Watt 对比

matlab
%% ========================================================================
% 第06篇:干涉仪与相位差测向(完整修复版)
% 在原代码基础上新增:
% 扩展1 - 解模糊成功率 vs SNR(蒙特卡洛)
% 扩展2 - 三基线解模糊(鲁棒性提升)
% 扩展3 - 2D 干涉仪(L型阵列,方位+俯仰)
% 修复:interp1 采样点重复问题
% ========================================================================
clear; close all; clc;
%% ==================== 图1:干涉仪基础特性(3子图) ====================
d_lam_vec = [0.5, 1, 2, 4];
psi_0_deg = -10;
psi_0 = deg2rad(psi_0_deg);
psi_deg = linspace(-60, 60, 4001);
psi_rad = deg2rad(psi_deg);
colors = lines(length(d_lam_vec));
figure;
sgtitle('干涉仪测向基础特性', 'FontSize', 14, 'FontWeight', 'bold');
% 子图1:方向图
subplot(1, 3, 1); hold on;
for idx = 1:length(d_lam_vec)
d_lam = d_lam_vec(idx);
g = (1 + exp(1i * 2*pi * d_lam * (sin(psi_rad) - sin(psi_0)))) / 2;
plot(psi_deg, 20*log10(abs(g) + eps), 'Color', colors(idx,:), ...
'DisplayName', sprintf('d/\\lambda = %.1f', d_lam));
end
xlabel('角度 \psi [度]'); ylabel('响应 [dB]');
title('干涉仪方向图'); legend('Location', 'southwest'); grid on;
xlim([-60, 60]); ylim([-30, 2]);
xline(psi_0_deg, '--k', 'LineWidth', 1);
% 子图2:相位差卷绕
subplot(1, 3, 2); hold on;
for idx = 1:length(d_lam_vec)
d_lam = d_lam_vec(idx);
delta_phi = 2*pi * d_lam * sin(psi_rad);
plot(psi_deg, wrapToPiLocal(delta_phi)/pi, 'Color', colors(idx,:), ...
'DisplayName', sprintf('d/\\lambda = %.1f', d_lam));
end
xlabel('角度 \psi [度]'); ylabel('相位差 / \pi');
title('相位差卷绕'); legend('Location', 'southwest'); grid on;
xlim([-60, 60]); ylim([-1.4, 1.4]);
yline(1, '--k', 'LineWidth', 0.8); yline(-1, '--k', 'LineWidth', 0.8);
% 子图3:角度灵敏度
subplot(1, 3, 3); hold on;
for idx = 1:length(d_lam_vec)
d_lam = d_lam_vec(idx);
plot(psi_deg, 2*pi*d_lam*abs(cos(psi_rad)), 'Color', colors(idx,:), ...
'DisplayName', sprintf('d/\\lambda = %.1f', d_lam));
end
xlabel('角度 \psi [度]'); ylabel('|d\Delta\phi/d\psi|');
title('角度灵敏度'); legend('Location', 'southwest'); grid on;
xlim([-60, 60]); ylim([0, 30]);
%% ==================== 图2:双基线解模糊原理(2子图) ====================
d1_lam = 0.5; d2_lam = 4.0;
theta_true_deg = 25;
theta_true_rad = deg2rad(theta_true_deg);
phi1_true = 2*pi*d1_lam*sin(theta_true_rad);
phi2_true = 2*pi*d2_lam*sin(theta_true_rad);
rng(42);
noise_std = 0.15;
phi1_meas = wrapToPiLocal(phi1_true + noise_std*randn());
phi2_meas = wrapToPiLocal(phi2_true + noise_std*randn());
theta_coarse = asin(phi1_meas / (2*pi*d1_lam));
phi2_pred = 2*pi*d2_lam*sin(theta_coarse);
k_est = round((phi2_pred - phi2_meas) / (2*pi));
phi2_unamb = phi2_meas + 2*pi*k_est;
theta_fine = asin(phi2_unamb / (2*pi*d2_lam));
fprintf('======= 双基线解模糊演示 =======\n');
fprintf('真实角度 : %.4f°\n', theta_true_deg);
fprintf('短基线粗估计 : %.4f°\n', rad2deg(theta_coarse));
fprintf('模糊整数 k : %d\n', k_est);
fprintf('长基线精估计 : %.4f°\n', rad2deg(theta_fine));
figure;
sgtitle('双基线解模糊原理', 'FontSize', 14, 'FontWeight', 'bold');
theta_scan_deg = linspace(-60, 60, 2001);
theta_scan_rad = deg2rad(theta_scan_deg);
phi2_true_curve = 2*pi*d2_lam*sin(theta_scan_rad);
k_vec = -3:3;
for sp = 1:2
subplot(1, 2, sp); hold on;
plot(theta_scan_deg, phi2_true_curve/pi, 'k-', 'LineWidth', 1.5, ...
'DisplayName', '长基线真实相位差');
yline(phi2_meas/pi, 'r-', 'LineWidth', 2, 'DisplayName', '测量值');
for k = k_vec
plot(theta_scan_deg, (phi2_meas + 2*pi*k)/pi * ones(size(theta_scan_deg)), ...
'--', 'Color', [0.5 0.5 0.5], 'LineWidth', 0.8, 'HandleVisibility', 'off');
end
for k = k_vec
sin_arg = (phi2_meas + 2*pi*k) / (2*pi*d2_lam);
if abs(sin_arg) <= 1
plot(rad2deg(asin(sin_arg)), (phi2_meas + 2*pi*k)/pi, 'bo', ...
'MarkerSize', 8, 'MarkerFaceColor', 'b', 'HandleVisibility', 'off');
end
end
plot(rad2deg(theta_fine), (phi2_meas + 2*pi*k_est)/pi, 'r^', ...
'MarkerSize', 14, 'MarkerFaceColor', 'r', 'DisplayName', '选中解');
plot(theta_true_deg, phi2_true/pi, 'kp', 'MarkerSize', 14, 'LineWidth', 2, ...
'DisplayName', '真实角度');
xlabel('角度 \theta [度]'); ylabel('相位差 / \pi');
grid on; legend('Location', 'northwest');
end
subplot(1, 2, 1); title('全局视图'); xlim([-60, 60]); ylim([-10, 10]);
subplot(1, 2, 2); title(sprintf('局部放大 (k = %d)', k_est));
xlim([theta_true_deg-15, theta_true_deg+15]);
ylim([(phi2_true/pi)-3, (phi2_true/pi)+3]);
%% ==================== 图3:CRLB 对比(2子图) ====================
figure;
sgtitle('干涉仪性能分析', 'FontSize', 14, 'FontWeight', 'bold');
subplot(1, 2, 1); hold on;
theta_scan2 = linspace(-60, 60, 1001);
theta_scan2_rad = deg2rad(theta_scan2);
M_a = 10; SNR_dB = 10; SNR_lin = 10^(SNR_dB/10);
crlb_short = rad2deg(1 ./ (2*pi*d1_lam*cos(theta_scan2_rad) * sqrt(2*M_a*SNR_lin)));
crlb_long = rad2deg(1 ./ (2*pi*d2_lam*cos(theta_scan2_rad) * sqrt(2*M_a*SNR_lin)));
semilogy(theta_scan2, crlb_short, 'b-', 'LineWidth', 2, 'DisplayName', '短基线 d/\lambda=0.5');
semilogy(theta_scan2, crlb_long, 'r-', 'LineWidth', 2, 'DisplayName', '长基线 d/\lambda=4');
xlabel('角度 \theta [度]'); ylabel('CRLB [度]');
title(sprintf('短基线 vs 长基线 (SNR=%ddB, M=%d)', SNR_dB, M_a));
legend('Location', 'northwest'); grid on;
xlim([-60, 60]); ylim([1e-3, 10]);
subplot(1, 2, 2); hold on;
snr_db_vec = -5:0.5:25;
snr_lin_vec = 10.^(snr_db_vec/10);
M_a2 = 10;
crlb_ifm = rad2deg(1 ./ (2*pi*0.5 * sqrt(2*M_a2*snr_lin_vec)));
crlb_ww = rad2deg(1 ./ sqrt(2*M_a2*snr_lin_vec));
semilogy(snr_db_vec, crlb_ww, 'b--', 'LineWidth', 2, 'DisplayName', 'Watson-Watt');
semilogy(snr_db_vec, crlb_ifm, 'r-', 'LineWidth', 2, 'DisplayName', '干涉仪 (d/\lambda=0.5)');
xlabel('信噪比 \xi [dB]'); ylabel('CRLB [度]');
title('干涉仪 vs Watson-Watt (M=10)');
legend('Location', 'southwest'); grid on;
xlim([-5, 25]); ylim([0.01, 30]);
%% ==================== 扩展1:解模糊成功率 vs SNR ====================
fprintf('\n执行扩展1:解模糊成功率蒙特卡洛...\n');
theta_true_ex = 25;
theta_true_ex_rad = deg2rad(theta_true_ex);
snr_db_ex = -10:2:20;
snr_lin_ex = 10.^(snr_db_ex/10);
num_mc_ex = 5000;
success_rate = zeros(size(snr_db_ex));
for idx = 1:length(snr_db_ex)
snr = snr_lin_ex(idx);
phase_std = sqrt(1/(2*snr));
phi1_true_ex = 2*pi*d1_lam*sin(theta_true_ex_rad);
phi2_true_ex = 2*pi*d2_lam*sin(theta_true_ex_rad);
phi1_meas_mc = wrapToPiLocal(phi1_true_ex + phase_std*randn(1, num_mc_ex));
phi2_meas_mc = wrapToPiLocal(phi2_true_ex + phase_std*randn(1, num_mc_ex));
theta_c = asin(phi1_meas_mc / (2*pi*d1_lam));
phi2_p = 2*pi*d2_lam*sin(theta_c);
k_est_mc = round((phi2_p - phi2_meas_mc) / (2*pi));
phi2_u = phi2_meas_mc + 2*pi*k_est_mc;
theta_f = asin(phi2_u / (2*pi*d2_lam));
err_mc = abs(rad2deg(theta_f) - theta_true_ex);
success_rate(idx) = sum(err_mc < 1) / num_mc_ex;
end
figure;
plot(snr_db_ex, success_rate*100, 'bo-', 'LineWidth', 2, 'MarkerSize', 9);
xlabel('信噪比 \xi [dB]'); ylabel('解模糊成功率 [%]');
title(sprintf('双基线解模糊成功率 (\\theta=%d°, d_1/\\lambda=%.1f, d_2/\\lambda=%.1f)', ...
theta_true_ex, d1_lam, d2_lam));
grid on; ylim([0, 105]); xlim([-10, 20]);
yline(99, 'r--', 'LineWidth', 1.5);
text(-8, 100, '99% 成功率门限', 'Color', 'r', 'FontSize', 10);
% ---- 修复段:手动线性插值求 99% 门限(避免 interp1 采样点重复问题) ----
idx_above = find(success_rate >= 0.99, 1, 'first');
if isempty(idx_above)
snr_threshold = NaN;
elseif idx_above == 1
snr_threshold = snr_db_ex(1);
else
x1 = snr_db_ex(idx_above-1); y1 = success_rate(idx_above-1)*100;
x2 = snr_db_ex(idx_above); y2 = success_rate(idx_above)*100;
if y2 == y1
snr_threshold = x2;
else
snr_threshold = x1 + (99 - y1) * (x2 - x1) / (y2 - y1);
end
end
if ~isnan(snr_threshold) && snr_threshold >= min(snr_db_ex) && snr_threshold <= max(snr_db_ex)
text(snr_threshold + 0.5, 90, ...
sprintf('SNR_{min} ≈ %.1f dB', snr_threshold), ...
'FontSize', 11, 'Color', 'r', 'FontWeight', 'bold');
end
% ---- 修复段结束 ----
%% ==================== 扩展2:三基线解模糊(鲁棒性提升) ====================
fprintf('\n执行扩展2:三基线解模糊对比...\n');
d_lam_set = [0.5, 2.0, 4.0];
num_base = length(d_lam_set);
success_rate_3 = zeros(size(snr_db_ex));
for idx = 1:length(snr_db_ex)
snr = snr_lin_ex(idx);
phase_std = sqrt(1/(2*snr));
phi_true_all = 2*pi*d_lam_set * sin(theta_true_ex_rad);
phi_meas_all = wrapToPiLocal(phi_true_all(:) + phase_std*randn(num_base, num_mc_ex));
% 逐级递推解模糊
theta_c3 = asin(phi_meas_all(1,:) / (2*pi*d_lam_set(1)));
phi2_pred3 = 2*pi*d_lam_set(2)*sin(theta_c3);
k2 = round((phi2_pred3 - phi_meas_all(2,:)) / (2*pi));
phi2_unamb3 = phi_meas_all(2,:) + 2*pi*k2;
theta_mid = asin(phi2_unamb3 / (2*pi*d_lam_set(2)));
phi3_pred3 = 2*pi*d_lam_set(3)*sin(theta_mid);
k3 = round((phi3_pred3 - phi_meas_all(3,:)) / (2*pi));
phi3_unamb3 = phi_meas_all(3,:) + 2*pi*k3;
theta_f3 = asin(phi3_unamb3 / (2*pi*d_lam_set(3)));
err3 = abs(rad2deg(theta_f3) - theta_true_ex);
success_rate_3(idx) = sum(err3 < 1) / num_mc_ex;
end
figure;
plot(snr_db_ex, success_rate*100, 'bo-', 'LineWidth', 2, ...
'MarkerSize', 9, 'DisplayName', '双基线 (0.5, 4)');
hold on;
plot(snr_db_ex, success_rate_3*100, 'rs-', 'LineWidth', 2, ...
'MarkerSize', 9, 'DisplayName', '三基线 (0.5, 2, 4)');
xlabel('信噪比 \xi [dB]'); ylabel('解模糊成功率 [%]');
title('双基线 vs 三基线解模糊鲁棒性对比');
grid on; ylim([0, 105]); xlim([-10, 20]);
legend('Location', 'southeast');
% ---- 修复段:直接用 find,不再依赖 interp1 ----
idx_99_2 = find(success_rate >= 0.99, 1, 'first');
idx_99_3 = find(success_rate_3 >= 0.99, 1, 'first');
if ~isempty(idx_99_2) && ~isempty(idx_99_3)
fprintf('双基线达到 99%% 成功率的 SNR 门限: %.1f dB\n', snr_db_ex(idx_99_2));
fprintf('三基线达到 99%% 成功率的 SNR 门限: %.1f dB\n', snr_db_ex(idx_99_3));
fprintf('三基线带来的 SNR 门限改善: %.1f dB\n', ...
snr_db_ex(idx_99_2) - snr_db_ex(idx_99_3));
end
% ---- 修复段结束 ----
%% ==================== 扩展3:2D 干涉仪(L型阵列,方位+俯仰) ====================
fprintf('\n执行扩展3:2D 干涉仪(L型阵列)...\n');
d_x_lam = 0.5;
d_y_lam = 0.5;
az_true_deg = 30;
el_true_deg = 60;
az_true = deg2rad(az_true_deg);
el_true = deg2rad(el_true_deg);
u_true = sin(el_true)*cos(az_true);
v_true = sin(el_true)*sin(az_true);
phi_x_true = 2*pi*d_x_lam*u_true;
phi_y_true = 2*pi*d_y_lam*v_true;
noise_std_2d = 0.1;
phi_x_meas = wrapToPiLocal(phi_x_true + noise_std_2d*randn());
phi_y_meas = wrapToPiLocal(phi_y_true + noise_std_2d*randn());
u_est = phi_x_meas / (2*pi*d_x_lam);
v_est = phi_y_meas / (2*pi*d_y_lam);
el_est = asin(min(max(sqrt(u_est^2 + v_est^2), -1), 1));
az_est = atan2(v_est, u_est);
fprintf('真实方位角: %.2f°, 真实俯仰角: %.2f°\n', az_true_deg, el_true_deg);
fprintf('估计方位角: %.2f°, 估计俯仰角: %.2f°\n', ...
rad2deg(az_est), rad2deg(el_est));
% 2D 可视化
figure;
sgtitle('L型 2D 干涉仪方向估计', 'FontSize', 14, 'FontWeight', 'bold');
subplot(1, 2, 1);
plot3([0 d_x_lam], [0 0], [0 0], 'ko-', 'LineWidth', 2, 'MarkerSize', 10, ...
'MarkerFaceColor', 'k'); hold on;
plot3([0 0], [0 d_y_lam], [0 0], 'ko-', 'LineWidth', 2, 'MarkerSize', 10, ...
'MarkerFaceColor', 'k');
r_vis = 1.2;
plot3([0 r_vis*u_true], [0 r_vis*v_true], [0 r_vis*cos(el_true)], ...
'r-', 'LineWidth', 2);
plot3([0 r_vis*u_est], [0 r_vis*v_est], [0 r_vis*cos(el_est)], ...
'b--', 'LineWidth', 2);
text(0.1, 0, 0, 'A_0', 'FontSize', 11, 'FontWeight', 'bold');
text(d_x_lam+0.05, 0, 0, 'A_1 (x)', 'FontSize', 10);
text(0, d_y_lam+0.05, 0, 'A_2 (y)', 'FontSize', 10);
xlabel('x/λ'); ylabel('y/λ'); zlabel('z');
title('几何示意'); grid on; axis equal;
view([30, 20]);
legend({'x 基线', 'y 基线', '真实方向', '估计方向'}, 'Location', 'northeast');
subplot(1, 2, 2);
polarplot(az_true, el_true, 'r^', 'MarkerSize', 14, 'MarkerFaceColor', 'r'); hold on;
polarplot(az_est, el_est, 'bo', 'MarkerSize', 12, 'MarkerFaceColor', 'b');
polarplot(az_true, el_true, 'r--', 'LineWidth', 1);
polarplot(az_est, el_est, 'b--', 'LineWidth', 1);
title('方位-俯仰估计(极坐标,半径=俯仰角)');
legend({'真实', '估计'}, 'Location', 'southoutside');
% 蒙特卡洛:2D 估计精度
num_mc_2d = 5000;
az_rmse = zeros(size(snr_db_ex));
el_rmse = zeros(size(snr_db_ex));
for idx = 1:length(snr_db_ex)
snr = snr_lin_ex(idx);
phase_std = sqrt(1/(2*snr));
phi_x_mc = wrapToPiLocal(phi_x_true + phase_std*randn(1, num_mc_2d));
phi_y_mc = wrapToPiLocal(phi_y_true + phase_std*randn(1, num_mc_2d));
u_mc = phi_x_mc / (2*pi*d_x_lam);
v_mc = phi_y_mc / (2*pi*d_y_lam);
el_mc = asin(min(max(sqrt(u_mc.^2 + v_mc.^2), -1), 1));
az_mc = atan2(v_mc, u_mc);
az_err = mod(rad2deg(az_mc) - az_true_deg + 180, 360) - 180;
el_err = rad2deg(el_mc) - el_true_deg;
az_rmse(idx) = sqrt(mean(az_err.^2));
el_rmse(idx) = sqrt(mean(el_err.^2));
end
figure;
sgtitle('2D 干涉仪测向精度(L型阵列,d/λ=0.5)', 'FontSize', 14, 'FontWeight', 'bold');
subplot(1, 2, 1);
semilogy(snr_db_ex, az_rmse, 'bo-', 'LineWidth', 2, 'MarkerSize', 8, ...
'DisplayName', '方位角 RMSE');
hold on;
semilogy(snr_db_ex, el_rmse, 'rs-', 'LineWidth', 2, 'MarkerSize', 8, ...
'DisplayName', '俯仰角 RMSE');
xlabel('信噪比 \xi [dB]'); ylabel('RMSE [度]');
title(sprintf('估计精度 (az=%d°, el=%d°)', az_true_deg, el_true_deg));
grid on; legend('Location', 'southwest');
xlim([-10, 20]); ylim([0.01, 100]);
subplot(1, 2, 2);
SNR_fix_dB = 10;
SNR_fix = 10^(SNR_fix_dB/10);
el_scan_deg = 10:5:85;
el_scan_rad = deg2rad(el_scan_deg);
phase_std_fix = sqrt(1/(2*SNR_fix));
az_rmse_vs_el = zeros(size(el_scan_deg));
for idx = 1:length(el_scan_deg)
u_t = sin(el_scan_rad(idx))*cos(az_true);
v_t = sin(el_scan_rad(idx))*sin(az_true);
px = 2*pi*d_x_lam*u_t;
py = 2*pi*d_y_lam*v_t;
px_mc = wrapToPiLocal(px + phase_std_fix*randn(1, 2000));
py_mc = wrapToPiLocal(py + phase_std_fix*randn(1, 2000));
u_mc = px_mc / (2*pi*d_x_lam);
v_mc = py_mc / (2*pi*d_y_lam);
az_mc = atan2(v_mc, u_mc);
az_err = mod(rad2deg(az_mc) - az_true_deg + 180, 360) - 180;
az_rmse_vs_el(idx) = sqrt(mean(az_err.^2));
end
semilogy(el_scan_deg, az_rmse_vs_el, 'k^-', 'LineWidth', 2, 'MarkerSize', 8);
xlabel('俯仰角 \theta_{el} [度]'); ylabel('方位角 RMSE [度]');
title(sprintf('方位角精度 vs 俯仰角 (SNR=%ddB)', SNR_fix_dB));
grid on; xlim([10, 85]); ylim([0.01, 100]);
text(15, 20, '低俯仰角精度恶化', 'FontSize', 10, 'Color', 'r');
fprintf('\n======= 全部扩展完成 =======\n');
%% ==================== 函数定义 ====================
function y = wrapToPiLocal(x)
% 将角度卷绕到 [-pi, pi](本地实现,避免与工具箱冲突)
y = mod(x + pi, 2*pi) - pi;
end
四、代码讲解:为什么这么写?
4.1 干涉仪复响应的构造
matlab
g = (1 + exp(1i * 2 * pi * d_lam * (sin(theta_rad) - sin(psi_0)))) / 2;
这是两阵元等权合成波束的响应。为什么用 sin(theta) - sin(psi_0)?因为相位差取决于路径差相对于参考方向 的增量。当 θ=ψ0\theta = \psi_0θ=ψ0 时,相位差为零,两路信号同相叠加,响应最大。当 d/λd/\lambdad/λ 增大时,响应主瓣变窄,旁瓣增多------这就是干涉仪的"多瓣"特性(图7.12的核心)。
4.2 相位卷绕与 wrapToPi
matlab
delta_phi_wrapped = wrapToPi(delta_phi_true);
真实相位差可能达到 2π×d/λ2\pi \times d/\lambda2π×d/λ(当 d/λ=4d/\lambda = 4d/λ=4 时,最大相位差约 252525 rad,约 8π8\pi8π)。但实际相位测量只能给出 −π,π-\\pi, \\pi−π,π 内的值,所以需要卷绕。wrapToPi 将任意角度映射到 −π,π-\\pi, \\pi−π,π。这正是干涉仪模糊问题的数学根源。
4.3 解模糊算法的四步逻辑
matlab
theta_coarse = asin(phi1_meas / (2 * pi * d1_lam));
phi2_pred = 2 * pi * d2_lam * sin(theta_coarse);
k_est = round((phi2_pred - phi2_meas) / (2 * pi));
phi2_unamb = phi2_meas + 2 * pi * k_est;
theta_fine = asin(phi2_unamb / (2 * pi * d2_lam));
每一步都有明确的物理意义:
- 短基线粗估计 :d1/λ=0.5d_1/\lambda = 0.5d1/λ=0.5 保证无模糊,但精度低。
- 预测长基线相位差 :用粗估计的 θ\thetaθ 代入长基线的相位公式。
- 计算模糊整数 :预测值与测量值之差除以 2π2\pi2π,四舍五入得到整数 kkk。
- 解模糊并精估计 :将 2πk2\pi k2πk 加回测量值,再用长基线公式得到高精度角度。
4.4 蒙特卡洛中的相位差估计
matlab
R = sum(y1 .* conj(y2), 1);
phi_est = angle(R);
这是互相关相位差估计 :将通道1与通道2的共轭相乘,求和后取相位。等价于最大似然相位差估计。在低信噪比下,angle(R) 的噪声较大,导致角度估计误差上升,但整体趋势严格遵循 CRLB。
4.5 CRLB 公式在代码中的体现
matlab
crlb_ifm_mc(idx_snr) = rad2deg(1 / (2*pi*d_lam*cos(theta_true_rad) * sqrt(2*M*snr)));
这行代码直接翻译了公式:
σθ=12πdλcosθ⋅2Mξ\sigma_\theta = \frac{1}{2\pi \frac{d}{\lambda} \cos\theta \cdot \sqrt{2M\xi}}σθ=2πλdcosθ⋅2Mξ 1
注意 cosθ\cos\thetacosθ 因子:当 θ\thetaθ 接近 ±90°\pm 90°±90° 时,cosθ→0\cos\theta \to 0cosθ→0,CRLB 趋于无穷------这解释了为什么干涉仪在正对法线方向精度最高,在端射方向精度最差。
五、运行结果解读
运行代码后,你将看到:
图1(响应方向图) :d/λ=0.5d/\lambda = 0.5d/λ=0.5 时主瓣宽、无旁瓣;d/λ=4d/\lambda = 4d/λ=4 时主瓣极窄,但出现多个旁瓣。基线越长,角度分辨率越高,但模糊越多。
图2(相位差卷绕) :d/λ=0.5d/\lambda = 0.5d/λ=0.5 时相位差始终在 −π,π-\\pi, \\pi−π,π 内,无卷绕;d/λ=4d/\lambda = 4d/λ=4 时相位差在 θ≈±7°\theta \approx \pm 7°θ≈±7° 处就已超过 π\piπ,发生多次卷绕。
图3(角度灵敏度) :灵敏度 ∣dΔϕ/dθ∣|d\Delta\phi/d\theta|∣dΔϕ/dθ∣ 正比于 d/λd/\lambdad/λ,且随 θ\thetaθ 接近 90°90°90° 而下降。长基线在法线附近灵敏度极高。
图4(解模糊) :蓝色点表示所有候选解(不同 kkk 对应的角度),红色三角是算法选中的正确解。短基线粗估计将搜索范围缩小到正确候选解附近,round 操作选中了正确的 kkk。
图5(精度对比) :长基线(红线)的 CRLB 比短基线(蓝线)低了近一个数量级,但注意这是在已解模糊的前提下。
图6(干涉仪 vs Watson-Watt) :在相同 MMM 和 SNR 下,干涉仪(d/λ=0.5d/\lambda=0.5d/λ=0.5)比 Watson-Watt 精度高约 10 dB (即误差小约 3 倍)。如果基线更长(如 d/λ=4d/\lambda=4d/λ=4),优势可达 30 dB 以上------这就是为什么现代 ESM 系统几乎都采用干涉仪。
蒙特卡洛图:RMSE 曲线紧密贴合 CRLB,验证了互相关相位差估计器是渐进有效的。
六、原书代码对照与延伸思考
- 原书对应 :
ch7_drawFigures中的图7.12(干涉仪方向图)、图7.14(干涉仪示例,由ex7_1~ex7_4生成)。原书还包含了单脉冲测向(图7.15b、7.16),其原理与干涉仪类似,但利用和差波束的比值,而不是相位差。 - 解模糊的实用技巧 :实际系统中,短基线可能仍存在少量噪声导致的错误解模糊。工程上常用多基线冗余(如三个以上基线)做投票或最小二乘,提高解模糊的鲁棒性。
- 2D 测向:本代码只演示了1D(方位角)。实际系统中,干涉仪通常排列成L形或圆形阵列,同时估计方位角和俯仰角。这将在第09篇(阵列信号处理)中详细展开。
下一篇预告(第07篇):多普勒测向
除了幅度和相位,还有一种完全不同的测向维度:频率 。当接收机(或辐射源)运动时,多普勒频移随来波方向的变化规律可以被用来测向------这就是多普勒测向(Doppler DF)。下篇将用原书第7章的代码,解析旋转天线/运动平台如何通过多普勒频率曲线反推方位角,并推导其 CRLB。敬请期待!