3. 常规波束形成(CBF)方向图绘制
任务说明
本案例实现常规波束形成器(Conventional Beamforming, CBF),针对均匀线阵(ULA),绘制不同阵元数 \(N\) 与阵元间距 \(d\)(以波长 \(\lambda\) 归一化)下的波束方向图。通过方向图主瓣宽度与栅瓣出现条件,直观验证阵列设计参数对空间滤波性能的影响。
核心原理与实现
均匀线阵的导向矢量为 \(\mathbf{a}(\theta) = [1, e^{j2\pi d\cos\theta/\lambda}, \ldots, e^{j2\pi (N-1)d\cos\theta/\lambda}]^T\)。常规波束形成器对各阵元接收信号进行相位补偿后同相叠加,其方向图(阵列响应)为:
\[ B(\theta) = \left| \mathbf{w}^H \mathbf{a}(\theta) \right|, \quad \mathbf{w} = \mathbf{a}(\theta_0) \]
其中 \(\theta_0\) 为波束指向角。本实现中令 \(\theta_0 = 90^\circ\)(阵列法线方向),扫描角度范围为 \(0^\circ \sim 180^\circ\)(端射方向到端射方向)。代码直接计算不同参数组合下的方向图并绘制对比曲线。
代码实现
import numpy as np
import matplotlib.pyplot as plt
def cbf_ula_pattern(N, d_over_lambda, theta0_deg=90.0):
"""
计算均匀线阵常规波束形成方向图(线性幅度)
参数:
N: 阵元数量
d_over_lambda: 阵元间距与波长之比 d/λ
theta0_deg: 波束指向角(度),默认90°(法线方向)
返回:
theta_deg: 扫描角度数组 (0~180度)
pattern_lin: 归一化方向图线性幅度 (最大值=1)
"""
theta_deg = np.linspace(0, 180, 1801) # 0.1°步进
theta_rad = np.deg2rad(theta_deg)
theta0_rad = np.deg2rad(theta0_deg)
# 阵元位置(以波长为单位)
positions = np.arange(N) * d_over_lambda
# 导向矢量矩阵: shape (N, len(theta))
# a_n(theta) = exp(j*2*pi*position_n*cos(theta))
steering = np.exp(1j * 2 * np.pi * np.outer(positions, np.cos(theta_rad)))
# 波束形成权重: 指向theta0的导向矢量
w = np.exp(1j * 2 * np.pi * positions * np.cos(theta0_rad))
# 阵列响应: w^H * a(theta)
response = np.conj(w) @ steering # 复数内积
pattern_lin = np.abs(response) / N # 归一化到最大值为1
return theta_deg, pattern_lin
# ===== 参数设置 =====
configs = [
{'N': 8, 'd': 0.5, 'label': 'N=8, d=0.5λ'},
{'N': 16, 'd': 0.5, 'label': 'N=16, d=0.5λ'},
{'N': 8, 'd': 1.0, 'label': 'N=8, d=1.0λ'},
]
# ===== 绘制方向图 =====
plt.figure(figsize=(10, 6))
for cfg in configs:
theta, pat = cbf_ula_pattern(cfg['N'], cfg['d'])
# 转换为dB,限制动态范围
pat_db = 20 * np.log10(pat + 1e-12)
pat_db = np.clip(pat_db, -60, 0)
plt.plot(theta, pat_db, lw=1.8, label=cfg['label'])
plt.xlabel('扫描角度 θ (度)', fontsize=12)
plt.ylabel('归一化幅度 (dB)', fontsize=12)
plt.title('常规波束形成方向图对比 (波束指向90°)', fontsize=14)
plt.ylim(-60, 5)
plt.xlim(0, 180)
plt.grid(True, alpha=0.3)
plt.legend(fontsize=11)
plt.tight_layout()
plt.savefig('cbf_patterns.png', dpi=150)
plt.show()
# ===== 验证:打印主瓣宽度与栅瓣位置 =====
print("=== 参数验证 ===")
for cfg in configs:
theta, pat = cbf_ula_pattern(cfg['N'], cfg['d'])
# 找到主瓣3dB宽度(在90°附近)
mainlobe = pat > 0.707 # -3dB点
# 从90°向两侧搜索
idx_center = np.argmin(np.abs(theta - 90))
left_idx = idx_center
while left_idx > 0 and pat[left_idx] > 0.707:
left_idx -= 1
right_idx = idx_center
while right_idx < len(theta)-1 and pat[right_idx] > 0.707:
right_idx += 1
bw_deg = theta[right_idx] - theta[left_idx]
# 检测栅瓣(除主瓣外幅度>0.5的峰值)
grating = []
for i in range(1, len(theta)-1):
if pat[i] > 0.5 and pat[i] > pat[i-1] and pat[i] > pat[i+1]:
if abs(theta[i] - 90) > 5: # 排除主瓣
grating.append(theta[i])
print(f"{cfg['label']}: 3dB主瓣宽度≈{bw_deg:.1f}°, 栅瓣数量={len(grating)}")
if grating:
print(f" 栅瓣位置: {[f'{g:.0f}°' for g in grating]}")
运行与验证
运行方式:将代码保存为 cbf_pattern.py,在已安装 numpy 和 matplotlib 的Python环境中执行 python cbf_pattern.py。
预期输出与判定标准:
- 程序生成
cbf_patterns.png,包含三条方向图曲线,波束指向均为90°。 - 观察曲线:N=16的曲线主瓣明显窄于N=8(相同d=0.5λ时);d=1.0λ的曲线在0°和180°附近出现与主瓣等高的栅瓣。
- 控制台打印的3dB主瓣宽度应满足:N=16约为N=8的一半(理论值约5.1° vs 10.2°);d=1.0λ时栅瓣数量为2(位于0°和180°)。
- 若打印的栅瓣数量与理论一致且主瓣宽度随N增大而减半,则验证通过。
判定标准:方向图中d=1.0λ曲线在端射方向出现完整栅瓣(幅度接近0dB),且N=16主瓣宽度约为N=8的一半,即证明CBF实现正确,参数影响符合阵列信号处理理论。