
在语音通信、雷达回波、水声探测这些场景里我们经常要面对同一个问题目标信号就藏在某个方向周围却满是干扰和噪声。拿单个麦克风或单根天线去接收目标可能完全被底噪淹没但如果换成一排麦克风或者一组天线把每个通道的信号按时间对齐后再加起来目标方向上的信号会越加越强其他方向的干扰却因为相位对不齐而相互抵消。这就是常规波束形成的基本思路也是我接触阵列信号处理时觉得最朴素又实用的一招。时域波束形成和频域波束形成正是这套思路的两种主流实现形态。这篇文章我把两者的原理、实现、算例和工程坑一次说透适合刚接触阵列信号处理的同学也适合已经写了代码但想回头补理论的人。1. 一个传感器搞不定的事一排传感器就能搞定波束形成在解决什么问题1.1 从到达时间差说起波束形成的物理基础其实特别简单就是声波或电磁波从一个方向传到不同位置的传感器时存在一个稳定的到达时间差。想象一下你在一个空旷的房间里拍手站在不同位置的两个麦克风收到同一个拍手声声音到达两个麦克风的时刻会有微小的差别这个差别由声源方向和麦克风之间的距离共同决定。假设有一个由M个传感器组成的均匀线阵阵元间距为d一个远场平面波以角度θ入射θ定义为与阵列法线的夹角。那么相邻两个阵元之间的传播时延是τ d·sinθ / c其中c是介质中的传播速度空气中声速约为343 m/s电磁波则为光速。这个公式是整个波束成形的基石。时域波束形成的全部操作本质上就是把每个阵元接收到的信号按照这个时延差值进行补偿让目标方向来的信号在时间轴上对齐。对齐之后再做加权求和带来的效果是目标方向的信号同相叠加幅度近似变成单通道信号的M倍功率提升M²倍而其他方向的信号因为到达各阵元的时间差和目标方向不同补偿后并没有真正对齐叠加时会发生相位干涉大部分被抵消。这就是波束形成能形成空间指向性的根本原因。1.2 远场与近场什么时候能按平面波算上面用到了远场平面波这个假设。实际工程里这取决于声源到阵列的距离r、阵列孔径D和信号波长λ之间的关系。工程上常用的远场判据是r 2D² / λ满足这个条件时波前可以近似看成平面波到达角θ就可以唯一描述信号来向不需要关心距离。否则就必须用球面波模型每个阵元到声源的距离需要单独计算波束形成还要考虑距离维的聚焦那就变成近场聚焦波束形成或者声成像的问题了。举个例子一个8阵元、阵元间距5cm的线性阵列孔径D约0.35m。如果关心4kHz以下的声音对应波长λ约0.086m那么远场距离是2×0.35²/0.086大约2.85m。所以声源在3米开外才可以放心用平面波模型如果只有1米远按远场算时延误差会带来明显的指向性偏差。很多初做麦克风阵列的人在这个问题上栽过跟头拿着远场公式处理近场语音信号结果波束指向完全不对。1.3 常规二字到底指什么常规波束形成Conventional Beamforming在学术文献里有时也叫Bartlett波束形成它对应的是另一大类自适应波束形成方法比如MVDR最小方差无失真响应和LCMV。两者的核心区别在于常规波束形成的权重完全由阵列几何和目标方向决定不依赖信号和噪声的统计特性计算简单、稳健性高自适应波束形成则会根据接收数据的协方差矩阵实时调整权重在约束目标方向增益为1的同时最小化输出功率理论上能自动在干扰方向形成零陷效果更好但依赖协方差矩阵估计的准确性指向误差、阵列幅相误差都会让性能急剧退化。所以常规波束形成虽然在复杂干扰环境下不一定最优但它是理解整个阵列信号处理的起点也是很多自适应算法的初始解和稳健备份。时域和频域只是实现这种空间滤波的两种形式下面分别展开。2. 时域波束形成延迟对齐、加权、求和一气呵成2.1 算法骨架与核心公式时域波束形成的输出式可以写成y(t) Σₘ wₘ · xₘ(t - τₘ(θ))其中m从0到M-1xₘ(t)是第m个阵元的时域信号τₘ(θ)是第m个阵元相对参考阵元在目标方向θ下需要补偿的时延wₘ是对第m个通道的幅度加权。整个流程就三步根据目标方向算出每个阵元需要的延迟把每个通道信号平移对应的延迟量再按权重累加。当所有阵元的权重取相等值wₘ1/M时这就是经典的延时求和Delay-and-Sum波束形成器也是实现最简单、鲁棒性最好的一种。它不依赖任何信号统计信息只要阵列几何标定准确指向就基本准确。时延补偿后的信号在对齐方向上的频率响应是平坦的幅度增益为1归一化后而对非对齐方向的信号来说等效于做了一次空间滤波不同频率的衰减程度不同。2.2 分数时延躲不开算一个实例时域实现的第一个麻烦就是计算出来的时延很多情况下不是采样周期的整数倍而是落在两个采样点之间。举一个具体数字。设阵元间距d5cm采样率fs8kHz目标方向θ30°声速c343m/s。相邻阵元的实际时延是τ 0.05 × sin30° / 343 0.05 × 0.5 / 343 ≈ 72.9μs而采样周期Ts 1/8000 125μs。也就是说这个时延只相当于0.583个采样间隔。第3个阵元相对第1个阵元的时延是145.8μs对应1.166个采样间隔。你没法直接通过移动整数的离散索引来精确对齐信号必须要做分数时延处理。工程上常见的分数时延实现有三种线性插值实现最简单但高频段幅度和相位误差偏大sinc插值理论上最准确用一个加窗的sinc核做卷积截断长度决定精度Farrow结构滤波器利用多项式近似时延适合实时系统系数固定后计算量可控。我自己做离线仿真时倾向用sinc插值因为numpy里一行就能完成精度好做实时嵌入式实现时则使用Farrow结构的亚采样延迟滤波器因为它的计算量不随延迟小数部分变化。2.3 权重系数不是随便给窗函数在空间域的作用时延对齐完成之后对每个阵元的幅度权重wₘ做调整直接影响波束图的旁瓣水平。均匀权重矩形窗对应的波束图主瓣最窄方向分辨力最高但第一旁瓣只比主瓣低约13.3dB如果希望抑制旁瓣可以给各阵元加上汉明窗或切比雪夫窗系数旁瓣能压到-40dB以下代价是主瓣变宽空间分辨力下降。这个权衡和时域FIR滤波器的窗函数设计几乎一模一样。经典MDRMinimum Dispersion Resolution里讨论的空间分辨率与被测距离分辨率、旁瓣抑制三者的制约关系在阵列设计时同样存在。实际项目里如果环境干扰主要来自正侧面我会优先考虑切比雪夫窗因为可以指定目标旁瓣电平如果只是做通用处理汉明窗的性价比最高。2.4 时域方案怎么落地最简单的时域波束形成器在代码里只需要几十行。下面是用Python写的delay-and-sum核心部分考虑了分数时延import numpy as np def delay_and_sum(x, theta_deg, d, fs, c343.0): x: (num_channels, num_samples) 输入信号矩阵 theta_deg: 目标方向角度(度), 0度对应阵列法线方向 d: 阵元间距(米) fs: 采样率(Hz) M, N x.shape y np.zeros(N, dtypenp.float32) theta np.deg2rad(theta_deg) for m in range(M): # 第m个阵元相对0号阵元的时延 tau_m m * d * np.sin(theta) / c delay_samples tau_m * fs # 整数部分直接平移, 小数部分用sinc插值 int_delay int(round(delay_samples)) frac_delay delay_samples - int_delay # 简易分数时延: 线性插值(演示用, 实际建议sinc/Farrow) x_shifted np.zeros(N) if int_delay N: x_shifted[int_delay:] x[m, :N - int_delay] if frac_delay 1e-6: x_shifted (1 - frac_delay) * x_shifted \ frac_delay * np.concatenate(([0.0], x_shifted[:-1])) y x_shifted return y / M实际工程中为了降低计算量通常会用一段固定长度的FIR滤波器和输入信号做卷积来实现分数时延同时还能把幅度修正一并做进去。每个阵元先用一个延时器粗对齐到最近的整数采样点再用一个短FIR做小数延迟整体就成了一个多通道的前端滤波网络。2.5 时域的天花板在哪儿时域延时求和的优点是处理延迟极低每输入一个采样点就能输出一个结果适合实时性要求极高的场景比如助听器、实时对讲设备。但它有两个明显的局限。第一权重是宽带统一的所有频率共用同一组幅度加权和同一个时延补偿。如果目标方向上有色噪声或者某个频段有强烈的窄带干扰时域方法没法针对特定频率做处理。第二时域波束图的旁瓣水平在宽带范围内不一致。由于波束宽度与频率成反比低频段波束很宽指向性弱高频段波束窄旁瓣却很乱。如果想在每个频点都独立控制响应就需要给每个阵元接一个FIR滤波器组这就是滤波求和结构Filter-and-Sum Beamformer。这种结构虽然灵活但滤波器长度一长计算量和设计复杂度都会明显上来。这也是很多人转向频域实现的原因。3. 频域波束形成相位旋转替代物理延迟3.1 频域处理的基本框架频域波束形成的基本思路是先把时域信号分帧、加窗、做FFT转换到频域在频域里对每个频点分别进行复加权再通过IFFT和重叠加法把时域信号恢复出来。整个过程相当于在每个频点上做一次窄带波束形成。为什么可以这么做因为时域里的一个时延τ在频域恰好对应一个相位旋转e^(-jωτ)。所以把第m个阵元的信号延时τₘ再求和这个操作可以直接写成在第m个通道的频域表示上乘一个复数相位因子再求和Y(f) Σₘ wₘ·Xₘ(f)·e^(-j2πfτₘ)这里的wₘ可以随频率变化这就解决了时域方法无法分频处理的问题。频域实现本质上是一个宽带子带处理方法每个频点都对应一个独立的窄带波束形成器。3.2 阵列流形向量与频域权重在频域波束形成里有个非常重要的概念叫阵列流形向量Steering Vector也叫导向矢量。对于均匀线阵在频率f、方向θ下的导向向量定义为a(θ, f) [1, e^(-j2πf·d·sinθ/c), e^(-j2πf·2d·sinθ/c), ..., e^(-j2πf·(M-1)·d·sinθ/c)]ᵀ向量里的第m个元素就是从参考阵元到第m个阵元在θ方向上的频域相移。有了这个向量常规频域波束形成的输出就可以写成Y(f) wᴴ(f)·X(f)其中w(f) a(θ, f)时就是标准的延时求和如果w(f)乘上一个与频率相关的窗函数系数就实现了分频点的旁瓣控制。用Python表达这个流程非常紧凑def freq_beamform_frame(X_frame, theta_deg, d, fs, c343.0): X_frame: (num_channels, fft_bins) 某一帧的复数频谱 返回: (fft_bins,) 频域波束形成输出 freqs np.fft.rfftfreq(X_frame.shape[1] * 2 - 2, 1 / fs) theta np.deg2rad(theta_deg) M X_frame.shape[0] Y np.zeros(len(freqs), dtypenp.complex64) for k, f in enumerate(freqs): # 构建频点k处的导向向量 a np.exp(-1j * 2 * np.pi * f * d * np.arange(M) * np.sin(theta) / c) Y[k] a.conj() X_frame[:, k] return Y注意这里对每个频点都重新算了一遍导向向量更高效的做法是先预计算好所有频点的导向向量矩阵之后只需要做复数矩阵乘法。3.3 分帧、加窗与重叠加法频域实现绕不开分帧处理。实际信号是连续流必须切成一帧一帧来做FFT处理完再拼回去。这里有两个工程要点。第一加窗。直接对时域信号截断会造成频谱泄漏通常要乘上汉宁窗或汉明窗。但加窗会破坏波形幅度所以恢复时需要用重叠加法Overlap-Add或重叠保留法Overlap-Save。为了保证信号能够完美重构窗函数必须满足COLAConstant Overlap-Add条件常见组合是50%重叠加汉宁窗。第二帧长选择。帧长影响频率分辨率和算法延迟两者矛盾。帧长N对应的频率分辨率是fs/N对应的算法延迟大约是N个采样点。如果在16kHz采样下用512点帧频率分辨率31.25Hz算法延迟32ms。对语音来说32ms尚可接受但助听器这类设备要求端到端延迟低于10ms512点帧就直接不合格了。COLA条件这个坑我第一次实现时就踩过用了50%重叠和汉宁窗按理说满足条件但我在频域里修改了各个频点的幅度后再做重叠加法因为没有用分析窗的平方根修正结果恢复出来的信号包络周期性起伏听起来像有喘息声。后来才意识到加了窗再做频域处理反变换回来之前要考虑窗口能量归一化否则幅度会偏。3.4 频域方案赢在哪里又输在哪里频域方案的最大优势是灵活性。因为每个频点独立加权你可以对低频和高频施加不同的约束也可以在频域里直接对接MVDR、GSC、后置维纳滤波等更高级的处理模块。大部分麦克风阵列语音增强算法都默认在频域实现原因就在于这种天然的模块化结构。它的劣势也有三个第一是延迟分帧处理必然引入至少一个帧长的时间缓冲对低延迟实时系统不友好第二是计算量虽然用FFT整体效率高但如果输入输出需要逐样本流式处理分帧、加窗、重叠保留这些逻辑会让系统结构变复杂第三是频域处理后如果做了非线性操作或幅度修改会导致时间波形在帧边界不连续产生所谓音乐噪声衍生出一系列抑制后处理。4. 时域和频域怎么选计算量、延迟和扩展性三维对比4.1 三组关键数字对比把两种实现放到同一张表里看取舍就会清晰很多。假设阵元数M、时域FIR长度L、FFT帧长N。维度时域延时求和频域波束形成每输出一个时域点的乘加次数M延时求和或 M×L滤波求和约 M×(NlogN N)/N ≈ M×logN算法延迟0~1个采样点至少1个帧长N个采样点分频处理能力弱需要滤波器组代价高天然支持每个频点独立加权与自适应算法衔接不直接直接对接MVDR/GSC嵌入式实现难度低纯乘加逻辑中高需要FFT缓冲管理稳健性非常稳健依赖窗函数和帧同步注意边界效应时域延时求和的计算量随阵元数线性增长频域因为有FFT在阵元数较多时计算效率优势明显。比如M8、L64时时域滤波求和每个采样点需要512次乘加频域采用256点FFT并做50%重叠时每采样点大约需要8×(256×8 256 256)/128次运算量量级也差不多上百次乘加但后续如果要做频域后处理这个优势就被摊薄了。4.2 不同应用场景的选型建议根据我自己的项目经验选型可以按下面几条来助听器、实时监听设备选时域。端到端延迟要求通常低于10ms频域一帧就超了根本没法用离线语音识别前端选频域。延迟不是关键频域方便接噪声抑制和去混响模块处理质量更高雷达和声纳系统多数选频域或者子带处理因为要同时处理很大的带宽而且数据本来就是分块处理的硬件资源非常有限的单片机系统先做时域延时求和简单可靠一根筋不弯需要自适应抗干扰的复杂场景直接用频域框架因为MVDR、LCMV这些方法都是基于协方差矩阵的协方差矩阵在频域里逐频点估计非常自然。4.3 混合与扩展思路实际系统未必二选一。我见过不少工程实现是混合结构先做时域的粗对齐和波束形成得到一路增强信号再做频域后置处理做噪声估计和频谱修正。这种方式兼顾了低延迟和灵活性。另一种常见的扩展是子带波束形成。把信号用分析滤波器组切成多个子带每个子带内部仍然用频域或者窄带波束形成子带之间可以独立调整。它的好处是每个子带的采样率降低后续处理计算量下降同时在每个子带内可以自由控制时延精度。Downsampling之后处理的延迟也能控制在几十个采样点内是比较均衡的方案。5. 工程落地中的坑从仿真到实机我踩过的那些细节5.1 阵元间距选择与空间混叠波束形成有个和数字信号处理里的采样定理非常相似的概念空间采样定理。阵元间距过大会导致不同方向的空间频率混淆出现栅瓣Grating Lobe。约束条件是d ≤ λ_min / 2其中λ_min是工作频段最高频率对应的波长。如果设计目标是在8kHz采样下处理4kHz以下音频λ_min 343 / 4000 0.08575m阵元间距d就不能超过4.29cm取3.5~4cm比较合理如果关心到8kHzλ_min变成4.3cmd必须控制在2.1cm以内。我第一次做16kHz采样的麦克风阵列时没有仔细算这个直接用了5cm间距结果高频方向图出现明显的栅瓣6kHz以上的信号从侧面来时会形成错误的指向波束完全失真。后来换成4cm间距才解决了问题。阵元间距小会降低低频指向性但至少不会出现致命的空间混叠。5.2 分数时延实现的精度问题分数时延滤波器看似不起眼实际对波束形成质量影响很大。如果只用线性插值在信号频率接近奈奎斯特频率时会产生明显的幅度纹波和相位失真。这些误差叠加在波束形成输出上会让目标方向的频响不再平坦尤其是宽带语音信号听起来发闷。用sinc插值时截断长度直接影响精度。理论上sinc插值需要无限长实际用64个抽头就足够把带内误差压到很低。嵌入式系统上用Farrow结构更合适比如3阶或5阶多项式近似采样率16kHz下精度已经足够。关键是不要图省事直接用最近邻或线性插值否则后期排查问题时会很痛苦。5.3 频域边界效应与周期性噪声频域波束形成最常见的两个问题都出在分帧环节。一个是不满足COLA条件造成的重构失真。如果把帧移设为40%或者60%汉宁窗不再满足重叠加法无损重构条件恢复出来的时域信号会出现周期性起伏。解决方法是严格使用50%重叠加汉宁窗或者按窗口平方和归一化每个输出点。另一个是频域加权后没有对窗口做补偿。因为输入信号加过窗频域幅度已经偏离真实值输出再逆变换回来后要注意除以窗口的均值增益。我实际测试过忘记这一步会让输出电平偏低约4~6dB虽然不影响信噪比但会影响后续自动增益控制和音量归一化。5.4 指向误差和阵列校准问题常规波束形成对目标方向的指向精度有一定容差但是这个容差随阵元数和频率变化。阵元越多、孔径越大、频率越高主瓣越窄指向误差导致的增益损失越明显。假设目标方向标定误差为2°一个8阵元、孔径28cm的阵列在4kHz时的3dB主瓣宽度大约十几度2°误差影响还小但如果是32个阵元的大孔径阵列主瓣只有几度宽2°误差能让目标信号衰减好几个dB。我建议实际系统里一定要做阵列校准。先用标准声源从已知方向发声实测各通道的幅度和相位响应将测量结果补偿到权重里。方法很简单采集一段远场正弦扫频信号对每个阵元做FFT得到实际幅相响应然后用这些实测值除以理论导向向量得到修正系数。用校准后的系数再算波束权重效果立竿见影。5.5 一套验证流程建议最后给一套我日常调试的验证流程基本能覆盖从算法正确性到工程实现的常见问题。第一步仿真波段验证指向性。用程序生成一个远场平面波信号构造几个不同方向的窄带源用理想参数跑一遍时域和频域波束形成观察输出信号幅度是否和理论一致。这一步如果都过不了说明基础公式或代码逻辑有问题不要急着上硬件。第二步噪声场仿真测增益。使用扩散噪声场模型比如球形各向同性噪声叠加目标信号分别用两种实现处理统计输出信噪比提升量。扩散场下延时求和的期望增益约等于√M如果你的实测结果明显低于这个值大概率是分数时延或指向角度算错了。第三步实测信号验证。用真实阵列录制目标声源和干扰声源从不同角度测试重点检查高频段是否有栅瓣、频域处理后是否有帧边界噪声、延迟是否符合预期。一旦发现异常优先检查5.1到5.4那几个环节。把这套流程跑通之后你对时域波束形成和频域波束形成的理解就不再停留在概念层面了。就我个人经验来说最好先亲手写一遍时域延时求和把阵列几何和分数时延调通再转到频域实现建立延时等于相位旋转这个直觉。做射频、声学还是水声系统不过是参数不同底层的思路完全一致。即使以后要上MVDR、GSC这些自适应方法常规波束形成这套基本功也能保证你面对工程问题时心里有底。