平面波阵列信号模拟与波束形成
1. 问题背景
阵列信号处理的核心任务:多个传感器按一定几何位置摆放,通过时延对齐实现信号同相叠加,从而增强特定方向的信号、抑制其他方向的干扰。
平面波假设:当信号源距离阵列足够远时,波前可视为平面,各阵元接收的信号仅存在时延差异,波形本身不变。
2. 阵列模型
2.1 几何关系
来波方向 θ
↘
↘ 平面波前
─────────────⊥────────────→
│ │ │ │
[0] [d] [2d] [3d] ← 阵元位置
x1 x2 x3 x4
- 阵元间距:
- 来波方向:(相对于阵列法线,0°为垂直入射)
- 第 个阵元相对于参考阵元的波程差:
2.2 时延计算
波程差转换为时间延迟:
其中 为波速(空气中约343 m/s,水中约1500 m/s)。
3. 时延实现:整数 + 小数分离
实际处理的是离散采样信号,时延需要分解为整数部分和小数部分分别处理。
3.1 整数时延:循环移位
将信号向量整体平移整数个采样点:
x_delayed = circshift(x, delay_integer);
delay_integer > 0:向后移位(延迟)delay_integer < 0:向前移位(超前)
3.2 小数时延:一阶线性插值
小数时延无法直接移位,采用相邻两采样点加权近似:
权重分配逻辑:
- 越接近0:当前采样点权重越大
- 越接近1:前一个采样点权重越大
4. 波束形成流程
原始阵列信号 → 估计来波方向 → 计算各阵元时延
↓
整数时延(circshift)
↓
小数时延(线性插值)
↓
各阵元信号时延对齐
↓
同相叠加(求和)
↓
输出增强信号
5. 关键代码结构
5.1 时延计算模块
% 时延转换为采样点数
delay_samples = ((0:N-1)*d * sin(theta)/c) * fs;
% 分离整数和小数
delay_int = round(delay_samples);
delay_frac = delay_samples - delay_int; % 范围: [-0.5, 0.5]
5.2 整数时延处理
x_int = circshift(x, delay_int(n));
5.3 小数时延处理(一阶权重)
if delay_frac(n) > 0
% 向后插值:混合当前点与前一点
x_shifted = circshift(x_int, 1);
x_out = (1-frac)*x_int + frac*x_shifted;
else
% 向前插值:混合当前点与后一点
x_shifted = circshift(x_int, -1);
x_out = (1-abs(frac))*x_int + abs(frac)*x_shifted;
end
6. 验证思路
6.1 信号对齐验证
- 输入:各阵元存在明显相位差的正弦信号
- 输出:经正确方向时延对齐后,各通道波形应完全重合
6.2 方向扫描验证
- 固定信号来波方向(如30°)
- 遍历-90°~90°扫描,对每个方向做时延对齐+求和
- 结果应在真实方向出现峰值,其他方向衰减
7. 代码与结果
7.1 完整代码
function delayed_signal = array_delay_beamforming(received_signal, doa, d, fs, c)
% ARRAY_DELAY_BEAMFORMING 对阵列接收信号进行时延波束形成
%
% 输入:
% received_signal - 阵列接收信号矩阵 [N_samples x N_elements]
% doa - 来波方向 (角度,单位度,相对于阵列法线方向)
% d - 阵元间距 (米)
% fs - 采样率 (Hz)
% c - 波速 (m/s,空气中约343m/s,水中约1500m/s)
%
% 输出:
% delayed_signal - 时延对齐后的信号 [N_samples x N_elements]
[N_samples, N_elements] = size(received_signal);
% 计算各阵元相对于参考阵元(第一个阵元)的时延
% 阵元位置: x = [0, d, 2d, ..., (N-1)d]
element_positions = -(0:N_elements-1) * d;
% 来波方向转换为弧度,并计算波程差引起的时延
% doa=0表示垂直入射(法线方向),doa=90表示端射方向
theta = doa * pi / 180;
% 时延: tau = (x * sin(theta)) / c
% 正值表示相对于参考阵元的延迟时间
delays = (element_positions * sin(theta)) / c;
% 转换为采样点数
delay_samples = delays * fs;
% 分离整数时延和小数时延
delay_integer = floor(delay_samples); % 整数时延
delay_fraction = delay_samples - delay_integer; % 小数时延 (-0.5 ~ 0.5)
% 初始化输出
delayed_signal = zeros(N_samples, N_elements);
for n = 1:N_elements
% 获取当前阵元信号
x = received_signal(:, n);
% ========== 步骤1: 整数时延 (直接循环偏移) ==========
x_int_delayed = circshift(x, delay_integer(n));
% ========== 步骤2: 小数时延 (一阶权重/线性插值) ==========
% 一阶近似: x(t - tau_frac) ≈ (1-tau_frac)*x(t) + tau_frac*x(t-1)
% 或者使用前后两个采样点加权
frac = delay_fraction(n);
if frac == 0
% 无小数时延
delayed_signal(:, n) = x_int_delayed;
else
% 一阶线性插值: 加权相邻两个采样点
% x_delayed[n] = (1-frac) * x_int[n] + frac * x_int[n-1]
% 注意: frac>0表示需要向后插值(延迟),frac<0表示向前插值(超前)
% 创建偏移一个采样的版本
x_shifted = circshift(x_int_delayed, sign(frac));
% 一阶权重相加
% |frac| 越接近0,当前采样点权重越大
% |frac| 越接近1,相邻采样点权重越大
weight_current = 1 - abs(frac);
weight_adjacent = abs(frac);
% 正小数时延: 向"过去"插值 (延迟)
% x(t-frac) ≈ (1-frac)*x(t) + frac*x(t-1)
delayed_signal(:, n) = weight_current * x_int_delayed + ...
weight_adjacent * x_shifted;
end
end
fprintf('来波方向: %.1f°\n', doa);
fprintf('阵元时延(采样点): ');
fprintf('%.3f ', delay_samples);
fprintf('\n');
end
%% ============ 使用示例 ============
clear; clc; close all;
% 参数设置
fs = 10000; % 采样率 10kHz
c = 343; % 声速 (空气中)
d = 0.05; % 阵元间距 5cm (半波长条件: d <= c/(2*f_max))
N_elements = 8; % 阵元数
N_samples = 512; % 采样点数
% 信号参数
f0 = 1000; % 信号频率 1kHz
doa_true = 30; % 真实来波方向 30度
SNR = 20; % 信噪比 dB
% 生成阵列信号
t = (0:N_samples-1)' / fs;
s = sin(2*pi*f0*t); % 原始信号
% 生成各阵元接收信号 (加入方向时延和噪声)
received_signal = zeros(N_samples, N_elements);
for n = 1:N_elements
% 计算该阵元的真实时延
tau_n = ((n-1)*d * sin(doa_true*pi/180)) / c;
delay_sample = tau_n * fs;
delay_int = round(delay_sample);
delay_frac = delay_sample - delay_int;
% 整数时延
s_delayed = circshift(s, delay_int);
% 小数时延 (一阶近似)
if delay_frac ~= 0
s_shifted = circshift(s_delayed, sign(delay_frac));
s_delayed = (1-abs(delay_frac))*s_delayed + abs(delay_frac)*s_shifted;
end
% 加噪声
noise = randn(N_samples, 1) / sqrt(10^(SNR/10));
received_signal(:, n) = s_delayed + noise;
end
% 测试不同来波方向的波束形成
doa_scan = -90:1:90; % 扫描角度
beam_output = zeros(length(doa_scan), 1);
for i = 1:length(doa_scan)
% 时延对齐
aligned_signal = array_delay_beamforming(received_signal, doa_scan(i), d, fs, c);
% 简单求和波束形成
beam_output(i) = mean(abs(sum(aligned_signal, 2)));
end
aligned_true = array_delay_beamforming(received_signal, doa_true, d, fs, c);
received_signal_plot = received_signal./max(received_signal, [], "all")/2 + (1:N_elements);
aligned_true_plot = aligned_true./max(aligned_true, [], "all")/2 + (1:N_elements);
% 绘图
figure('Position', [100 100 1200 400]);
% 原始阵列信号
subplot(1,3,1);
plot(received_signal_plot);
title('原始阵列信号 (未对齐)');
xlabel('阵元编号');
ylabel('时间采样');
% 时延对齐后的信号 (真实方向)
subplot(1,3,2);
plot(aligned_true_plot);
title(sprintf('时延对齐后 (DOA=%d°)', doa_true));
xlabel('阵元编号');
ylabel('时间采样');
% 波束形成方向图
subplot(1,3,3);
plot(doa_scan, 20*log10(beam_output/max(beam_output)), 'LineWidth', 2);
hold on;
xline(doa_true, 'r--', 'LineWidth', 1.5, 'Label', '真实方向');
xlabel('来波方向 (度)');
ylabel('归一化功率 (dB)');
title('波束形成方向图');
grid on;
xlim([-90 90]);
fprintf('\n真实来波方向: %d°\n', doa_true);
[~, max_idx] = max(beam_output);
fprintf('估计来波方向: %d°\n', doa_scan(max_idx));
7.2 运行结果
波束形成方向图
8. 常见问题
| 问题 | 原因 | 解决 |
|---|---|---|
| 对齐后仍有残余相位差 | 小数时延精度不足 | 改用更高阶插值(sinc/FIR) |
| 方向图旁瓣过高 | 阵元数太少或间距过大 | 增加阵元数,控制 |
| 峰值方向偏移 | 时延计算误差累积 | 检查角度转弧度、采样率单位 |
9. 扩展方向
- 高阶小数时延:使用sinc插值或FIR分数延迟滤波器,提高精度
- 自适应波束形成:根据干扰环境自动调整权重(MVDR/LCMV)
- 宽带信号:不同频率时延不同,需频域处理或抽头延迟线