很多人第一次学波束形成,接触到的都是“给每个阵元加一个延迟,再叠加起来”这种讲法。这个讲法没有错,但它会让人忽略一个更本质的视角:波束形成的输出,本质上是对整个接收孔径上信号场的一次线性积分。搞清楚这一点,栅瓣为什么出现、窗函数为什么有用、导向矢量为什么长成那个样子,全都是顺理成章的事。这篇文章就用“线性积分”这条主线,把窄带常规波束形成的原理和 MATLAB 实现从头顺一遍,最后再聊聊实际仿真里一定会踩的几个坑。适合刚开始接触阵列信号处理、想把原理和代码对应起来的读者。1. 为什么要把波束形成理解成一次“线性积分”1.1 连续孔径上的输出方程先忘掉离散阵元,假设我们有一根长度为 L 的连续接收孔径,比如一条无限细的水听器线阵。入射信号在孔径位置 x 处的复声压是 p(x, t)。一个线性波束形成器的输出,可以写成孔径上的加权积分:[ y(t) = \int_{-L/2}^{L/2} w(x) , p(x, t) , dx ]这里的 w(x) 是孔径加权函数,也就是常说的窗函数或锥削函数。输出 y(t) 是输入场 p(x,t) 的线性泛函,而连续孔径上的组合方式就是积分。所以“线性积分”并不是一个高深说法,它就是字面意思:把孔径上每个位置接收到的信号,乘上一个权重,然后沿整个孔径加起来。为什么要关心这个连续形式?因为很多结论在连续模型下特别干净。远场平面波假设下,从 θ 方向来的信号到达孔径位置 x 时,相对参考点有一个传播时延 x sinθ / c。窄带情况下,这个时延在复包络上表现为一个相移 e^{-j k x sinθ},其中 k = 2π/λ。于是输出可以写成:[ Y(\theta) = S(\omega) \int_{-L/2}^{L/2} w(x) e^{-j k x \sin\theta} dx ]注意看这个积分:它是对空间坐标 x 做积分,而积分核是 e^{-j k x sinθ}。这和傅里叶变换的核长得一模一样,只不过变量从时间频率换成了空间角度。换句话说,波束方向图就是孔径加权函数 w(x) 在空间频率 u = sinθ 处的傅里叶变换值。这个结论值得单独拎出来记:波束形成的本质是空间傅里叶分析,而不是某种“近似的延迟叠加技巧”。1.2 离散阵元让积分退化成加权求和实际阵列不可能连续采样,只有 M 个离散阵元。数学上,相当于把连续孔径上的采样用一个梳状函数表达,积分退化成求和:[ y(t) = \sum_{m=0}^{M-1} w_m , p(x_m, t) ]如果阵元等间距 d,且以阵列中心为原点,x_m = (m - (M-1)/2)d。这时权重向量 w = [w_0, ..., w_{M-1}]^T,阵列接收数据也是向量,输出就是一个简单的内积。离散化带来了一个连续模型里不存在的限制:空间采样定理。阵元间距 d 必须不大于 λ/2,否则方向图在 u 域会出现周期重复,也就是栅瓣。这一点后面展开讲。刚到这一步,很多初学者会困惑:为什么有的地方写 y = w^H x,有的地方写 y = w^T x?因为不同教材对导向矢量的相位定义不一样。这篇文章统一采用如下约定:导向矢量 a(θ) = e^{-j k x_m sinθ},波束输出时用补偿权重 v(θ₀) = conj(a(θ₀)),输出写成 v^T x 而不是 v^H x。这个约定会在 MATLAB 代码部分再次强调,因为符号搞反是最常见的低级错误。1.3 这个视角带来的三个工程推论从“线性积分”看波束形成,至少有三个工程上经常用到的推论:第一,波束形成和傅里叶分析是同构的。所以时域信号处理里关于窗函数、旁瓣、主瓣宽度的所有经验,几乎可以原封不动搬到空间域。时域加窗降低频谱旁瓣,空间加窗降低方向图旁瓣;时域窗越宽主瓣越窄,空间阵列孔径越大主瓣越窄。第二,栅瓣就是空间域的混叠。时域采样率不够会产生频谱混叠,空间采样间隔大于 λ/2 会产生栅瓣。这两个是同一个数学现象的两张脸。第三,窄带假设是线性积分成立的边界。如果信号带宽较大,x_m 处的“相位差”不再能用单一频率的 e^{-j k x sinθ} 描述,而必须保留真实的延迟。这时单导向矢量模型崩坏,需要换成频域子带处理或真实时延波束形成。很多人把宽带信号硬套窄带模型,方向图从中间塌掉,原因就在这里。2. 窄带常规波束形成:导向矢量与方向图的来龙去脉2.1 从几何时延到导向矢量假设 M 元均匀线阵,间距 d,目标信号是频率为 f₀ 的窄带信号,从法线方向右侧 θ 角入射。以阵列中心为参考点,第 m 个阵元相对参考点的传播时延是:[ \tau_m = \frac{x_m \sin\theta}{c} ]中心频率 f₀ 对应的波数为 k = 2π/λ,窄带复包络下,阵元接收信号可以写成:[ x_m(t) = s(t) e^{-j k x_m \sin\theta} ]把所有阵元排成列向量,就得到导向矢量:[ \mathbf{a}(\theta) = \left[ e^{-j k x_0 \sin\theta}, \ e^{-j k x_1 \sin\theta}, \ \dots, \ e^{-j k x_{M-1} \sin\theta} \right]^T ]这里每个阵元相对参考点都有一个相位差。记住一个判断方法:入射角为正时,阵列右侧阵元先收到信号,所以它们的相位相对参考点是超前的;但上面公式用负指数表示滞后。两种约定都能自洽,关键是权重补偿方向必须和它配套。为了让波束指向 θ₀,我们需要给第 m 个阵元乘上一个正好抵消该相位差的权重:[ v_m = e^{+j k x_m \sin\theta_0} ]也就是 v = conj(a(θ₀))。这样当真实信号从 θ₀ 来时,每个阵元补偿后的复数信号都对齐到同一个方向,相加之后信号幅度增强 M 倍。输出写法和常见教材有点差别,我用普通转置:[ y(t) = \mathbf{v}^T \mathbf{x}(t) ]提示:如果看到别的资料写 w^H x,不要直接照抄公式,先确认它的导向矢量是 e^{j k x sinθ} 还是 e^{-j k x sinθ}。导向矢量定义方向不同,权重到底是共轭还是非共轭,结论完全不同。这块符号约定问题坑了很多初学者,MATLAB 报错或者方向图反向,多半就是这里出了问题。2.2 方向图就是空间傅里叶变换把波束输出幅度写成入射角的函数,就是方向图。把权重 v(θ₀) 和每个可能入射方向的导向矢量 a(θ) 做内积:[ F(\theta) = \frac{1}{M} \sum_{m=0}^{M-1} e^{j k x_m (\sin\theta_0 - \sin\theta)} ]令 u = sinθ,u₀ = sinθ₀,方向图变成:[ F(u) = \frac{1}{M} \sum_{m=0}^{M-1} e^{j \frac{2\pi}{\lambda} x_m (u_0 - u)} ]这正是离散孔径的空间傅里叶变换。为什么矩形窗下方向图像一个 sinc 函数的离散版本?因为均匀加权的有限长序列做傅里叶变换,本来就得到 Dirichlet 核。所以用 FFT 快速扫描方向图是完全合理的做法:把阵元坐标和角度变量都离散化,一次矩阵乘法就能算出全角度响应。这里有一个工程细节值得注意:因为方向图只和 sinθ 有关,所以角度响应的形状在 u 空间是平移不变的。主瓣宽度、旁瓣位置参考 u 空间来设计,会比直接看角度更规整。2.3 主瓣、旁瓣与增益的定量关系对 16 元半波长间距均匀线阵,矩形窗下的关键参数如下:主瓣第一零点宽度在 u 空间约为 2λ/(Md)。转成角度时会因 cosθ₀ 有拉伸,偏离法线越远波束越宽。半功率波束宽度近似为 0.886λ/(M d cosθ₀)(弧度)。法线方向、d=λ/2 时,M=16 大约对应 6.4°。第一旁瓣电平约为 -13.3 dB,这是矩形窗众所周知的性质。白噪声输入下,常规波束形成的输出 SNR 提升 10log₁₀(M) dB。原因是信号相干相加幅度增益 M,功率增益 M²;而阵元噪声是非相干的,功率相加,所以只增加 M 倍,净增益 M 倍。这些数字是判断仿真代码是否写对的“手感指标”。比如你跑完一个 16 元阵列方向图,主瓣半功率宽度不是 6 度上下,第一旁瓣不是 -13 dB 附近,那大概率代码有符号或归一化问题,而不是物理问题。3. MATLAB 实现:从单频目标信号到可复现的仿真3.1 仿真场景与参数选择我用一个非常经典的水声场景来写示例:均匀线阵,16 个阵元,中心频率 15 kHz,声速 1500 m/s,波长 0.1 m,阵元间距取半个波长 0.05 m。目标从 20° 方向入射,采样率 100 kHz,快拍数 4096。单阵元输入信噪比设为 0 dB。这样选择参数的原因:d = λ/2 是空间采样定理的临界值,既能保证无栅瓣,又能让阵列孔径尽可能大,主瓣更窄。窄带信号直接用复指数表示,仿真里不需要走完调制解调流程,原理验证最干净。16 阵元给后面加窗、误差分析留了足够自由度,方向图也足够平滑。3.2 完整仿真代码clear; close all; clc; %% 基本参数 c = 1500; % 声速 m/s f0 = 15e3; % 中心频率 Hz lambda = c / f0; d = 0.5 * lambda; % 阵元间距,取半波长避免栅瓣 M = 16; % 阵元数 theta0 = 20; % 目标方向 deg fs = 100e3; % 采样率 Hz Ns = 4096; % 快拍数 SNR_in = 0; % 单阵元输入信噪比 dB %% 阵列坐标,以阵列中心为参考点 x_m = ((0:M-1) - (M-1)/2) * d; %% 导向矢量 k = 2*pi / lambda; a_target = exp(-1i * k * x_m(:) * sind(theta0)); % M x 1 %% 生成窄带目标信号 + 独立阵列噪声 t = (0:Ns-1).' / fs; s_t = exp(1i * 2*pi*f0 * t).'; % 1 x Ns 复包络 noise_power = 10^(-SNR_in/10); noise = sqrt(noise_power/2) * (randn(M, Ns) + 1i*randn(M, Ns)); X = a_target * s_t + noise; % M x Ns 阵列接收数据 %% 常规波束形成权重 % 注意:此处权重是共轭导向矢量,输出用普通转置而不是共轭转置 w_bf = conj(a_target) / M; % M x 1 %% 波束输出 y = w_bf.' * X; % 1 x Ns %% 分别计算信号和噪声分量,看 SNR 提升 y_signal = w_bf.' * (a_target * s_t); y_noise = w_bf.' * noise; SNR_in_est = 10*log10(mean(abs(s_t).^2) / mean(mean(abs(noise).^2))); SNR_out_est = 10*log10(mean(abs(y_signal).^2) / mean(abs(y_noise).^2)); fprintf('输入SNR: %.2f dB\n', SNR_in_est); fprintf('波束形成后SNR: %.2f dB\n', SNR_out_est); fprintf('理论增益: %.2f dB\n', 10*log10(M)); %% 方向图扫描 theta_scan = -90:0.1:90; A_scan = exp(-1i * k * x_m(:) * sind(theta_scan)); % M x Ntheta F = w_bf.' * A_scan; % 1 x Ntheta F_dB = 20*log10(abs(F) / max(abs(F))); figure; plot(theta_scan, F_dB, 'LineWidth', 1.5); grid on; xlabel('角度 (deg)'); ylabel('归一化幅度 (dB)'); ylim([-40 0]); title('常规波束形成方向图');3.3 跑完代码后怎么解读结果正常运行后,方向图最大值出现在 20° 附近,幅度是 0 dB,这就是波束指向。第一旁瓣大约在 -13 dB 附近,和前面理论值吻合。SNR 输出一般会比输入高 12 dB 左右,因为 10log₁₀(16) ≈ 12.04 dB。如果这两条都对不上,先检查导向矢量符号和转置有没有搞错。我这里用w_bf.' * X而不是w_bf' * X,关键就在 MATLAB 里单引号是共轭转置。由于权重本身已经存成了共轭导向矢量,再做共轭转置会多出一个共轭,波束输出相位乱掉,方向图最大值位置会跑到负角度去。这个错误非常隐蔽,因为幅度方向图看起来仍然有个峰,很多人直到方向图“镜像”了才意识到。另外可以顺手验证一件事:把d = 0.5 * lambda改成d = 1.0 * lambda,再跑一次方向图,会看到除了 20° 主峰外,-41° 附近出现一个等高的假峰。这就是栅瓣,后面专门说它。4. 方向图之外:栅瓣、窗函数和指向误差的实战考验4.1 栅瓣:空间采样定理被违反时会发生什么栅瓣是阵列信号处理里最容易验证、也最容易理解的一个现象。方向图在 u = sinθ 空间里是周期函数,周期是 λ/d。只要 d ≤ λ/2,这个周期大于等于 2,而 u 的取值范围恰好是 [-1, 1],所以可见范围内只有一个主瓣。一旦 d > λ/2,周期小于可见范围,u 空间里相邻周期的重复峰就会漏进 [-1,1],形成栅瓣。以下表是 d=0.5λ、λ、1.5λ 三种取值下,目标从 20° 入射时出现的栅瓣角度:阵元间距栅瓣位置(u空间平移量)可见栅瓣角度0.5λ±2,超出范围无λ1 的整数倍平移-41.1°1.5λ每 0.667 平移-18.9°,-82.4°第三个例子里,-82.4° 的低掠射角栅瓣甚至比主瓣更接近端射区域,实际工程中会被当成真实目标。宽带系统尤其要注意:阵元间距设计通常按最高工作频率对应的半波长来定,如果频率范围太宽,高频端满足条件,低频端波长变大,半波长间距反而变大?其实反了,高频端波长小,按低频端设计会给高频造成栅瓣。所以正确做法是“最高频定间距”,低频端只是主瓣变宽,不会出现栅瓣。如果已经用了稀疏阵列无法改间距,最常见的补救是布阵时引入非均匀间距,破坏空间采样周期性。好处是不再有明确栅瓣,代价是平均旁瓣抬高、方向图可控性变差。这个交易要心里有数。4.2 空间窗函数:旁瓣与主瓣宽度的交易矩形窗方向图第一旁瓣 -13.3 dB,在很多干扰场景下不够用。比如 30° 处有个强干扰,它透过旁瓣进来的能量可能直接淹没目标。空间加窗和时域加窗思路完全一样:对幅度锥削,让阵列边缘的阵元贡献小、中间贡献大。代价是有效孔径变短,主瓣变宽,输出 SNR 增益也会略小于 M。常用窗的情况:窗类型第一旁瓣电平主瓣展宽系数(相对矩形窗)矩形窗-13.3 dB1.00汉宁窗-31.5 dB1.62汉明窗-42.7 dB1.52布莱克曼窗-57.6 dB1.74MATLAB 里加窗很简单,比如在生成权重时乘一个汉明窗:win = hamming(M, 'periodic').'; % 1 x M w_bf = win .* conj(a_target).'; w_bf = w_bf / sum(win); % 保持主瓣增益为 0 dB注意 MATLAB 里hamming默认返回列向量,为了维度对齐,我把它转成行向量再和conj(a_target).'做逐元素乘。sum(win)归一化是为了让主瓣峰值仍然为 0 dB。如果不做归一化,SNR 的理论增益会进一步偏离 M。实际项目里我见过不少“既要低旁瓣、又要窄主瓣、还要高 SNR”的需求,它们在物理上是互相拉扯的。加窗之前最好先量化一下:旁瓣要压到多少 dB?主瓣可以容忍变宽多少?干扰是近旁瓣还是远旁瓣?通常压旁瓣到 -30 dB 左右,对主瓣的损失还比较可控,再低就要用更复杂的优化方法而不是简单窗函数了。4.3 指向误差和阵元误差:理想模型的边界线性积分模型假设了理想均匀直线阵、平面波、窄带、阵元特性完全一致。现实中每一条都可能失配,其中最隐蔽的是指向误差和阵元幅相误差。指向误差很好理解:波束指向 θ₀,目标实际从 θ₀ + δ 来,输出幅度会落在方向图主瓣斜坡上。比如上面的 16 元阵,20° 附近半功率波束宽度约 6.8°,如果指向偏差 2°,损失大概不到 1 dB;偏差 5°,损失接近 3 dB。这个损失在低信噪比场景下可能被噪声起伏掩盖,不容易发现,但会直接吃掉积累增益。阵元误差更麻烦。阵元位置误差、幅度不一致、相位不一致都会让实际方向图偏离理论值。最典型的表现是旁瓣抬高、零陷变浅。低旁瓣设计对误差尤其敏感,你加了布莱克曼窗期望旁瓣 -50 dB,实际加工出的阵列可能只能到 -30 dB。所以阵列标校不是可有可无的事。我自己做阵列仿真有个固定习惯:先跑理想模型确认算法正确,然后立刻加一组 Monte Carlo 误差仿真,检验算法对失配的敏感度。常用误差量级是:阵元位置随机偏差 0.02λ、幅度增益误差 5%、相位误差 5°。如果方向图在这些误差下还能保住期望的旁瓣或零陷水平,这个方案才敢往后走。差了几 dB 就调算法或者调布阵,总比装到平台上再发现问题便宜得多。最后分享一个小技巧:不要只盯着方向图理论曲线看,把多次蒙特卡洛的波束输出 SNR 直方图画出来,你会很直观地看到误差对系统稳定性的影响。很多阵列算法的“理论优势”在误差面前缩水得很快,提前用仿真暴露出来,比到外场再被动解释要强得多。
很多人第一次学波束形成,接触到的都是“给每个阵元加一个延迟,再叠加起来”这种讲法。这个讲法没有错,但它会让人忽略一个更本质的视角:波束形成的输出,本质上是对整个接收孔径上信号场的一次线性积分。搞清楚这一点,栅瓣为什么出现、窗函数为什么有用、导向矢量为什么长成那个样子,全都是顺理成章的事。这篇文章就用“线性积分”这条主线,把窄带常规波束形成的原理和 MATLAB 实现从头顺一遍,最后再聊聊实际仿真里一定会踩的几个坑。适合刚开始接触阵列信号处理、想把原理和代码对应起来的读者。1. 为什么要把波束形成理解成一次“线性积分”1.1 连续孔径上的输出方程先忘掉离散阵元,假设我们有一根长度为 L 的连续接收孔径,比如一条无限细的水听器线阵。入射信号在孔径位置 x 处的复声压是 p(x, t)。一个线性波束形成器的输出,可以写成孔径上的加权积分:[ y(t) = \int_{-L/2}^{L/2} w(x) , p(x, t) , dx ]这里的 w(x) 是孔径加权函数,也就是常说的窗函数或锥削函数。输出 y(t) 是输入场 p(x,t) 的线性泛函,而连续孔径上的组合方式就是积分。所以“线性积分”并不是一个高深说法,它就是字面意思:把孔径上每个位置接收到的信号,乘上一个权重,然后沿整个孔径加起来。为什么要关心这个连续形式?因为很多结论在连续模型下特别干净。远场平面波假设下,从 θ 方向来的信号到达孔径位置 x 时,相对参考点有一个传播时延 x sinθ / c。窄带情况下,这个时延在复包络上表现为一个相移 e^{-j k x sinθ},其中 k = 2π/λ。于是输出可以写成:[ Y(\theta) = S(\omega) \int_{-L/2}^{L/2} w(x) e^{-j k x \sin\theta} dx ]注意看这个积分:它是对空间坐标 x 做积分,而积分核是 e^{-j k x sinθ}。这和傅里叶变换的核长得一模一样,只不过变量从时间频率换成了空间角度。换句话说,波束方向图就是孔径加权函数 w(x) 在空间频率 u = sinθ 处的傅里叶变换值。这个结论值得单独拎出来记:波束形成的本质是空间傅里叶分析,而不是某种“近似的延迟叠加技巧”。1.2 离散阵元让积分退化成加权求和实际阵列不可能连续采样,只有 M 个离散阵元。数学上,相当于把连续孔径上的采样用一个梳状函数表达,积分退化成求和:[ y(t) = \sum_{m=0}^{M-1} w_m , p(x_m, t) ]如果阵元等间距 d,且以阵列中心为原点,x_m = (m - (M-1)/2)d。这时权重向量 w = [w_0, ..., w_{M-1}]^T,阵列接收数据也是向量,输出就是一个简单的内积。离散化带来了一个连续模型里不存在的限制:空间采样定理。阵元间距 d 必须不大于 λ/2,否则方向图在 u 域会出现周期重复,也就是栅瓣。这一点后面展开讲。刚到这一步,很多初学者会困惑:为什么有的地方写 y = w^H x,有的地方写 y = w^T x?因为不同教材对导向矢量的相位定义不一样。这篇文章统一采用如下约定:导向矢量 a(θ) = e^{-j k x_m sinθ},波束输出时用补偿权重 v(θ₀) = conj(a(θ₀)),输出写成 v^T x 而不是 v^H x。这个约定会在 MATLAB 代码部分再次强调,因为符号搞反是最常见的低级错误。1.3 这个视角带来的三个工程推论从“线性积分”看波束形成,至少有三个工程上经常用到的推论:第一,波束形成和傅里叶分析是同构的。所以时域信号处理里关于窗函数、旁瓣、主瓣宽度的所有经验,几乎可以原封不动搬到空间域。时域加窗降低频谱旁瓣,空间加窗降低方向图旁瓣;时域窗越宽主瓣越窄,空间阵列孔径越大主瓣越窄。第二,栅瓣就是空间域的混叠。时域采样率不够会产生频谱混叠,空间采样间隔大于 λ/2 会产生栅瓣。这两个是同一个数学现象的两张脸。第三,窄带假设是线性积分成立的边界。如果信号带宽较大,x_m 处的“相位差”不再能用单一频率的 e^{-j k x sinθ} 描述,而必须保留真实的延迟。这时单导向矢量模型崩坏,需要换成频域子带处理或真实时延波束形成。很多人把宽带信号硬套窄带模型,方向图从中间塌掉,原因就在这里。2. 窄带常规波束形成:导向矢量与方向图的来龙去脉2.1 从几何时延到导向矢量假设 M 元均匀线阵,间距 d,目标信号是频率为 f₀ 的窄带信号,从法线方向右侧 θ 角入射。以阵列中心为参考点,第 m 个阵元相对参考点的传播时延是:[ \tau_m = \frac{x_m \sin\theta}{c} ]中心频率 f₀ 对应的波数为 k = 2π/λ,窄带复包络下,阵元接收信号可以写成:[ x_m(t) = s(t) e^{-j k x_m \sin\theta} ]把所有阵元排成列向量,就得到导向矢量:[ \mathbf{a}(\theta) = \left[ e^{-j k x_0 \sin\theta}, \ e^{-j k x_1 \sin\theta}, \ \dots, \ e^{-j k x_{M-1} \sin\theta} \right]^T ]这里每个阵元相对参考点都有一个相位差。记住一个判断方法:入射角为正时,阵列右侧阵元先收到信号,所以它们的相位相对参考点是超前的;但上面公式用负指数表示滞后。两种约定都能自洽,关键是权重补偿方向必须和它配套。为了让波束指向 θ₀,我们需要给第 m 个阵元乘上一个正好抵消该相位差的权重:[ v_m = e^{+j k x_m \sin\theta_0} ]也就是 v = conj(a(θ₀))。这样当真实信号从 θ₀ 来时,每个阵元补偿后的复数信号都对齐到同一个方向,相加之后信号幅度增强 M 倍。输出写法和常见教材有点差别,我用普通转置:[ y(t) = \mathbf{v}^T \mathbf{x}(t) ]提示:如果看到别的资料写 w^H x,不要直接照抄公式,先确认它的导向矢量是 e^{j k x sinθ} 还是 e^{-j k x sinθ}。导向矢量定义方向不同,权重到底是共轭还是非共轭,结论完全不同。这块符号约定问题坑了很多初学者,MATLAB 报错或者方向图反向,多半就是这里出了问题。2.2 方向图就是空间傅里叶变换把波束输出幅度写成入射角的函数,就是方向图。把权重 v(θ₀) 和每个可能入射方向的导向矢量 a(θ) 做内积:[ F(\theta) = \frac{1}{M} \sum_{m=0}^{M-1} e^{j k x_m (\sin\theta_0 - \sin\theta)} ]令 u = sinθ,u₀ = sinθ₀,方向图变成:[ F(u) = \frac{1}{M} \sum_{m=0}^{M-1} e^{j \frac{2\pi}{\lambda} x_m (u_0 - u)} ]这正是离散孔径的空间傅里叶变换。为什么矩形窗下方向图像一个 sinc 函数的离散版本?因为均匀加权的有限长序列做傅里叶变换,本来就得到 Dirichlet 核。所以用 FFT 快速扫描方向图是完全合理的做法:把阵元坐标和角度变量都离散化,一次矩阵乘法就能算出全角度响应。这里有一个工程细节值得注意:因为方向图只和 sinθ 有关,所以角度响应的形状在 u 空间是平移不变的。主瓣宽度、旁瓣位置参考 u 空间来设计,会比直接看角度更规整。2.3 主瓣、旁瓣与增益的定量关系对 16 元半波长间距均匀线阵,矩形窗下的关键参数如下:主瓣第一零点宽度在 u 空间约为 2λ/(Md)。转成角度时会因 cosθ₀ 有拉伸,偏离法线越远波束越宽。半功率波束宽度近似为 0.886λ/(M d cosθ₀)(弧度)。法线方向、d=λ/2 时,M=16 大约对应 6.4°。第一旁瓣电平约为 -13.3 dB,这是矩形窗众所周知的性质。白噪声输入下,常规波束形成的输出 SNR 提升 10log₁₀(M) dB。原因是信号相干相加幅度增益 M,功率增益 M²;而阵元噪声是非相干的,功率相加,所以只增加 M 倍,净增益 M 倍。这些数字是判断仿真代码是否写对的“手感指标”。比如你跑完一个 16 元阵列方向图,主瓣半功率宽度不是 6 度上下,第一旁瓣不是 -13 dB 附近,那大概率代码有符号或归一化问题,而不是物理问题。3. MATLAB 实现:从单频目标信号到可复现的仿真3.1 仿真场景与参数选择我用一个非常经典的水声场景来写示例:均匀线阵,16 个阵元,中心频率 15 kHz,声速 1500 m/s,波长 0.1 m,阵元间距取半个波长 0.05 m。目标从 20° 方向入射,采样率 100 kHz,快拍数 4096。单阵元输入信噪比设为 0 dB。这样选择参数的原因:d = λ/2 是空间采样定理的临界值,既能保证无栅瓣,又能让阵列孔径尽可能大,主瓣更窄。窄带信号直接用复指数表示,仿真里不需要走完调制解调流程,原理验证最干净。16 阵元给后面加窗、误差分析留了足够自由度,方向图也足够平滑。3.2 完整仿真代码clear; close all; clc; %% 基本参数 c = 1500; % 声速 m/s f0 = 15e3; % 中心频率 Hz lambda = c / f0; d = 0.5 * lambda; % 阵元间距,取半波长避免栅瓣 M = 16; % 阵元数 theta0 = 20; % 目标方向 deg fs = 100e3; % 采样率 Hz Ns = 4096; % 快拍数 SNR_in = 0; % 单阵元输入信噪比 dB %% 阵列坐标,以阵列中心为参考点 x_m = ((0:M-1) - (M-1)/2) * d; %% 导向矢量 k = 2*pi / lambda; a_target = exp(-1i * k * x_m(:) * sind(theta0)); % M x 1 %% 生成窄带目标信号 + 独立阵列噪声 t = (0:Ns-1).' / fs; s_t = exp(1i * 2*pi*f0 * t).'; % 1 x Ns 复包络 noise_power = 10^(-SNR_in/10); noise = sqrt(noise_power/2) * (randn(M, Ns) + 1i*randn(M, Ns)); X = a_target * s_t + noise; % M x Ns 阵列接收数据 %% 常规波束形成权重 % 注意:此处权重是共轭导向矢量,输出用普通转置而不是共轭转置 w_bf = conj(a_target) / M; % M x 1 %% 波束输出 y = w_bf.' * X; % 1 x Ns %% 分别计算信号和噪声分量,看 SNR 提升 y_signal = w_bf.' * (a_target * s_t); y_noise = w_bf.' * noise; SNR_in_est = 10*log10(mean(abs(s_t).^2) / mean(mean(abs(noise).^2))); SNR_out_est = 10*log10(mean(abs(y_signal).^2) / mean(abs(y_noise).^2)); fprintf('输入SNR: %.2f dB\n', SNR_in_est); fprintf('波束形成后SNR: %.2f dB\n', SNR_out_est); fprintf('理论增益: %.2f dB\n', 10*log10(M)); %% 方向图扫描 theta_scan = -90:0.1:90; A_scan = exp(-1i * k * x_m(:) * sind(theta_scan)); % M x Ntheta F = w_bf.' * A_scan; % 1 x Ntheta F_dB = 20*log10(abs(F) / max(abs(F))); figure; plot(theta_scan, F_dB, 'LineWidth', 1.5); grid on; xlabel('角度 (deg)'); ylabel('归一化幅度 (dB)'); ylim([-40 0]); title('常规波束形成方向图');3.3 跑完代码后怎么解读结果正常运行后,方向图最大值出现在 20° 附近,幅度是 0 dB,这就是波束指向。第一旁瓣大约在 -13 dB 附近,和前面理论值吻合。SNR 输出一般会比输入高 12 dB 左右,因为 10log₁₀(16) ≈ 12.04 dB。如果这两条都对不上,先检查导向矢量符号和转置有没有搞错。我这里用w_bf.' * X而不是w_bf' * X,关键就在 MATLAB 里单引号是共轭转置。由于权重本身已经存成了共轭导向矢量,再做共轭转置会多出一个共轭,波束输出相位乱掉,方向图最大值位置会跑到负角度去。这个错误非常隐蔽,因为幅度方向图看起来仍然有个峰,很多人直到方向图“镜像”了才意识到。另外可以顺手验证一件事:把d = 0.5 * lambda改成d = 1.0 * lambda,再跑一次方向图,会看到除了 20° 主峰外,-41° 附近出现一个等高的假峰。这就是栅瓣,后面专门说它。4. 方向图之外:栅瓣、窗函数和指向误差的实战考验4.1 栅瓣:空间采样定理被违反时会发生什么栅瓣是阵列信号处理里最容易验证、也最容易理解的一个现象。方向图在 u = sinθ 空间里是周期函数,周期是 λ/d。只要 d ≤ λ/2,这个周期大于等于 2,而 u 的取值范围恰好是 [-1, 1],所以可见范围内只有一个主瓣。一旦 d > λ/2,周期小于可见范围,u 空间里相邻周期的重复峰就会漏进 [-1,1],形成栅瓣。以下表是 d=0.5λ、λ、1.5λ 三种取值下,目标从 20° 入射时出现的栅瓣角度:阵元间距栅瓣位置(u空间平移量)可见栅瓣角度0.5λ±2,超出范围无λ1 的整数倍平移-41.1°1.5λ每 0.667 平移-18.9°,-82.4°第三个例子里,-82.4° 的低掠射角栅瓣甚至比主瓣更接近端射区域,实际工程中会被当成真实目标。宽带系统尤其要注意:阵元间距设计通常按最高工作频率对应的半波长来定,如果频率范围太宽,高频端满足条件,低频端波长变大,半波长间距反而变大?其实反了,高频端波长小,按低频端设计会给高频造成栅瓣。所以正确做法是“最高频定间距”,低频端只是主瓣变宽,不会出现栅瓣。如果已经用了稀疏阵列无法改间距,最常见的补救是布阵时引入非均匀间距,破坏空间采样周期性。好处是不再有明确栅瓣,代价是平均旁瓣抬高、方向图可控性变差。这个交易要心里有数。4.2 空间窗函数:旁瓣与主瓣宽度的交易矩形窗方向图第一旁瓣 -13.3 dB,在很多干扰场景下不够用。比如 30° 处有个强干扰,它透过旁瓣进来的能量可能直接淹没目标。空间加窗和时域加窗思路完全一样:对幅度锥削,让阵列边缘的阵元贡献小、中间贡献大。代价是有效孔径变短,主瓣变宽,输出 SNR 增益也会略小于 M。常用窗的情况:窗类型第一旁瓣电平主瓣展宽系数(相对矩形窗)矩形窗-13.3 dB1.00汉宁窗-31.5 dB1.62汉明窗-42.7 dB1.52布莱克曼窗-57.6 dB1.74MATLAB 里加窗很简单,比如在生成权重时乘一个汉明窗:win = hamming(M, 'periodic').'; % 1 x M w_bf = win .* conj(a_target).'; w_bf = w_bf / sum(win); % 保持主瓣增益为 0 dB注意 MATLAB 里hamming默认返回列向量,为了维度对齐,我把它转成行向量再和conj(a_target).'做逐元素乘。sum(win)归一化是为了让主瓣峰值仍然为 0 dB。如果不做归一化,SNR 的理论增益会进一步偏离 M。实际项目里我见过不少“既要低旁瓣、又要窄主瓣、还要高 SNR”的需求,它们在物理上是互相拉扯的。加窗之前最好先量化一下:旁瓣要压到多少 dB?主瓣可以容忍变宽多少?干扰是近旁瓣还是远旁瓣?通常压旁瓣到 -30 dB 左右,对主瓣的损失还比较可控,再低就要用更复杂的优化方法而不是简单窗函数了。4.3 指向误差和阵元误差:理想模型的边界线性积分模型假设了理想均匀直线阵、平面波、窄带、阵元特性完全一致。现实中每一条都可能失配,其中最隐蔽的是指向误差和阵元幅相误差。指向误差很好理解:波束指向 θ₀,目标实际从 θ₀ + δ 来,输出幅度会落在方向图主瓣斜坡上。比如上面的 16 元阵,20° 附近半功率波束宽度约 6.8°,如果指向偏差 2°,损失大概不到 1 dB;偏差 5°,损失接近 3 dB。这个损失在低信噪比场景下可能被噪声起伏掩盖,不容易发现,但会直接吃掉积累增益。阵元误差更麻烦。阵元位置误差、幅度不一致、相位不一致都会让实际方向图偏离理论值。最典型的表现是旁瓣抬高、零陷变浅。低旁瓣设计对误差尤其敏感,你加了布莱克曼窗期望旁瓣 -50 dB,实际加工出的阵列可能只能到 -30 dB。所以阵列标校不是可有可无的事。我自己做阵列仿真有个固定习惯:先跑理想模型确认算法正确,然后立刻加一组 Monte Carlo 误差仿真,检验算法对失配的敏感度。常用误差量级是:阵元位置随机偏差 0.02λ、幅度增益误差 5%、相位误差 5°。如果方向图在这些误差下还能保住期望的旁瓣或零陷水平,这个方案才敢往后走。差了几 dB 就调算法或者调布阵,总比装到平台上再发现问题便宜得多。最后分享一个小技巧:不要只盯着方向图理论曲线看,把多次蒙特卡洛的波束输出 SNR 直方图画出来,你会很直观地看到误差对系统稳定性的影响。很多阵列算法的“理论优势”在误差面前缩水得很快,提前用仿真暴露出来,比到外场再被动解释要强得多。