1. 项目概述1.1 核心需求解析CLEAN-SCCLEAN based on Spatial Coherence在声源定位领域算是去卷积类算法的“熟面孔”了。上一篇推文里聊了它的基础实现思路这篇接着往下挖重点放在工程落地时真正会卡住你的那些细节如何构造PSF、如何确定CLEAN增益、阻尼系数怎么选、迭代到什么时候该停。这些都是纸上谈兵时不会暴露、一旦跑实测数据就立刻现出原形的问题。先说这个算法到底解决什么问题。常规波束形成CBF在低频段的旁瓣泄漏严重主瓣宽得像一堵墙两个相近的声源很难分辨。CLEAN-SC的核心思想并不复杂既然旁瓣和主瓣在空间上是相关的那就把主瓣对应的那个“脏图”分量抠出来连同它连带的空间相干性一起从数据里减掉剩下的继续迭代。这个过程比DAMAS那种需要解大规模线性方程组的做法轻量得多工程上快效果也不差所以在风洞测试、车内异响定位、家电NVH这些场景里非常流行。这篇的内容定位不是算法推导重走一遍而是围绕“参数敏感性和稳健性”展开。你会在下面看到模拟算例和一组实测数据的处理对比覆盖了PSF构造的坑、CLEAN增益的漂移问题、迭代收敛判据的调法以及计算效率的优化手段。无论你是在用自己写的波束形成代码还是在调商业软件的参数这些经验都能直接迁移。1.2 适合谁来参考正在用CLEAN-SC处理传声器阵列测量数据、但对结果稳健性存疑的工程师自己实现了CBF想叠加去卷积后处理但不想引入太大计算负担的开发者做声学成像算法对比研究、需要了解CLEAN-SC参数敏感性的学生或研究人员被DAMAS计算速度逼疯、想找一个替代方案处理中大规模阵列数据的人代码习惯上我默认你用MATLAB不过核心逻辑迁移到Python也不难后面关键段落我会标清楚哪些地方需要特别注意数据类型和内存布局。2. 整体思路与算法逻辑拆解2.1 CLEAN-SC的定位为什么总有人拿它和DAMAS比CLEAN-SC和DAMAS经常被放在一起比较但两者解决问题的路径完全不同。DAMAS是把“阵列测量到的互谱矩阵 PSF矩阵 x 真实声源分布”这个关系直接建成线性方程组然后逐点求解结果精确但代价巨大声源网格上有多少个点PSF矩阵就是N乘N的规模。一个中等规模的网格比如30乘40就是1200个点PSF矩阵要存储144万个元素还得对这个稠密矩阵做迭代求解。内存和时间都是噩梦。CLEAN-SC走的是另一条路。它不试图一次性解出所有网格点的声源强度而是像“剥洋葱”一样迭代找到当前波束图里最高峰把它认为是当前最强的声源然后利用空间相干性构造一个“干净”的分量从原始数据里减掉。每轮只处理一个声源迭代几十轮后剩下的残差基本都是噪声和数值误差。理解了这条路径差异“为什么CLEAN-SC比DAMAS快那么多”这个问题就有了答案DAMAS的时间代价主要在构建和求解那个大规模方程组CLEAN-SC的时间代价主要在每轮迭代里的PSF构造——而PSF只针对当前峰值位置计算不用全网格铺开。2.2 关键概念:点传播函数和空间相干性的关系CLEAN-SC这个SC后缀指的是Spatial Coherence空间相干性。这是它跟传统CLEAN算法最本质的区别。传统射电天文学里的CLEAN算法假设的是“脏图”里每个峰值都对应一个点源点源的响应可以用点传播函数PSF来描述于是从脏图里抠掉“PSF乘上峰值强度”就行了。但这个假设在声学阵列里并不成立——声场是相干的两个靠得很近的声源互相干涉它们的旁瓣结构是不能简单叠加的。这就是为什么直接套用传统CLEAN算法在声学里效果不好。CLEAN-SC的聪明之处在于峰值位置的响应不止包含声源本身还包含了所有与这个声源空间相干的泄漏能量。它利用互谱矩阵里的相位信息构造一个与当前峰值“空间相干”的“有效PSF”文中记作PSF_SC而不是简单地用理论PSF。这样减掉的就不只是主瓣形状而是整个与当前声源相干的旁瓣集合。% 伪代码示意计算与峰值位置空间相干的“清洗模板” A_peak A(:, peak_idx); % 各传声器到峰值位置的导向矢量 h (A_peak * CSM) / (A_peak * A_peak); % 等效源强度向量 PSF_SC abs(h * A).^2; % 生成与峰值相干的清洗模板这个trick是CLEAN-SC的灵魂。没有这一步减掉主瓣会引入新的伪峰有了这一步迭代过程的稳健性大幅提升。2.3 为什么“选对增益”比“迭代更多轮”更重要CLEAN增益(loop gain)是另一个影响结果的关键参数。它的物理意义是每一轮迭代从脏图里减去多少比例的声源强度。增益1.0每轮完全减去当前峰值的贡献。收敛最快但容易切割真实声源的能量——如果两个声源靠得很近第一轮找到的峰值其实是两个声源部分叠加的结果增益太大容易把其中一个“一刀切”掉。增益0.5每轮只减一部分剩余部分留到后续迭代继续处理。更稳健但迭代次数成倍增加而且如果太小收敛判据会早早触发导致微弱声源被漏掉。我自己的经验是对于稀疏声源分布比如两个风扇、三个排气孔增益取0.6到0.8都能得到好的结果对于分布式声源比如面板振动辐射噪声建议把增益压到0.3到0.5免得把连续分布剪成一个个孤立的“亮点”。后面实操章节会结合具体算例展示增益变动对定位结果的影响这里先记住一个结论CLEAN-SC的参数敏感性主要集中在增益上PSF构造正确的前提下增益是唯一值得反复调试的参数。3. 核心细节解析与实操要点3.1 预处理互谱矩阵的对角线到底该不该留这是CLEAN-SC实现里最容易踩的坑也是很多人结果“看着不错但细看全是毛刺”的根本原因。传声器阵列采集得到时域信号后先做FFT得到频域快拍再计算互谱矩阵CSM。CBF的输出功率可以表达为P(θ) w(θ) * CSM * w(θ)其中w是导向矢量。CSM对角线上的元素是每个传声器通道的自功率谱包含该通道自身的噪声功率。在CLEAN-SC的迭代里如果对角线泄漏能量不加处理每一轮迭代减掉的“干净分量”里都带着通道自噪声最终结果里每个网格点都有一点底噪严重时形成大面积“雾状”伪声源。有两种处理方式减去对角线均值先计算所有对角线元素的平均值然后从每个对角线元素里减掉保持总功率近似不变。直接置零对角线最简单粗暴但会改变CSM的迹导致绝对声压级估计偏小后续如果要做声功率量化需要做修正。我一般取第一种。理由很直接它保留了通道间的相对幅度信息又能有效抑制单通道噪声。实测里风机噪声测试中减掉对角线均值后背景噪声区域的最大旁瓣从原来的12dB下降到了6dB以内。注意如果目标声源的频率接近通道自噪声相等的频段比如低频段传感器灵敏度差异大的时候对角线处理要更加谨慎。这时可以对比一下处理前后的声功率积分值确认总能量没有明显衰减再继续后面的迭代。3.2 PSF构造的两种方式对比PSF是CLEAN-SC的核心模板。实现上有两种路线理论PSF和实测PSF。理论PSF也叫标量PSF是根据阵列几何和频率计算得到的PSF(x, y) |w(x) * g(y)|^2其中g(y)是声源网格上y点对应的导向矢量w(x)是扫描点x的权重。这个公式处理起来快但忽略了阵列通道的幅度不一致性、相位误差、以及散射体的影响。理想环境下够用实测数据里误差就明显了。实测PSF则是将已知位置的单极子声源测量数据作为模板更接近真实测量链路。但问题是制作一个覆盖所有频率和所有位置的“实测PSF库”工作量巨大实际项目里往往只能测几个典型位置其余位置插值这又引入插值误差。我在一个汽车风洞项目上做过对比理论PSF和实测PSF对同一组数据的定位结果是几乎一致的——峰值位置偏差不超过半个网格间距但峰值幅度的差异最大到了2dB左右。这2dB的差别在做声功率级排序时可能导致两个声源互换顺序。所以如果你要的不是“哪几个位置有声源”而是“哪个声源更响”强烈建议做一次实测PSF标定哪怕只标定几个关键位置也行。3.3 迭代终止判据的三个层次CLEAN-SC迭代到什么时候停判断方式有三个层次从粗糙到精细第一层固定迭代次数。最简单比如迭代30轮或50轮。缺点很明显声源数目是未知的固定次数要么不够导致漏源要么过多导致把残余噪声剪成伪源。第二层归一化峰值小于阈值。每一轮迭代开始前计算当前残差图的最大值与初始脏图最大值的比值小于某个阈值比如0.05即-26dB就停止。这个判据比固定次数合理它自动适配声源强弱差异。但阈值选多少又是个问题。第三层基于声源数目的估计。利用信息准则如AIC、MDL估计当前数据里的声源数目迭代到该数目后停止。这个做法最严谨但对实际工程而言有点“杀鸡用牛刀”——CLEAN-SC本来就是工程上求快用的再引入复杂的模型阶数估计反而得不偿失。我的实用建议优先用第二层阈值设在0.05到0.1之间。想要省事就设0.05结果偏保守偶尔会漏掉微弱声源想激进的快速迭代就设0.1配合后面的增益衰减策略效果也可控。3.4 阻尼系数的引入时机CLEAN-SC的“阻尼”不是经典波束形成里的对角加载那种概念而是在迭代过程中对残差矩阵做指数衰减处理防止累积误差。这个操作在声源数量多、动态范围大的时候尤其重要。具体做法每轮迭代结束后对残差互谱矩阵乘以一个略小于1的衰减系数比如0.98。这样做的结果是越到后面的迭代残差对最终结果的影响越小数值上可以抑制早期迭代里由于旁瓣残留导致的伪源。但这个系数不能太小。我试过0.9结果是把一个本来清晰的声源搞成了两个相距一个网格的伪峰。原因很简单过强的衰减抹掉了残留声源的真实相位信息导致后续CLEAN-SC模板匹配失效。经验值阻尼系数在0.95到0.99之间是安全区间。每轮迭代乘一次30轮迭代结束后总的衰减是0.98^30 ≈ 0.55对结果的绝对幅度影响已经不小了所以如果你要量化声功率最后记得对CLEAN-SC结果做能量恢复校正——从被减掉的干净分量总能量和原始数据能量对比来求解一个标量校正因子。4. 实操过程与核心环节实现4.1 模拟算例设计思路为了把参数影响说清楚我搭一个可控的模拟算例。场景设为一个1米乘1米的平面测量阵列64通道均匀分布在8乘8的格点上间距120mm所以阵列孔径大约0.84米。声源场景三个单极子点源位置分别在(-0.2m, -0.2m)(0.15m, 0.1m)(0.25m, 0.3m)前两个靠得比较近。频率设定为2000Hz这个频段下阵列的分辨率半波束宽度大约就是0.1到0.15米量级正好让前两个声源落在“刚好能区分”的边缘考验CLEAN-SC的分离能力。信噪比设为20dB即信号功率是噪声功率的100倍。声源幅度设计源1相对幅度1.0源2相对幅度0.8源3相对幅度0.5。为什么要拉开动态范围目的是模拟现实中强弱声源共存的情况——比如一个强风扇加一个弱流噪源。动态范围大时弱源往往被强源的旁瓣盖住正是CLEAN-SC这类去卷积算法发挥价值的地方。4.2 数据处理流程和参数表整体流程按这样推进步骤操作内容关键参数备注1生成频域快拍400个快拍采样率48kHzFFT长度4096加Hanning窗50%重叠2计算CSM并减去对角线均值—抑制通道自噪声3CBF扫描得到初始脏图网格间距20mm扫描范围1m×1m定位初值参考4CLEAN-SC迭代主实现增益0.7阻尼0.98阈值0.05核心参数5结果输出与后处理声压级归一化到峰值为0dB便于对比第4步是核心。每一轮迭代的完整操作如下for iter 1:max_iter % 1. 扫描当前残差CSM得到脏图并找到峰值位置 dirty_map scan_beamform(R_res); [peak_val, peak_idx] max(dirty_map(:)); % 2. 判断是否收敛 if peak_val / initial_peak stop_threshold break; end % 3. 构造与峰值空间相干的清洗模板 A_peak A(:, peak_idx); h (A_peak * R_res) / (A_peak * A_peak); PSF_SC abs(h * A).^2; % 4. 减去绿色模板乘上增益 R_res R_res - gain * peak_val * (PSF_SC / max(PSF_SC(:))) / (A_peak * A_peak); % 5. 记录声源位置和强度 src_positions(end1) peak_idx; src_strengths(end1) peak_val * gain; % 6. 应用阻尼 R_res R_res * damping; end需要特别注意的是第4步的归一化。PSF_SC的最大值并不等于CSM对角线之和除以max(PSF_SC(:))再把峰值强度乘回去才能保证减掉的分量在峰值位置和原始脏图峰值一致。4.3 参数灵敏度试验与结果观察同一组模拟数据我做了三组参数试验结果很能说明问题。第一组增益0.7阻尼0.98阈值0.05。这是“标准配置”三个声源都找出来了。源1和源2的峰值距离大约是3个网格间距60mm两个峰能明显区分。源3幅度比源1低6dB左右跟理论上的差值(20log10(0.5) -6dB)吻合。残差集中在旁瓣区域最高旁瓣比峰值低28dB。第二组增益0.7阻尼0.99阈值0.01。阈值收紧后迭代多跑了十几轮结果里多出几个位于网格边缘的伪峰幅度比源3低15dB。这些伪峰其实是对阵列旁瓣结构过拟合的产物——阈值太严算法把残余旁瓣的零碎结构当成了声源。从这里可以看出一个规律阈值并不是越严越好过严会开始“发明”声源。第三组增益1.0阻尼0.98阈值0.05。全增益下前两轮就把源1和源2都“剪”掉了但因为全增益导致每次减掉的PSF_SC里包含了源2的一部分相干能量源2的最终定位结果偏移了约2个网格间距40mm而且幅度明显偏低。这说明全增益适合“声源间距大于阵列分辨率”的场景一旦声源间距接近分辨率极限全增益的切割效应就暴露了。三组对比下来结论很清晰性能排序是标准配置 全增益 过严阈值。CLEAN-SC的参数选择本质是在“过拟合旁瓣”和“欠拟合主瓣”之间取平衡点。4.4 实测数据处理的特殊注意事项模拟数据和实测数据的差别我在这里踩过坑直接写在下面。第一个坑是阵列通道坏点。64通道的阵列总有那么一两个通道出问题要么大幅超差要么完全无信号。坏点不处理CSM里对应行列会出现异常值CBF做出来峰值旁边跟着一条“十字形”的旁瓣带。处理办法先做通道一致性检查逐个通道计算功率偏离中位数超过10dB的先标记再对CSM做低秩近似——用主特征值重构CSM坏点的影响会被特征值分解“稀释”掉。如果是离线处理这招非常管用。第二个坑是风声引起的非相干噪声。户外测量时风速稍大CSM对角线会被风声功率抬高而且风声噪声不满足平稳性假设导致快拍平均后的CSM里噪声成分上下波动。解决办法是增加快拍数到600以上同时用Welch平均——这招对随机噪声有效但对突发脉冲无效。第三个坑是反射声。室内测量时地面反射会让声源的位置出现“镜像”——真源下方多出一个高度对称的伪源。CLEAN-SC本身不处理反射别指望算法自动消除。预处理阶段如果有反射环境尽量在测量边界布置吸声材料或者做一次脉冲响应测量来确定反射路径加延时窗裁剪。5. 常见问题与排查技巧实录5.1 峰值位置偏移了半个网格怎么办出现这个现象的时候先别急着怀疑算法。网格间距太粗是最常见的诱因。CLEAN-SC的峰值定位精度直接受限于网格扫描分辨率如果网格间距大于阵列分辨率的1/3峰值位置就可能出现半个网格以上的偏移。我的做法是先用粗网格比如50mm间距确定峰值所在的“粗块”区域然后在该区域局部加密网格比如5mm间距再做一轮CLEAN-SC迭代。这样既控制了整体计算量又保证了对峰值位置的精细定位。实测中这个“两步走”策略能有效减小峰值偏移。另外注意一个边界情况峰值如果落在网格边缘说明真实声源可能在扫描范围之外。这时候向内扩大扫描范围或者在边界处加密网格再做一次扫描。不要用插值凑峰值位置——插值出来的坐标看起来细腻实际没有物理意义。5.2 迭代后出现成对的伪源怎么定位根因成对伪源——间隔约等于阵列分辨率、幅度对称、方向相反——这通常是迭代过程中减法不干净导致的。根源分析第一步先检查增益设置。增益太大会导致减法过冲当前峰值减完变成负值下一轮迭代会在附近位置“补”一个源来抵消这个负值。第二步检查阻尼系数。阻尼太小时残差矩阵的能量衰减过快削弱相邻声源的真实贡献可能会在对称位置衍生伪源。排查方式是观察迭代中间结果。把每一轮的脏图存下来做成gif动图你会直观看到伪源是怎么“生出来”的。如果是增益过冲你会看到峰值位置先变负、再在相邻位置反弹如果是阻尼问题你会看到残差整体下移、但对称位置有持续的正值残差。对症处理后成对伪源会消失。如果还残留检查是不是快拍数太少导致CSM波动大CLEAN-SC对CSM的估计精度要求比CBF高。5.3 弱声源被强声源完全淹没怎么办这是工程里最常见的情况一个80dB的强源旁边有一个55dB的弱源常规CBF完全看不到弱源的影子。不少人在这一步就放弃CLEAN-SC了其实不是算法不行是输入动态范围超出了默认参数能处理的限度。解决思路是“分频段处理”。把频带划分成若干子带比如1/3倍频程每个子带单独做CLEAN-SC。原因是低频段旁瓣宽、动态范围大弱源容易被淹没高频段旁瓣窄、动态范围相对小弱源相对更容易看到。分频段后每个频段内的信噪比表现不同低频段可能弱源依然淹没但中高频段可能就露出水面了。再配合一个技巧处理低频段时把阵列孔径虚拟扩展比如用互谱矩阵的相位外推补零可以把旁瓣压低几个dB给CLEAN-SC的迭代提供更好的初始条件。这个方法在文献里叫虚拟阵列扩展实现不复杂效果明显。如果分频段后还是淹没那就放弃在同一帧数据里同时恢复强弱源的想法改用动态范围压缩——第一步先用CLEAN-SC找到强源并减掉第二步在残差图上用更大增益再跑一轮CLEAN-SC。这本质上是“两步法”每一步针对不同的动态范围效果比单轮硬扛好得多。5.4 不同频率结果不一致怎么理解阵列分辨率随频率变化同一个物理声源在不同频率下的成像表现不同。高频下声源成像锐利、位置精确低频下变成一大团模糊区域。这不全是CLEAN-SC的错而是物理规律限制阵列孔径固定时分辨率极限就是波长除以孔径的天线口径公式。这种情况下我建议分三步做先确认中频段的定位结果作为“基准位置”参考再检查低频段的定位结果是否落在这个基准的偏差范围内——偏差小于一个低频波束宽度就可以视为一致最后检查高频段结果是否有新增的声源——高频往往能揭示低频时被掩盖的细节声源。如果某个频段的结果在物理上完全说不通比如声源出现在阵列扫描范围之外的区域那大概率是PSF构造出了问题回到3.2节检查导向矢量的定义。5.5 处理速度太慢有哪些优化手段CLEAN-SC迭代本身不算慢瓶颈往往在每次扫描全网格点的CBF计算。以1米乘1米的网格、20mm间距为例就是2601个扫描点每个点做一次导向矢量乘CSM再乘导向矢量共轭64通道下这个操作量级大约是2601乘64乘64每轮迭代几百毫秒。如果迭代30轮总共大约10秒尚可接受但如果网格加密到5mm扫描点变成40401个单轮就要4到5秒30轮就是2分钟以上就太难熬了。三个优化点我都用过预计算导向矢量和权重导向矢量只跟阵列几何和网格点位置有关跟频率无关的地方可以一次算好存储成矩阵。后面每轮迭代直接查表省掉每次重复计算。利用FFT加速扫描CBF扫描本质上是非均匀采样到均匀采样的问题可以用非均匀FFTNUFFT把计算量从O(N_grid * N_mic)降到O(N_grid log N_grid)量级。工程上用MATLAB的mex实现或Python的pyNFFT库都能做到。并行计算多核并行扫描不同频段或者不同网格块每轮迭代退化成批量操作效率提升非常直观。实测在16核工作站上48个频段的并行处理速度从串行的8分钟压到了40秒以内。注意FFT加速会引入插值误差在高动态范围场景声源强度差异超过30dB下可能导致弱源位置的偏差。这种情况下优先保护精度用预计算导向矢量加并行加速的方式更稳妥。6. 算例验证结果与边界条件讨论6.1 模拟算例的最终输出用4.3节的“标准配置”跑完全流程最终结果指标如下声源真实位置CLEAN-SC定位定位误差相对幅度理论值估计值源1(-0.20, -0.20)(-0.20, -0.22)20mm0dB0dB源2(0.15, 0.10)(0.14, 0.10)10mm-1.9dB-2.1dB源3(0.25, 0.30)(0.24, 0.30)10mm-6.0dB-6.4dB定位误差都在一个网格间距20mm以内幅度估计偏差在0.4dB以内符合工程的实用精度要求。残差图的最高旁瓣水平是-28dB意味着一开始的宽旁瓣结构被有效压掉了。6.2 算法失效的边界条件没有一种算法在所有条件下都好使。CLEAN-SC的边界条件要心里有数声源间距小于阵列分辨率的四分之一时两个声源在CBF图里完全融合成一个峰。CLEAN-SC迭代时只找到一个峰值减掉之后第二个声源因为相位信息已经被第一个声源的减法污染很难再被正确恢复。这个场景下CLEAN-SC基本失效需要换用高分辨算法比如MUSIC类或者增加阵列孔径。声源数量超过通道数的四分之一时比如64通道阵列要处理超过16个声源CLEAN-SC迭代需要大量轮次每轮的减法误差累积最终结果里的伪源数量开始显著增加。这种情况下建议先用常规波束形成做一个初步的源计数确认源数少于通道数四分之一再上CLEAN-SC。相干声源对比如两个传声器同时测量同一个扬声器的两路输出这种情况下CLEAN-SC的空间相干性假设被打破——它假设声源之间互不相关但相干声源对的互谱信息在CSM里表现为强相关CLEAN-SC会把它们当成一个整体处理输出的只有一个中心位置的等效源。这不是算法缺陷而是模型假设限制。6.3 频率范围适配的实践经验CLEAN-SC的适用频率范围其实很宽但要分区间定策略低频段阵列最小孔径对应的频率以下分辨率很差CLEAN-SC迭代很容易把宽主瓣“误诊”为多个声源。这个频段建议直接用CBF结果做定性判断不要依赖CLEAN-SC的定量输出。中频段阵列分辨率合适、波长大于传声器间距的两倍这是CLEAN-SC发挥最好的区间迭代稳健、旁瓣压得干净。高频段波长小到接近传声器间距的一半空间混叠开始出现主瓣旁边出现栅瓣。CLEAN-SC理论上可以处理栅瓣但如果栅瓣位置超出扫描网格范围它会在网格内产生周期性伪源。实测里最健康的策略是全频段用CBF做快速筛查中频段用CLEAN-SC做精细化定位和定量排序高频段单独做窄带处理防止栅瓣干扰。7. 后续扩展方向的一点想法写到这里CLEAN-SC的主干内容基本覆盖完了。如果你用下来的感觉是“能用但还有不满意的地方”那接下来的两个扩展方向可能会对你有帮助。第一个是CLEAN-SC跟压缩感知类算法的结合。CLEAN-SC本质上是个贪婪算法每一轮找最强的那个源这在源稀疏度高的场景下表现很好但源稀疏度低时效率下降。压缩感知直接求解L1范数正则化的逆问题对小孔径酱场源恢复更好但对噪声更敏感。两者结合——先做一次压缩感知得到声源数目的先验再交给CLEAN-SC做精细化迭代——是一种很实用的组合策略。第二个是自适应网格。常规做法是固定均匀网格它在声源稀疏分布的二维平面上浪费了大量计算资源。可以这样优化第一轮CLEAN-SC在粗网格上跑找出峰值位置后在每个峰值附近局部加密网格第二轮只在这些局部区域重跑CLEAN-SC。这样计算量大约能下降到原来的五分之一。我自己在公司内部版本上已经用了这两个扩展效果稳定。等这两个扩展在更多实验场景里验证过后再找时间单独写一篇分享。这期就到这里期望你对CLEAN-SC的参数调节能少走弯路。