3. 均匀直线阵导向矢量与阵列流形校验

导向矢量的数学定义与校验思路

均匀直线阵(ULA)的导向矢量描述的是:当一束远场窄带平面波以方位角 θ 入射时,各阵元相对于参考阵元所接收到的复相位差。设阵元数为 N、阵元间距为 d、波长为 λ,以第 0 号阵元为相位参考,则导向矢量可写为

a(θ, f) = [1, e^{-j2πfd·sinθ/c}, e^{-j4πfd·sinθ/c}, ..., e^{-j2π(N-1)fd·sinθ/c}]^T

其中 c 为声速,f 为信号频率,空间相位步进量 μ = 2πfd·sinθ/c。把多个来向的导向矢量按列排成矩阵,就得到阵列流形矩阵 A = [a(θ₁), a(θ₂), …, a(θ_K)]。校验的核心就是检查这个矩阵是否满足三条可独立验证的性质:

  • 共轭对称性:a(θ) 与 a(−θ) 互为共轭,即 a(−θ) = conj(a(θ)),因为 sin(−θ) = −sinθ 只改变相位符号。
  • 范数恒定性:每个导向矢量的 2-范数应恒为 √N,与来向、频率无关,这是相位项模值为 1 的直接结果。
  • 相位斜率线性:相邻阵元相位差恒为 −μ,对相位序列做线性拟合,斜率应等于 −μ,残差接近 0。

下面给出一个自洽的生成与校验函数,直接可运行(仅依赖 NumPy)。

import numpy as np

def ula_steering(N, d, f, theta_deg, c=1500.0):
    """生成 ULA 导向矢量,theta 为与阵列法线的夹角(度)"""
    theta = np.deg2rad(theta_deg)
    n = np.arange(N)
    mu = 2 * np.pi * f * d * np.sin(theta) / c
    return np.exp(-1j * mu * n)

def ula_manifold(N, d, f, thetas_deg, c=1500.0):
    """阵列流形矩阵,每列一个来向"""
    return np.column_stack([ula_steering(N, d, f, t, c) for t in thetas_deg])

def check_manifold(N, d, f, thetas_deg, c=1500.0, tol=1e-9):
    A = ula_manifold(N, d, f, thetas_deg, c)
    report = {}
    # 1) 范数
    norms = np.linalg.norm(A, axis=0)
    report['范数偏差'] = float(np.max(np.abs(norms - np.sqrt(N))))
    # 2) 共轭对称:找 +θ 与 -θ 配对
    th = np.asarray(thetas_deg, dtype=float)
    idx_pos = np.where(th > 0)[0]
    idx_neg = np.where(th < 0)[0]
    sym_err = 0.0
    for ip in idx_pos:
        match = idx_neg[np.isclose(th[idx_neg], -th[ip])]
        if match.size:
            sym_err = max(sym_err, float(np.max(np.abs(A[:, ip] - np.conj(A[:, match[0]])))))
    report['共轭对称偏差'] = sym_err
    # 3) 相位斜率
    slope_err = 0.0
    for k, t in enumerate(th):
        phase = np.unwrap(np.angle(A[:, k]))
        n = np.arange(N)
        p = np.polyfit(n, phase, 1)
        mu = 2 * np.pi * f * d * np.sin(np.deg2rad(t)) / c
        slope_err = max(slope_err, abs(p[0] + mu))
    report['相位斜率偏差'] = float(slope_err)
    report['通过'] = all(v < tol for k, v in report.items() if k != '通过')
    return report

# 示例:N=8, d=λ/2 @ 3kHz, 声速1500 → λ=0.5m, d=0.25m
print(check_manifold(8, 0.25, 3000.0, [-60, -30, 0, 30, 60]))

示例参数下,三项偏差都应落在 1e-12 量级(浮点舍入),报告“通过”为 True。若把 d 误设为 0.5 m(即 λ),在 60° 处会出现相位混叠,相位斜率拟合残差会明显增大,这正是校验要拦截的错误。

ULA 导向矢量生成与三项校验 输入参数 N = 8 阵元 d = 0.25 m (λ/2) f = 3000 Hz θ = ±60°, ±30°, 0° 导向矢量生成 μ = 2πfd·sinθ/c a[n] = exp(−j·μ·n) A = [a(θ₁)…a(θ_K)] c = 1500 m/s 三项独立校验 范数 ‖a‖₂ = √N 与θ、f无关 偏差 < 1e-9 共轭对称 a(−θ)=conj(a(θ)) sin(−θ)=−sinθ 偏差 < 1e-9 相位斜率 Δφ = −μ 线性拟合残差≈0 偏差 < 1e-9 校验通过 → 可信导向矢量 供 CBF / MVDR 等后续算法复用 偏差超限 → 检查 d 是否 > λ/2 相位混叠导致斜率拟合失败 相位序列示意(θ=30°, N=8) 阵元序号 n 相位 unwrap 后呈线性,斜率 = −μ = −π/2

校验函数的工程使用要点

把上面的 check_manifold 作为单元测试嵌入到算法流程之前,可以避免“导向矢量写错却继续做波束形成”的隐性错误。实际使用时注意三点:

  1. 配对来向要成对给出:共轭对称检查依赖 +θ 与 −θ 同时出现在来向列表中,否则该项会被跳过(偏差记为 0),造成假通过。建议固定传入 [-60,-30,0,30,60] 这类对称集合。
  2. 相位斜率用 unwrap:当 μ 接近或超过 π 时,np.angle 会卷绕,必须先 np.unwrap 再拟合,否则斜率检查会误报。
  3. 容差按浮点精度设定:纯数学构造的导向矢量偏差应在 1e-12 量级,容差取 1e-9 足够宽松;若从实测数据估计导向矢量,则需改用统计容差。
把 ula_steering 与 check_manifold 保存为独立模块,后续 CBF、MVDR 等案例直接导入,即可保证所有算法共用同一份经过校验的导向矢量定义,避免各案例间相位约定不一致。