【电子战】第06篇:干涉仪与相位差测向【含matlab代码】

第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,高精度)。

解模糊步骤

  1. 用短基线得到粗估计 θ^coarse\hat{\theta}_{\text{coarse}}θ^coarse(无模糊)。
  2. 由粗估计预测长基线的相位差:Δϕ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。
  3. 计算长基线测量的模糊整数: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)。
  4. 解模糊后的相位差:Δϕ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。
  5. 用解模糊后的相位差得到高精度估计。
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),包含:

  1. 干涉仪方向图 :不同 d/λd/\lambdad/λ 下的响应曲线
  2. 相位差与角度的关系:展示卷绕现象
  3. 双基线解模糊算法:完整的解模糊流程
  4. 蒙特卡洛仿真 :验证 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));

每一步都有明确的物理意义:

  1. 短基线粗估计 :d1/λ=0.5d_1/\lambda = 0.5d1/λ=0.5 保证无模糊,但精度低。
  2. 预测长基线相位差 :用粗估计的 θ\thetaθ 代入长基线的相位公式。
  3. 计算模糊整数 :预测值与测量值之差除以 2π2\pi2π,四舍五入得到整数 kkk。
  4. 解模糊并精估计 :将 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。敬请期待!

相关推荐
老王爱玩车2 小时前
深入理解指针2
c语言·开发语言·学习
quantdash_cc2 小时前
股票历史数据为什么比实时行情更重要?回测结果失真的根源可能就在 K 线数据
开发语言·python·数据分析·量化交易·股票数据·quantdash
光电的一只菜鸡3 小时前
为什么调整LSC会对AF产生影响
android·开发语言·kotlin
zhangjw343 小时前
第47篇:Java综合实战:电商秒杀系统(高并发场景)
java·开发语言
FOAF-lambda3 小时前
uiautomation-new 控件方位的使用
开发语言·python
OKkankan3 小时前
LangChain能力详解!:从工具调用到 LangSmith——让聊天模型具备实时交互能力!
开发语言·python·langchain
richard_yuu3 小时前
AOI 实战第五篇:c_broken 漏检严重,V4 迭代背后的权衡
开发语言·深度学习·yolo
m0_734571763 小时前
深入理解C++ 析构函数<一>基本概念
开发语言·c++
滕州市燕猫虎计算机科技工作室个体工商户4 小时前
Java面试题汇总
java·开发语言