2. 均匀线性阵列的常规波束形成(CBF)
任务说明
本案例使用8元均匀线性阵列(ULA),阵元间距为半波长,接收一个远场窄带信号。目标是通过常规波束形成(CBF)在−90°~90°范围内扫描,估计信号到达方向(DOA),并分析主瓣波束宽度与扫描角度的关系。
信号模型与CBF原理
设阵元数为M=8,阵元间距d=λ/2,信号波长为λ,入射角为θ。第m个阵元接收信号为:
xm(t) = s(t)·ej·2π·m·d·sinθ/λ + nm(t)
其中s(t)为信号复包络,nm(t)为噪声。CBF通过对各阵元施加相位补偿并求和来形成波束,扫描角度θscan对应的导向矢量为:
a(θscan) = [1, e−j·2π·d·sinθscan/λ, …, e−j·2π·(M−1)·d·sinθscan/λ]T
空间谱输出为P(θscan) = |aH(θscan)·x|²,其中x为某一快拍下的阵列接收向量。峰值位置即为DOA估计值。
代码实现
import numpy as np
import matplotlib.pyplot as plt
# 参数设置
M = 8 # 阵元数
d_lambda = 0.5 # 阵元间距/波长 = 0.5
theta_true = 30.0 # 真实信号到达角(度)
SNR_dB = 10 # 信噪比(dB)
N_snap = 200 # 快拍数
# 生成阵列流形矩阵(扫描角度范围)
theta_scan = np.linspace(-90, 90, 1801) # 扫描角度
theta_rad = np.deg2rad(theta_scan)
# 导向矢量矩阵 A: (M, len(theta_scan))
A = np.exp(-1j * 2 * np.pi * d_lambda * np.arange(M)[:, None] * np.sin(theta_rad)[None, :])
# 生成信号(真实方向)
theta_true_rad = np.deg2rad(theta_true)
a_true = np.exp(-1j * 2 * np.pi * d_lambda * np.arange(M) * np.sin(theta_true_rad))
s = np.exp(1j * 2 * np.pi * 0.1 * np.arange(N_snap)) # 信号复包络
noise = (np.random.randn(M, N_snap) + 1j * np.random.randn(M, N_snap)) / np.sqrt(2)
signal_power = np.mean(np.abs(s)**2)
noise_power = signal_power / (10**(SNR_dB/10))
x = a_true[:, None] * s[None, :] + np.sqrt(noise_power) * noise
# 常规波束形成空间谱(使用所有快拍平均)
R = x @ x.conj().T / N_snap # 样本协方差矩阵
P = np.zeros(len(theta_scan))
for i in range(len(theta_scan)):
a = A[:, i]
P[i] = np.real(a.conj() @ R @ a)
# 归一化并转换为dB
P_dB = 10 * np.log10(P / np.max(P))
# DOA估计
idx_peak = np.argmax(P_dB)
theta_est = theta_scan[idx_peak]
# 计算3dB波束宽度(在主瓣两侧找下降3dB的点)
peak_val = P_dB[idx_peak]
# 在主瓣范围内找左右-3dB交叉点
left_idx = idx_peak
while left_idx > 0 and P_dB[left_idx] > peak_val - 3:
left_idx -= 1
right_idx = idx_peak
while right_idx < len(theta_scan)-1 and P_dB[right_idx] > peak_val - 3:
right_idx += 1
beamwidth_3dB = theta_scan[right_idx] - theta_scan[left_idx]
# 输出结果
print(f"真实DOA: {theta_true}°")
print(f"CBF估计DOA: {theta_est:.2f}°")
print(f"估计误差: {abs(theta_est - theta_true):.2f}°")
print(f"3dB波束宽度: {beamwidth_3dB:.2f}°")
# 绘制空间谱
plt.figure(figsize=(10, 5))
plt.plot(theta_scan, P_dB, 'b-', linewidth=1.5)
plt.axvline(x=theta_true, color='r', linestyle='--', label=f'真实DOA={theta_true}°')
plt.axvline(x=theta_est, color='g', linestyle='-.', label=f'估计DOA={theta_est:.1f}°')
plt.axhline(y=-3, color='gray', linestyle=':', alpha=0.7)
plt.xlabel('扫描角度 (度)')
plt.ylabel('归一化功率 (dB)')
plt.title('均匀线性阵列CBF空间谱')
plt.legend()
plt.grid(alpha=0.3)
plt.ylim(-40, 1)
plt.savefig('cbf_spectrum.png', dpi=150)
plt.show()
波束宽度理论分析
均匀线性阵列在扫描角θ0处的3dB波束宽度近似为:
BW3dB ≈ 0.886·λ / (M·d·cosθ0)(弧度)
当d=λ/2时,BW3dB ≈ 101.5° / (M·cosθ0)。可见波束宽度随扫描角增大而变宽,在阵列法线方向(θ=0°)最窄。本案例中M=8,θ=30°时理论波束宽度约为101.5/(8·cos30°)≈14.65°。
验证方法
运行上述代码,观察输出结果与空间谱图。判定标准:
- 估计DOA与真实DOA(30°)误差小于1°;
- 空间谱在30°附近出现明显峰值,且峰值高于旁瓣至少10dB;
- 实测3dB波束宽度与理论值14.65°偏差在±2°以内。
运行与结果判定
执行代码后,终端将打印DOA估计值与3dB波束宽度。同时生成空间谱图,图中蓝色曲线在30°附近出现主峰。若估计误差小于1°且波束宽度接近理论值,则案例验证通过。可修改theta_true为0°、45°、60°等角度重复运行,观察波束宽度随扫描角增大而变宽的趋势,验证理论公式的正确性。