ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于改进鲸鱼优化算法的通风吸声超表面优化设计

基于改进鲸鱼优化算法的通风吸声超表面优化设计 最近在做声学通风超表面的优化设计文章发在了Journal of Building EngineeringJBESCI二区TOP用的核心方法是自己改的增强鲸鱼优化算法EWOA搭配Matlab做了整套的优化仿真。做完这个项目回头看最有价值的反而不是某个吸声系数刷到了多少而是把“声学结构设计”和“元启发式优化”这两件事怎么打通。这篇就把整个思路、建模、Matlab代码结构、还有踩过的坑原原本本拆开聊。先说清楚一个前提这不是一篇纯声学文章也不是一篇纯算法文章它是一套“优化算法声学仿真内核工程设计约束”的组合拳。所以下面所有内容都围绕“怎么在Matlab里把EWOA跑起来让它帮我们找到既通风又能吸声的超表面结构参数”这件事展开。1. 通风和吸声有多拧巴优化问题的物理源头如果你没专门做过通风降噪可能觉得“开孔通风、顺便吸声”是一件很自然的事。但真正去仿真或者做实验就会发现这两个需求从物理上就是互斥的。超表面吸声的核心机制是共振耗能要让声波进入结构并在里面被粘滞热效应消耗掉结构表面必须允许声波“透进去”但传统微穿孔板、共振腔这类结构的吸声峰值通常靠低穿孔率换来的——孔越小、越稀声阻越高吸声效果越好。通风却要求孔越大、越密越好。你要找的是在这一块矛盾区域里最合适的折中点。传统设计靠什么调参数。孔径、孔间距、空腔深度、面板厚度每调一个就仿真一次在几个变量身上轮番试。一开始你可能觉得变量不多但组合起来就失控了一个单元如果有5个几何参数每个参数取10个水平全枚举就是10万次仿真。如果你的单次声学仿真是COMSOL级别的全波计算跑一次几分钟到十几分钟那这个枚举量就是不现实的。这还没算频带内要扫多少个频点。所以问题的物理源头可以归纳成三条多峰且不可导的目标函数吸声系数随几何参数变化不是单调函数它的峰值来自共振而共振模态会与多个几何参数耦合映射关系非常复杂。设计变量之间强耦合孔径和孔距共同决定开孔率开孔率又同时影响通风量和声阻抗你很难人为拆成“先定通风再定吸声”的两步走。单次仿真成本高必须控制评估次数。这意味着我们需要一种每次评估代价可控、且不依赖梯度信息的搜索方法。这个需求直接指向元启发式算法。遗传算法、粒子群、鲸鱼算法都属于这一类。我的选择是增强鲸鱼优化算法EWOA理由等一下说但先记住一个原则用优化算法不是为了秀算法而是为了用尽可能少的仿真次数逼近那个物理上存在的“最优结构参数”。2. EWOA不是玄学鲸鱼优化算法到底改在哪几处我见过很多论文把“改进鲸鱼算法”写得很玄仿佛换了一个初始化方式就“大大提升性能”。实际做工程不能这样自欺欺人每一项改动都得告诉自己有明确的物理意义或数学依据。先回顾原版WOA再说我改了什么。2.1 原版WOA的三种搜索动作Mirjalili在2016年提出的鲸鱼优化算法模拟的是座头鲸的泡泡网捕食策略。核心就三个位置更新机制包围猎物X(t1) X*(t) - A·D气泡网攻击螺旋更新X(t1) D·e^(bl)·cos(2πl) X*(t)随机搜索猎物X(t1) X_rand - A·D其中A是一个随迭代次数变化的关键参数A 2a·r - a这里a从2线性衰减到0。当 |A| 1算法倾向于利用当前的最优解附近进行开发当 |A| ≥ 1算法倾向于在更广的空间里随机探索。这套机制的本质是一种带精英引导的随机搜索好处是参数少、结构简单、前期收敛速度非常快。但问题也出在这里当种群快速聚拢到当前最优个体附近后多样性会迅速丧失如果搜索空间里存在多个局部极值很容易在早期就被一个不太好的峰“吸住”后期跳不出来。2.2 我改的第一处Tent混沌初始化替代随机初始化原版WOA用rand生成初始种群这在低维问题里影响不大但到5个以上设计变量的声学超表面问题里随机种子稍差一点初始种群可能扎堆在一个角落直接就影响算法最终能摸到的区域。我用Tent混沌映射生成初始位置具体是先生成一个d维的混沌序列再线性映射到变量上下界x(k1) 2·x(k), 当 0 ≤ x(k) 0.5x(k1) 2·(1 - x(k)), 当 0.5 ≤ x(k) ≤ 1对应到Matlab就是一行循环。与随机生成相比Tent序列能在解空间里更均匀地“洒”出初始种群用几乎为零的计算量提升首轮搜索覆盖面。2.3 我改的第二处收敛因子从线性衰减变成非线性衰减原版WOA里a从2线性降到0相当于前期探索和后期开发的边界非常“死板”。我把它改成二次曲线衰减a 2 * (1 - (t / T)^2)t是当前迭代数T是最大迭代数。这个改动其实是顺着算法行为逻辑走的在迭代前半段保留更大的a值让种群在探索期更激进地分布开后半段快速压下来把精力集中在最优解附近做精细搜索。2.4 我改的第三处Lévy飞行扰动和精英保留策略这是最有效的一处。在每次迭代生成新解后按一定概率我取0.2对部分个体叠加Lévy飞行扰动X_new X_best α * Lévy(β) * (X - X_best)Lévy飞行是一种重尾分布下的随机游走通俗说就是大部分时间小步移动偶尔跳一大步。这个特性非常适合逃离局部最优小步保证局部搜索精度大步帮助种群跳出当前吸引域。α取0.01β取1.5已经能明显改善后期多样性。同时我做了简单但很实用的精英保留——每一轮迭代如果最优个体变差了不让它更新直接保留上一代最优。这个策略在声学超表面这种单次评估成本不低的优化里特别有价值能防止因为某次随机扰动过大而丢掉已找到的好解。我整理过一份改动和效果的对比表做项目的时候放在论文里当论据改进点原版问题增强后行为对声学优化问题的价值Tent混沌初始化种群分布不均易漏搜关键区域初始点更均匀覆盖设计空间超表面参数空间大均匀撒点能减少初期盲目性非线性收敛因子前期探索不足后期开发过快探索与开发按曲线的节奏切换避免过早把搜索资源耗在非共振区Lévy扰动种群快速聚集多样性下降偶尔大幅跳跃搜索新区域逃脱局部极值对多峰吸声问题尤其有效精英保留最优解可能因随机性被冲掉历史最优严格不退化保证每次评估结果都有意义这里想特别说一件事EWOA这套增强并不复杂但“有效”的前提是问题本身确实需要它做的这种全局探索。声学通风超表面的适应度面就是典型的多峰函数不同腔深、孔径组合会激发不同阶次共振函数面上有很多高低不一的“山包”。这种情况下一个只会快速收敛的算法反而有害。3. 把设计问题翻译成数学问题的完整建模过程算法再好建模不合理等于白搭。很多复现这类优化项目的同学最吃亏的地方是把所有精力花在调算法参数上却忽略了目标函数和约束条件的建模质量。实际上在“优化算法能不能找到好东西”这件事上目标函数定义的影响比算法本身的影响大得多。3.1 结构模型与设计变量定义我做的是一个微穿孔板加背腔的结构形式这也是通风吸声超表面最常见的基础构型。单个单元的几何设计变量有5个面板厚度 t范围 0.3–1.0 mm微孔直径 d范围 0.3–1.5 mm孔中心距 p范围 3–10 mm背腔深度 D范围 20–100 mm蜂窝芯等效孔径参数我这里简化为单元占空比系数范围 0.5–0.95其中孔中心距p一旦确定开孔率σ就可以通过几何关系算出来。单层方形排列穿孔板的开孔率近似为σ (π/4) * (d / p)²开孔率必须大于等于设计阈值例如σ_min 12%这是通风需求的硬指标。这个变量组合不是随便挑的它覆盖了三个物理维度t和d决定孔的声阻抗特性孔径越小粘滞损耗越大p决定开孔率进而决定通风量和声阻D决定背腔共振频率。一个合理的超表面设计最终一定是在这三个维度之间求得妥协。3.2 目标函数与约束条件怎么定我用的目标函数是两个频带平均吸声系数加权之后取最大Fitness w₁·mean(α(f)), f ∈ [500, 1000] Hz w₂·mean(α(f)), f ∈ [1500, 4000] Hz之所以分两个频带加权是因为面向建筑通风场景时你关心的往往是低频段的降噪能力但也不能完全放弃中高频宽带性能。w₁和w₂按设备噪声谱调整我这次取w₁0.6w₂0.4。约束条件有三条开孔率σ ≥ σ_min保证通风量总厚度 t D ≤ 100 mm建筑隔断、窗式通风器都有厚度限制单点吸声系数 α(800Hz) ≥ 0.4避免优化结果在关键频点塌陷约束处理我强烈建议不要一上来就写罚函数。伦理上罚函数虽然简单但罚因子怎么定很头疼罚重了限制搜索、罚轻了等于没约束。针对几何约束这种可以直接映射到变量区间的直接约束变量本身。比如开孔率下限可以换算为p的上限p ≤ d·sqrt(π/(4·σ_min))这样把硬约束直接消掉算法在变量边界内随便跑都不会违反通风约束。极少数场景不能用这种方法时我才建议用带惩罚的适应度函数。3.3 仿真内核选型为什么是传递矩阵法TMM而不是普通有限元这可能是全项目最关键的一个工程决策。超表面优化需要评估数千次声学响应如果每一次评估都调用有限元全波仿真即使在COMSOL里对一个二维轴对称模型扫81个频点也需要几十秒到几分钟优化一轮几小时起步完全没法用于迭代搜索。我选择用传递矩阵法TMM作为优化主循环的快速内核。TMM把结构沿厚度方向看作串联的声学层每一层用2x2传递矩阵描述层与层之间矩阵相乘得到整个结构的表面声阻抗再换算吸声系数。对于微穿孔板加背腔结构单层微穿孔板的相对声阻抗率用Maa低速理论模型计算r (32·η·t)/(σ·ρ·c·d²) · (√(1 k²/32) √2·k·d/(32·t))x (ω·t)/(σ·c) · (1 1/√(9 k²/2) 0.85·t/d) - cot(ω·D/c)其中穿孔常数 k d·√(ω·ρ/(4·η))η是空气粘滞系数ω2πf是角频率ρ是空气密度c是声速。表面相对阻抗率z r jx后吸声系数按标准公式计算α 4r / ((1r)² x²)用Matlab写这个模型向量化扫频后单次评估所有频点只需要1-2毫秒。整个优化迭代种群规模40、迭代100次也就是4000次评估单核算下来大概也就一两分钟。做完了再用有限元对搜索到的几个“高适应度候选解”做精确验证这个组合拳既快又稳。4. Matlab实现从主循环到声学求解器的代码拆解说句实在话网上关于WOA的Matlab代码一抓一大把但大部分都是直接套标准测试函数换到真实声学问题上就废了。差别在哪差在前处理、约束处理、适应度函数和主循环之间的接口设计。这节直接看我项目里能跑的代码骨架。4.1 EWOA主循环骨架我建议把主循环、初始化、适应度函数分开写。主循环只负责任意个体的位置更新和收敛判断function [bestX, bestFit, conv] EWOA_main(problem, algo) % problem: 包含lb, ub, dim, fitness_func等字段的结构体 % algo: 种群规模N, 最大迭代T, 扰动概率p_levy等 lb problem.lb; ub problem.ub; dim problem.dim; N algo.N; T algo.T; p_levy 0.2; % Tent混沌初始化 X tent_initialization(lb, ub, N, dim); fit zeros(N, 1); for i 1:N fit(i) problem.fitness_func(X(i, :)); end [bestFit, bestIdx] max(fit); bestX X(bestIdx, :); conv zeros(T, 1); for t 1:T % 非线性收敛因子 a 2 * (1 - (t / T)^2); for i 1:N r1 rand; r2 rand; A 2 * a * r1 - a; C 2 * r2; if rand 0.5 if abs(A) 1 D abs(C * bestX - X(i, :)); X(i, :) bestX - A * D; else randIdx randi([1, N]); D abs(C * X(randIdx, :) - X(i, :)); X(i, :) X(randIdx, :) - A * D; end else D abs(bestX - X(i, :)); l -1 2 * rand; b 1; X(i, :) D * exp(b * l) * cos(2 * pi * l) bestX; end % 边界反弹/截断 X(i, :) max(min(X(i, :), ub), lb); end % Lévy飞行扰动 if rand p_levy idx randi([1, N]); levy_step levy_flight(dim, 1.5); X(idx, :) bestX 0.01 * levy_step .* (X(idx, :) - bestX); X(idx, :) max(min(X(idx, :), ub), lb); end % 精英保留 for i 1:N newFit problem.fitness_func(X(i, :)); if newFit fit(i) fit(i) newFit; else X(i, :) X(i, :); % 不更新 end end [curBest, curIdx] max(fit); if curBest bestFit bestFit curBest; bestX X(curIdx, :); end conv(t) bestFit; end end迭代里每次评估完以后先和当前这个体的历史适应度比较只有更好才接受新位置。这个“设定”很重要因为目标函数每评估一次都有计算成本不能容忍白白变差。Lévy飞行扰动那一步目标位置也控制在边界内防止跑到无意义的设计参数上去。4.2 适应度函数与声学求解器的封装适应度函数是整个优化的核心。在这类优化项目里适应度函数必须做成“纯函数”输入一个设计变量向量输出一个适应度标量中间不要依赖任何全局变量。因为你后面可能拿distributed computing并行跑种群评估全局变量会导致并行任务互相污染出错误只能是玄学。function fitness fitness_func(x) % x [t, d, p, D, gamma] t x(1); d x(2); p x(3); D x(4); gamma x(5); % 开孔率微穿孔板方形排列 sigma (pi/4) * (d / p)^2; if sigma 0.12 fitness -1e6; % 惩罚但实际中我会用区间映射尽量杜绝 return; end % 声学参数 rho 1.21; c 343; eta 1.81e-5; f 250:25:4000; omega 2 * pi * f; k d .* sqrt(omega .* rho ./ (4 * eta)); r 32 * eta * t ./ (sigma * rho * c * d^2) .* (sqrt(1 k.^2 ./ 32) sqrt(2) .* k .* d ./ (32 * t)); x_m omega .* t ./ (sigma * c) .* (1 1 ./ sqrt(9 k.^2 ./ 2) 0.85 * d ./ t) - cot(omega .* D ./ c); alpha 4 * r ./ ((1 r).^2 x_m.^2); % 加权频带平均 f_target1 (f 500) (f 1000); f_target2 (f 1500) (f 4000); fitness 0.6 * mean(alpha(f_target1)) 0.4 * mean(alpha(f_target2)); end这种代码风格非常直白没有任何花哨。但注意几个细节第一频点直接256个扫出来计算用向量化而不是循环。第二你会在r里看到k出现了k和d、频率都有关系。这其实是在直接实现Maa模型代码看起来和公式是一一对应的这样后面复查也方便。第三不希望适应度函数里出现太多魔法数字但作为一个调试骨架这个够了。4.3 算法参数配置与运行耗时评估按下面的配置这个优化任务用TMM内核在普通笔记本上就能跑完参数取值种群规模 N40最大迭代数 T100设计变量维数5频点数量151单次适应度评估耗时≈1.5 ms总评估次数4000单轮优化总耗时≈1-2 分钟这个耗时量级是做这个项目最舒服的地方。一个结构参数方案的声学响应从“建模—求解—后处理”整个周期降到毫秒级才有了后面“反复试错、反复调weights”的可能性。如果你的适应度内核换成有限元光是4000次评估就已经不可接受了。4.4 一个复现时的性能加速建议如果变量维数上到10个以上或者频点更密建议先把适应度函数向量化然后用parfor或者statset并行跑种群评估parpool(local, 4); fit zeros(N, 1); parfor i 1:N fit(i) problem.fitness_func(X(i, :)); end这里的前提是fitness_func不能依赖全局动态变量否则parfor一跑就崩或者结果错误。在这个基础上单次优化从几分钟缩到几十秒是正常的。5. 收敛曲线和吸声频谱怎么读我的实测对比结果算法好不好不能光靠嘴说。我做了三组对比原版WOA、粒子群PSO、遗传算法GA全部用同一个适应度函数和同一组随机种子。每组重复跑10次统计最优值的均值和标准差。5.1 收敛对比算法最优适应度均值标准差平均收敛迭代数WOA0.6830.03461PSO0.6540.04174GA0.6380.05583EWOA0.7210.01547EWOA在第40代左右已经基本收敛到较高水平而原版WOA在后半程几乎没有提升PSO和GA则是典型的“慢热型”。标准差这个数据最直接地反映了稳定性EWOA跑10次的最好值方差非常小意味着每次复现都能拿到接近的结果这对工程化落地很关键。5.2 优化后的吸声频谱怎么读最终优化出来的一组几何参数大概长这样参数优化值面板厚度 t0.42 mm微孔直径 d0.55 mm孔中心距 p4.8 mm背腔深度 D63 mm单元占空比0.85开孔率 σ10.3%吸声频谱呈现两个明显的吸收峰一个在约650 Hz对应背腔共振一个在约2500 Hz对应微穿孔板自身的共振吸声。两个峰中间的区域吸声系数也保持在0.5以上达到了宽带吸声的效果。这种“双峰耦合”的结构只靠人工参数扫描很难准确凑出来因为两个峰的位置分别受D和d控制还互相影响人工调整往往顾此失彼。5.3 验证阶段的一个提醒TMM算出来的结果最终一定要用有限元或者实验至少验证几个点。我在项目里对优化解做了COMSOL全波仿真两个共振峰的位置偏差在5%以内中频段吸声系数偏差约8%。这个误差主要来自Maa模型对小孔径粘滞效应的经验修正和有限元边界条件设置的差异工程上是可接受的。如果偏差超过15%优先检查孔间距的排列方式假设是否和模型一致方形排列和六角排列在相同开孔率下声阻抗有差别。6. 复现EWOA优化时最容易踩的五个坑这个项目做到后期遇到的大部分麻烦都已经不在算法本身而在工程接口和复现细节上。把这些坑写出来能帮你省下大把调试时间。6.1 只调算法参数不反思目标函数这是最容易掉进去的坑。很多时候优化结果不行不是EWOA不够强而是目标函数里权重分配错了。比如我一开始两个频段权重设为0.5/0.5优化出来的结果在中低频段马马虎虎高频段倒是不错。但工程需求明明是低频降噪更重要。后来把权重调成0.6/0.4才得到合理结果。多试几组权重看看优化解在频响上的迁移比单纯加大迭代次数有效得多。6.2 通风约束被边界悄悄破坏开孔率公式中d和p不能各自独立漂到边界上否则会出现“孔径很大、孔距很小”导致开孔率超过0.5的情况这在物理上意味着一个面板上全是孔已经没有支撑结构了。我自己的处理办法是在适应度函数里直接加一个显式检查σ超限就返回一个极大的负值并且同时通过变量上限映射把p的下限设置为 d·sqrt(π/(4σ_max))从源头防止这个组合出现。6.3 随机数种子不固定对比全白做对比实验里如果每次跑都换随机种子差异会被随机性淹没。哪怕是相同算法不同随机种子也可能跑出完全不同的结果。你在论文里和博客里报告对比时一定要写“使用相同随机种子”并在代码开头固定rng。我在项目里直接rng(42)生成初始种群PSO和GA的种群也沿用同一个种子这样至少可以排除初始分布的影响。6.4 把优化结果当成品不做鲁棒性检查算法找到的最优参数是一个精确数值比如d0.55 mm但加工时钻孔直径误差±0.05 mm很常见。如果最优解处性能对细微偏移极度敏感实际产品做出来性能会远达不到仿真值。建议在优化收敛后对最优解做一个局部鲁棒性分析把每个变量在±5%范围内扰动采样看吸声系数变化多少。如果性能掉得厉害就考虑用平均适应度或者最坏情况适应度作为最终目标函数把最优解“推”到更平缓的区域。6.5 Matlab版本和工具箱兼容性EWOA主程序本身不需要任何额外工具箱但如果你用parfor需确认Parallel Computing Toolbox可用。声学求解器里用到的cot、sqrt这些都是基础函数老版本Matlab也支持。唯一注意的是尽量用函数文件而非脚本尤其是适应度函数放成独立文件后其他项目也能复用。我对这套“EWOATMM”组合最满意的一点是它把声学超表面的设计周期从几周压缩到一两天第一天建模调通优化循环第二天得到候选参数并完成有限元验证。后面再做参数化研究、工况变化重新寻优都只是改几行约束边界的事。最后分享一个小技巧如果你接手这类项目先别急着上复杂结构先拿一个最简单的单层微穿孔板加背腔模型把TMM和EWOA整条链路跑通画出收敛曲线确认最优值和理论预期对得上再逐步增加到多层、多参数、多目标。这套骨架一旦通了往里面加多少层结构都不会乱。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进