先立个目标:这篇文章写完,你要能照着它把“周期性结构 + 多极子展开 + 透射谱 + 可视化”这条链路完整跑通,而不是只停留在“我看过一篇教程”的层面。我自己做超表面和光子晶体仿真这几年,最深的体会是:COMSOL算透射谱本身并不难,难的是把谱线和物理机制对应起来——谷底是电偶极共振还是磁偶极共振?劈裂是源于模式耦合还是晶格衍射?这些光靠看电场分布猜,十次有八次要翻车。多极子展开就是用来解决这个问题的:把远场辐射按电偶极、磁偶极、电四极等通道拆开,谁在哪个波长主导,一图看清。这篇文章就围绕这条主线,从建模、边界条件、透射谱计算,到多极子展开的数学原理与代码实现,再到联合可视化分析,一步一步拆开讲。
1. 项目定义与计算链路梳理
1.1 这个项目到底在算什么
先说清楚我们要处理的物理场景:一个二维周期性排列的纳米结构阵列,比如金纳米盘、硅纳米柱、或者开口谐振环,平面波正入射(或斜入射)照上去,我们关心两件事:第一,不同波长下结构阵列的透射率是多少,这是我们常说的透射谱;第二,某个透射谷或透射峰对应的电磁模式到底是什么类型,这就要靠多极子展开来回答。
为什么要做多极子展开?因为透射谱本质上是一个宏观可观测量的结果,它把所有微观电磁响应都“混合”在了一个曲线里。两个物理机制完全不同的结构,可能画出几乎一样的透射谱;同一个结构在不同波长处,可能先后由不同的多极子通道主导。如果只看谱线形状,你永远只能描述“发生了什么”,没法解释“为什么发生”。多极子展开就是把散射场按球谐函数基底拆解,把每一个共振峰的物理身份标签贴上去。
这个项目的典型应用范围很广:超表面滤波器设计、完美吸收器、传感结构、非线性增强结构,甚至电磁超材料单元设计,凡是涉及“周期性亚波长结构 + 远场光谱响应”的场景,这套流程都能直接平移。对做实验的人来说,它还能帮你在加工前就预判某个共振峰的角谱响应、对入射角的敏感度,以及结构参数偏移后峰的移动方向。
1.2 计算流程的整体框架
整个仿真与分析链路可以分成五个环节,缺一个后面都会卡壳:
- 几何建模与材料定义:构建周期性单元,赋予随波长变化的复折射率数据,这一步出错后面所有结果都白算。
- 边界条件与端口设置:周期性结构用 Floquet 周期性边界条件(COMSOL 里叫 Periodic Condition),激发源用端口(Port)或背景场(Background Field),这一步决定了你算的是无限阵列还是孤立颗粒。
- 频域扫描求解:在目标波段内扫频,得到 S 参数随频率(波长)的变化关系。
- 多极子展开计算:从 COMSOL 里导出单元内电磁场分布,在 MATLAB 或 Python 里做体积分,得到各阶多极子系数。
- 联合可视化:把透射谱和多极子贡献画在同一张图里,找到峰谷与辐射通道的对应关系。
每一步都有容易翻车的细节。比如 Floquet 端口的模式阶数,默认可能只算 0 阶,但高阶衍射通道在某些波段里是开着的,漏掉就会导致透射谱在高频段严重失真。再比如多极子展开的坐标原点,选在结构几何中心还是质心,结果会差很多,尤其是对于不对称结构,原点选错会把低阶多极子的贡献“泄漏”到高阶项里去。
1.3 我用的软件版本与模块配置
我这次用的是COMSOL Multiphysics 6.1,物理场接口选的是RF Module下的Electromagnetic Waves, Frequency Domain (ewfd)。这里有两个常见的选型坑:
第一,不要用波动光学模块(Wave Optics)来算。波光学接口默认的因变量是电场,虽然也能算,但它对材料色散的处理方式、端口定义的习惯,和 RF 接口不太一样。尤其在可见光到近红外波段,材料折射率实部小于 1 的情况(比如金、银),RF 接口的边界条件处理更稳健。当然,如果在微波波段,两个都可以,但既然要统一流程,我建议全部走 RF。
第二,求解器要启用直接求解器(Direct,MUMPS)。周期性结构 + 色散材料 + 频扫,这三件事凑在一起,迭代求解器很容易不收敛或者收敛到错误的解。直接求解器慢一些,但胜在稳。我在一个硅纳米柱阵列上试过,迭代求解器在某个波长上静默地给出了一个能量不守恒的结果,透射加反射大于 1,排查了很久才发现是求解器的问题。
2. 周期性结构的建模细节:几何、材料与边界条件的正确配置
2.1 几何建模的取舍原则
周期性结构的几何建模,关键不是画得像不像,而是算得了、算得准、算得快。这三个目标经常冲突,需要做取舍。
以金纳米盘阵列为例子。实际加工出来的纳米盘,边缘是有一定倾斜角度的,底部可能还有一层几纳米的粘附层(比如钛或铬)。但从仿真角度,除非你的研究目标就是研究边缘角度对共振的影响,否则这些细节全部忽略。原因很简单:COMSOL 在边界处要画网格,每多一个小圆角或倾斜面,网格量就可能翻倍,而计算结果差异常在 1% 以内,远小于实验中的加工误差。
我的建议是,第一步先用最简单几何跑通全流程:圆柱 + 基底 + 空气层。等流程完全跑通,再根据需要逐步加入复杂化因素。这样能保证你不会把大量的时间花在几何细节上,最后发现多极子展开程序里有一个 bug 需要从头再来。
几何参数上要特别注意一个点:单元尺寸(晶格常数)和结构尺寸的相对关系。对于亚波长结构,单元尺寸通常要小于工作波长,否则会出现高阶衍射;但也不能太小,否则相邻结构之间的近场耦合太强,多极子展开的单颗粒近似会失效。经验上,晶格常数 p 和工作波长 λ 的关系在 0.5λ 到 1.0λ 之间比较常见。这个区间内,Floquet 模式通常只有 0 阶传播,多极子分析的结果也最干净。
2.2 材料色散数据的处理:一个容易被忽略的精度陷阱
金属材料的色散必须用实验测量的复折射率数据,不是常数,也不是简单的 Drude 模型就够。我用的是 Johnson and Christy 的金、银数据,这是光学仿真界的“老黄历”了,虽然老,但可靠、可复现,审稿人也认。
COMSOL 里导入色散数据有两种方式:
- 在材料节点下用 Interpolation 函数,把波长-折射率数据点导入,然后设置折射率实部 n 和虚部 k 为插值函数。这种方式最灵活,也最容易检查数据是否正确。
- 直接用 COMSOL 材料库里的内置金属材料。方便是方便,但内置数据的来源和适用范围有时候不透明,而且不同版本的 COMSOL 材料库数据有差异。如果你要复现别人论文里的结果,强烈建议自建材料,保证数据来源一致。
这里有个特别容易翻车的精度陷阱:插值函数要在整个计算波段内连续可导。COMSOL 在求解时会用到折射率对频率的导数(比如计算群速度、色散效应时),如果插值点之间是线性插值,导数就是分段的常数,会在数据点上出现跳变。虽然大多数情况下这不影响 S 参数的计算结果,但如果你后续要做材料的损耗分析或者非线性分析,这个问题会被放大。
我的做法是:导入数据后用 MATLAB 做一次平滑,再以平滑后的数据点建插值函数。平滑方法用移动平均或者局部回归(loess)都可以,关键是不要改变数据的总体趋势,尤其是不要抹掉等离激元共振峰的位置。
2.3 Floquet 周期性边界条件的正确打开方式
周期性边界条件的设置在 COMSOL 里路径是:Definitions > Periodic Condition。但这里有几个细节新手特别容易踩:
第一个细节:边界条件要成对选择。你需要先定义一个“源边界”(Source),再定义一个“目标边界”(Destination),两者的网格必须完全匹配。COMSOL 的周期性边界条件会自动处理匹配,所以只要你用同一个几何操作生成的对面边界,通常没问题。但如果你的几何是通过复制、旋转等操作生成的两对面,一定要检查每一对面是否都配了对。漏掉一对面,结果直接就是错的,而且错得毫无征兆。
第二个细节:k-vector 的设置。正入射时,Floquet 波矢的周期分量是 (0,0),这最简单。斜入射时,需要根据入射角和方位角算周期分量,这个稍后展开。一个常见的误区是:有人以为周期性边界条件只需要在 x 和 y 方向各设一对就完了,其实还需要注意端口处的高阶衍射模式是否要包含,这个后面专门讲。
第三个细节:对称性边界条件的误用。如果结构在 x 或 y 方向有镜面对称,可以额外加 Perfect Electric Conductor (PEC) 或 Perfect Magnetic Conductor (PMC) 对称面来减半模型。但仅当入射场也满足对应对称性时才成立。斜入射时,入射场本身就不满足镜面对称,强行用对称面会算出错误结果。我一开始图省事,在正入射验证完之后直接切到斜入射,没去掉对称面,结果透射谱上出现了莫名其妙的尖峰,排查了半天才意识到是这个问题。
2.4 端口设置与衍射模式:为什么透射谱高频段会失真
在周期性结构中,端口设置不能只留一个默认的“Port 1, Port 2”。COMSOL 的 RF 模块中,端口类型选Periodic,它会自动计算 Floquet 模式。但关键在模式阶数的选择:默认情况下可能只会计算少数几个低阶模式,而高频段高阶衍射模已经打开,如果这些模式没有被包含在计算中,能量就会“消失”,透射率算出来偏低。
怎么判断哪些模式需要包含?方法很简单:看频率对应的波长 λ 和周期 p 的关系。对于正入射,当 λ > p 时,只有 0 阶模式传播;当 λ < p 时,至少会出现 (±1, 0) 和 (0, ±1) 阶衍射。所以如果你的计算波段最低波长已经小于周期,就必须在端口设置里手动加高阶模式。
在 COMSOL 中,操作路径是:Port 节点 > Periodic > Mode list,手动列出所有可能传播的模式阶数。我建议宁可多算几个也不漏,因为高阶模如果不传播,COMSOL 会自动衰减掉,对结果没有影响;但漏掉一个传播的模式,结果直接就是错的。
这里我再强调一个检查手段:算完透射谱后,把 T + R(透射率+反射率)画出来,看是否等于 1。如果不等于 1,不要怀疑物理,先回去检查端口模式有没有漏。能量守恒是对周期性结构仿真最简单的“体检”。
3. 透射谱的计算逻辑与数据导出:从 S 参数到光谱曲线
3.1 频域扫描设置:波长扫描还是频率扫描
COMSOL 中的频域扫描有两种方式:按频率扫和按波长扫。对于光学问题,我强烈建议按波长扫。原因很实际:材料色散数据通常是按波长给的,按波长扫描可以直接复用插值节点,扫描点也更好控制密度。
在Study > Step 1: Frequency Domain中,设置扫描范围时,把单位改成 nm,然后设置步长。步长不是越小越好:COMSOL 的频域求解器在每个频点是独立求解的,点数太多,总耗时线性增长,而一些窄线宽的共振峰可能在几个纳米内就从峰顶到谷底,步长太大根本捕捉不到。
判断步长是否合适的办法很土但很有效:扫完一遍,看看透射谱里有没有“尖刺”,如果有,把那个附近的谱线单独加密重新扫一遍,和原来的结果对比。如果峰谷变深了,说明原步长不够;如果没变化,说明步长够了。
这里有个经验值可以参考:对于等离激元结构,在共振峰附近步长建议不超过 2 nm;非共振区可以放宽到 5-10 nm。如果结构是低损耗介质(比如硅),共振线宽本来就窄,步长建议 1 nm 以下。
3.2 S 参数的本质与透射率的正确算法
COMSOL 在端口处计算出来的 S 参数,本质上是端口模式复振幅的比值。对于周期性端口,S21 的物理意义是透射 0 阶模式的复振幅与入射 0 阶模式的复振幅之比,是一个复数,包含了相位信息。
但注意:S21 的模平方不完全等于透射率。透射率是功率之比。在无损耗、对称结构、正入射这些条件都满足时,T = |S21|² 成立。但一旦有高阶衍射模式传播,能量会被分配到高阶通道里,这时只取 S21 会低估总透射。
正入射且只关注 0 阶光谱时,T = |S21|² 是常用近似,这个没问题。但如果你的研究涉及斜入射或者短波段,正确的做法是:把每个传播模式对应的 S 参数模平方加起来,得到总透射。COMSOL 的端口节点里会列出所有模式的 S 参数,把它们都导出。
不过这里还有个更省事的方案:直接在 COMSOL 里定义一个“能量透射率”的全局变量,用端口边界上的坡印廷矢量积分来计算透射功率,再除以入射功率。这样做的好处是不需要关心哪些模式在传播,功率积分自动包含了所有通道的能量。操作上,在Derived Values > Surface Integration里选端口边界面,对Time-average Power Flow, Outgoing做积分即可。
3.3 数据导出的格式与后续处理流程
COMSOL 导出一维数据有几种方式,我最常用的是:Results > 1D Plot Group > Global,把多个变量画在一起,然后File > Export Data > Plot,导出为文本文件。
导出时注意几点:
导出数据点的密度。COMSOL 默认导出的是绘图点,如果你在频域扫描里设置了“Store fields on all frequency points”,那每个频点都有结果;但如果没有存储场,只有 S 参数结果,导出的是 S 参数在每个频点的值。这个在导出设置里可以指定。
变量名的记忆。导出的表头是变量名,比如
port_1_Sparam、port_2_Sparam。这些名字在你建模的时候就会生成,导出时对应关系要理清楚。我习惯在做完定义后,把端口编号和物理意义记在一个笔记里,防止后面导出时对应错。文本格式。导出为 .txt 或 .csv 都行。如果数据有很多列,用 .csv 更方便后续在 Python 里读取。
导出的原始曲线通常会有一定的数值噪声,尤其是远离共振区的平缓区域,S21 的幅值在两个相邻频点之间可能会有小波动。这不是物理效应,是数值求解的误差。处理方式是在绘图时做一次平滑滤波(比如 Savitzky-Golay 滤波),窗口大小不要太大,否则会把尖锐的共振峰抹平。
4. 多极子展开的原理与代码实现:找出占主导的共振机制
4.1 多极子展开的物理图像
多极子展开的思想并不复杂:任意一个电流分布产生的远场辐射,可以看成一系列“基本辐射体”的叠加。基本的零阶辐射体是电偶极子(ED),它由电荷分离产生;第二重要的是一阶辐射体,包括磁偶极子(MD),由环形电流产生,和电四极子(EQ),由电荷的四边形排布产生;再往上还有磁四极子(MQ)、电八极子(EO)等。
低阶多极子的远场辐射功率和频率的标度关系不同:电偶极子辐射功率正比于 ω⁴,磁偶极子也是 ω⁴,但电四极子正比于 ω⁶。这意味着什么?在高频段,高阶多极子更容易被激发,贡献占比会上升。所以同一个结构,低频段可能是电偶极子主导,高频段切换到磁四极子或电八极子,这是完全正常的。
多极子展开的价值在于:它把“一团复杂的电磁场分布”压缩成一组标量系数,每个系数对应一个明确的物理图像和辐射方向图。通过比较各阶系数的贡献权重,我们就能判断光谱中的每个共振峰是由哪种模式触发的。
4.2 笛卡尔张量形式的积分公式:实用选择
多极子系数的计算有两种常用形式:球谐函数展开和笛卡尔张量积分形式。在 COMSOL 的网格数据上,我用的是第二种,因为它可以直接利用仿真中得到的电流密度 J(r),做体积分,不需要处理球谐函数的角动量耦合问题。推导这里不展开,实际要用到的公式如下:
电偶极矩:
[ \mathbf{P} = \frac{1}{i\omega}\int \mathbf{J} , d^3r ]
磁偶极矩:
[ \mathbf{M} = \frac{1}{2c}\int (\mathbf{r} \times \mathbf{J}) , d^3r ]
电四极矩(张量形式):
[ Q_{\alpha\beta} = \frac{1}{i2\omega}\int \left[ r_\alpha J_\beta + r_\beta J_\alpha - \frac{2}{3}(\mathbf{r}\cdot\mathbf{J})\delta_{\alpha\beta} \right] d^3r ]
其中 (\alpha, \beta \in {x,y,z}),(\delta_{\alpha\beta}) 是克罗内克函数。有了这些矩,就可以用下面的公式计算各通道的散射功率(在非磁性的情况下):
[ P_{ED} = \frac{\mu_0\omega^4}{12\pi c}|\mathbf{P}|^2 ]
[ P_{MD} = \frac{\mu_0\omega^4}{12\pi c}|\mathbf{M}|^2 ]
[ P_{EQ} = \frac{\mu_0\omega^6}{160\pi c^5}\sum_{\alpha,\beta}|Q_{\alpha\beta}|^2 ]
这几个公式的适用范围是真空/均匀介质背景。如果结构埋在介电常数为 (\varepsilon_d) 的均匀介质中,需要做替换:(\mu_0 \to \mu_0/\sqrt{\varepsilon_d})、(c \to c/\sqrt{\varepsilon_d})。对于基底上的结构,严格来说不是均匀背景,但实际处理中可以用“平均环境”做一个近似。这一点后面会专门展开,因为它是很多人在多极子展开结果不合理时忽略的原因。
4.3 MATLAB 实现:从 COMSOL 导出体电流密度到多极子系数
在 COMSOL 中,体电流密度 J 不是直接可以导出的物理量。需要先手动定义一个变量。在Definitions > Variables里定义:
Jx = ewfd.Jx Jy = ewfd.Jy Jz = ewfd.Jz然后,在需要做多极子展开的波长点,把整个结构域内的 Jx、Jy、Jz 导出。推荐导出到 .txt 文件,格式是每一行存储一个网格单元中心点的坐标以及该点的 J 分量。
有了这些数据,MATLAB 的实现很直接:
% 读取 COMSOL 导出的体电流数据 % 格式: x y z Jx Jy Jz data = load('current_density.txt'); x = data(:,1); y = data(:,2); z = data(:,3); Jx = data(:,4); Jy = data(:,5); Jz = data(:,6); % 离散体积元的体积(假设网格近似均匀,取平均体积) dx = median(diff(unique(x))); dy = median(diff(unique(y))); dz = median(diff(unique(z))); dV = dx * dy * dz; omega = 2*pi*c/lambda; % 角频率,单位注意统一 % 电流密度体积分:电偶极矩(复数) Px = (1/(1i*omega)) * sum(Jx(:)) * dV; Py = (1/(1i*omega)) * sum(Jy(:)) * dV; Pz = (1/(1i*omega)) * sum(Jz(:)) * dV; % 磁偶极矩:需要叉乘 r × J Mx = (1/(2*c)) * sum( (y.*Jz - z.*Jy) ) * dV; My = (1/(2*c)) * sum( (z.*Jx - x.*Jz) ) * dV; Mz = (1/(2*c)) * sum( (x.*Jy - y.*Jx) ) * dV; % 散射功率 mu0 = 4*pi*1e-7; P_ED = mu0*omega^4/(12*pi*c) * (abs(Px)^2 + abs(Py)^2 + abs(Pz)^2); P_MD = mu0*omega^4/(12*pi*c) * (abs(Mx)^2 + abs(My)^2 + abs(Mz)^2);代码看着简单,但有三个细节必须注意:
第一,单位要统一。如果 COMSOL 几何用的是纳米,电流密度单位是 A/m²,那么坐标要转换成米再算,否则差 10^9 的因子。我在第一次算的时候就是忘记转换单位,得到的高阶多极子项异常大,检查了整整一天。
第二,体积元的计算不能想当然。如果网格不是均匀的,用上面的median(diff(unique))方法会不准确。更稳妥的办法是:在 COMSOL 里做一次体积分,记录总积分值,然后在 MATLAB 里用点数反推平均体积:dV = 几何体积 / 总点数。这个值比你用坐标差推算的更稳健。
第三,相位基准要一致。多极子系数是复数,相位取决于坐标原点和参考时刻。如果你的目的是看相对贡献大小,相位不重要;但如果是做干涉分析(比如电偶极和磁偶极之间的干涉),就必须明确原点和参考面。通常把原点选在结构的几何中心或重心,并且保持所有波长、所有结果都在同一参考系下。
4.4 周期性与多极子展开的冲突及处理策略
这里有个概念性的问题需要说清楚:多极子展开严格来说是对孤立颗粒的散射场做的。而我们在 COMSOL 里模拟的是周期性阵列,每个单元里的电流分布是包含了相邻单元耦合的“等效”电流。
那周期阵列的多极子展开为什么还是有效的?
答案是:定性有效,定量有偏差。当晶格常数大于结构尺寸的 3 倍以上、相邻单元间的近场耦合较弱时,每个单元内的电流分布接近于孤立颗粒的电流分布,此时多极子展开各项的相对大小基本可靠。但当单元间距很近时,相邻颗粒之间的近场相互作用会改变每个颗粒的等效极化率,此时多极子展开的结果只能作为参考,不能严格定量解释。
有一种常见的处理方式:用“单颗粒 + 周期性边界”的两步法。第一步,用 COMSOL 算单个颗粒在平面波照射下的散射场,做常规多极子展开;第二步,把阵列作为一个周期系统分析,用多极子的“阵列因子”(array factor)修正。这样得到的结果更严格,但实现复杂度翻倍,而且需要搞清楚阵列因子和耦合之间的微妙关系。我的建议是:多数情况下用单元电流直接展开就够了,在论文里加上一句“多极子展开基于单元内电流,定性反映共振模式类型”即可。
5. 透射谱与多极子联合可视化:从谱线形状读出物理机制
5.1 多极子谱线和透射谱叠加:一张图讲清楚机制
计算的最终产出是一张联合图:横轴是波长,左纵轴是透射率,右纵轴是多极子散射功率(对数坐标),不同颜色的曲线分别对应电偶极、磁偶极、电四极的贡献。
画好这张图的关键在于归一化。透射率是 0-1 范围的量,而多极子散射功率的量级可能从 10^-10 到 10^-6,直接画在一张图里,多极子曲线会被压成一条贴着横轴的线,什么都看不见。我习惯的做法是:把每个多极子通道的功率除以所有通道功率之和,得到“相对贡献占比”。这样所有曲线都在 0-1 之间,和透射率可以同轴显示,方便直接对比。
多极子谱线和透射谱线叠加之后,一个典型的“标准图景”是这样的:
- 某波长处,电偶极子散射功率占比突然上升,该处透射谱出现一个谷底。
- 磁偶极子占比上升的位置,往往伴随一个 Fano 不对称线型,因为磁偶极共振通常和宽带背景产生相消干涉。
- 电四极子占比在短波长处开始抬头,透射谱出现一个更宽更浅的谷。
注意:透射谷的位置和多极子共振峰的位置并不严格重合。透射谷是“总场干涉相消”的结果,多极子峰是“某一种辐射通道增强”的结果。两者之间通常有几纳米的偏移,这是正常的,不要试图把它们硬生生对齐。判断关联时,应该看“透射谷附近是否有某个多极子通道的占比同步抬升”,而不是找完全重合的极值点。
5.2 用多极子的干涉项解释 Fano 线型
透射谱里经常看到一种不对称的峰谷结构,史称 Fano 共振。这种线型的来源可以用多极子的干涉来解释:当一个窄带的暗模式(比如磁四极子)与一个宽带的亮模式(比如电偶极子)在频谱上重叠时,两条通道的辐射场会发生相消或相长干涉,产生不对称线型。
要在多极子分析中识别这种干涉,光看各通道的功率占比还不够,因为功率是模平方,丢失了相位信息。正确的做法是:把复数的多极子矩(比如电偶极矩 P 和磁偶极矩 M)在同一个复平面上画出来。如果两条矢量的方向在某个波长处突然从“同向”变成“反向”,那这里必然存在干涉异常,对应透射谱里会出现 Fano 线型。
这个分析做一次两次之后就会形成直觉:看到谱线上有个明显不对称的峰谷组合,第一反应就去看那两个波长的复多极子矩的相位关系。相位差接近 180° 且宽度相似,基本可以锁定是 Fano 型共振。
5.3 电场与功率流分布图:验证多极子判断的“照妖镜”
多极子展开给了结论,但有时候结论可能出乎意料,这时候需要用电场分布图和功率流图来交叉验证。
具体操作为:在 COMSOL 后处理中,选一个透射谷对应的波长,画结构内部及周围 3D 电场增强分布 |E|/|E0|。观察增强区域:如果是电偶极共振,增强区通常集中在结构的一端(或两端),呈现明显的偶极子极化方向;如果是磁偶极共振,增强区会形成一个首尾相接的环形分布,这是环形位移电流的典型特征;如果是四极甚至更高级的模式,增强区会呈现更多的节点结构。
更直观的标准是位移电流分布:在结构中做一个截平面,画电流箭头图。磁偶极子对应的是一个闭合的环形电流图案,电偶极子对应的是沿某个方向的大致平行的电流线。这两种图案非常容易辨认,几乎不可能认错。
我一般建议在论文里放这样一组图:透射谱-多极子联合图当“总览”,电场分布图当“特写”,两个证据彼此支撑,这个共振机制的论述就立得住。
5.4 可视化编码建议:让看图的人快速抓住重点
画图这件事,很多人不重视,但审稿人或导师第一眼就是从图里判断工作质量的。这里分享几个我在可视化上的做法:
- 透射谱用黑色粗线,多极子通道用彩色细线。主次分明,不会被多根彩色线干扰。
- 共振波长处加一条竖直虚线,把透射谷和多极子峰对齐标注。这样读者可以快速定位每个共振峰对应的多极子通道。
- 多极子占比用面积图(stacked area)而不是折线图。堆叠面积图能一眼看出“哪个波长段哪种机制占主导”,比折线的阅读成本低得多。
- 如果做斜入射扫角分析,用二维颜色图(横轴波长,纵轴入射角,颜色表示透射率),然后在图上叠加多极子共振峰位置点。这样做可以看模式随角度的色散行为,信息量非常大。
6. 实操中容易翻车的几个细节与排查思路
6.1 收敛性检查:网格加密到结果不变才算数
这是周期性结构仿真最老生常谈但依然最多人栽的问题。COMSOL 的默认网格是为通用物理问题设计的,对等离激元结构来说,默认网格几乎必然太粗。金属表面的趋肤深度在可见光波段只有几十纳米,如果边界层网格不够密,表面电流分布会被严重低估,导致多极子展开的偶极矩计算偏差巨大。
我的经验是,至少做三组网格的收敛性测试:
- 粗网格:默认网格或略加密。
- 中网格:在金属表面加 3-5 层边界层网格,最大边界层厚度小于趋肤深度的 1/3。
- 细网格:在中网格基础上把全局最大单元尺寸再减半。
如果透射谱从粗到细变化明显,继续加密;如果中网格和细网格的结果几乎重合(谷深差异小于 1%),取细网格的结果做后续分析。另外要盯着看多极子展开的结果,因为透射谱可能已经收敛,但多极子矩对网格更敏感——它直接依赖于电流分布的细节,电流分布只要有微小扰动,高阶矩的数值就可能跳动很大。
6.2 多极子结果不合理的排查清单
如果多极子展开的结果明显不合理(比如所有波长都是电偶极主导,完全没有磁偶极贡献),按以下顺序排查:
第一,检查坐标单位。我把这个列第一位,因为我自己犯过,而且这个错误的表现方式非常具有迷惑性——结果看起来“很合理”,只是数值完全不对。坐标一定要转换成米再做积分。
第二,检查电流密度变量名。COMSOL 中的电流密度是ewfd.Jx、ewfd.Jy、ewfd.Jz,不要在Variables里把它们重新定义成同名的另一个变量,否则可能导出错误的数据。导出前先在数据检查里画一次这个变量的分布,看看是否符合物理预期。
第三,检查积分域。正确做法是只在结构域内做积分。空气域中的位移电流也要考虑,尤其当结构周围存在强近场时,空气域的位移电流对多极子矩也有贡献。但大部分情况下,结构内部的传导电流占主导,空气域的贡献可以忽略。如果你发现多极子结果对积分域边界很敏感,就要把积分域扩大到包含近场区域再试试。
第四,检查坐标原点。原点偏移会导致偶极矩和高阶矩之间发生混合。验证方法是:故意把原点移动几个纳米,看多极子结果是否发生明显变化。如果变化明显,说明你的结果对原点敏感,需要重新选择原点的位置(一般选几何中心即可,并保持一致)。
6.3 高频段透射率大于 1 的排查思路
这是个让我印象深刻的问题。某次仿真,在波长接近周期的短波段,透射率居然超过了 1。物理上这是不可能的,问题一定出在数值设置上。
排查路径如下:
- 检查端口模式列表。这是我前面反复强调的:高频段高阶衍射模式必须加入端口计算。漏掉会对能量的计算产生影响。
- 检查网格。如果金属结构表面网格太粗,表面等离激元的传播长度会被高估,可能导致局部的功率流积分偏大。
- 检查坡印廷矢量的积分面。积分面如果紧贴着结构表面,近场中的非辐射分量会被错误地计入“透射功率”。正确的做法是至少把积分面放在距离结构表面半个波长以上的位置。
最终我的问题就是出在第一点:漏了高阶衍射模式。补上之后,T + R 恒等于 1,问题消失。
6.4 周期结构斜入射的 Floquet 波矢设置
如果你的研究涉及斜入射,Floquet 周期性边界条件的设置就要多费些心思。k 矢量的切向分量为:
[ k_{//} = \frac{2\pi}{\lambda} (\sin\theta\cos\phi, \sin\theta\sin\phi) ]
在 COMSOL 的 Periodic Condition 中,需要把这里的 k 分量转换成对应的相位因子。注意:这里的 θ 是入射角,φ 是方位角,两者独立,缺一个都会造成斜入射结果完全错误。
斜入射时还有一个容易被忽略的问题:S 参数的定义会变。端口模式可以分解为 TE 和 TM 偏振,两种偏振的 S 参数是分开计算的。当入射角变大,模式之间可能发生耦合,这时光看一个偏振的透射谱就不够了,需要同时看交叉偏振透射(比如 TE 入射产生 TM 透射),那是手性超表面和偏振转换器件的核心指标,也是一大批论文的看点。
7. 个人经验拓展:从“能算出来”到“讲得明白”的关键几步
7.1 多极子展开和高级后处理:一个参数化扫描的自动化脚本思路
当模型、边界条件、多极子展开程序都稳定之后,你会发现最耗时间的事情变成了重复劳动:换一个结构参数(直径、周期、高度),重新跑一遍频扫,导出数据,再跑一遍多极子展开,画图,判断结果。
这一步可以通过 COMSOL 的Parameter Sweep和COMSOL with MATLAB联合脚本把整个流程自动化。具体思路是:在 COMSOL 中把几何参数设为全局参数,用model.param().set('d', value)修改参数值,循环求解、导出、调用 MATLAB 多极子展开函数,最后把所有结果汇总成一张“参数-波长-多极子贡献占比”的三维图。
这个自动化能带来的价值非常大:你可以一次性扫描几十组参数,各组之间不需要手动干预。更重要的是,你可以同时记录每个参数组合下多极子共振峰的位置和类型,从而画出“结构参数调谐模式类型”的相图——这种图在设计超表面时极其有用。
7.2 数值实验的记录习惯
最后说一个看起来和“硬核仿真”无关,但实际极其重要的习惯:每次仿真都要记录完整的日志。
我之前吃过一次亏:调了一个晚上的参数,终于得到了想要的谱线,但因为没有记录具体参数,第二天想复现,死活找不到那组参数对应的设置。从那以后,我养成了一个习惯:仿真文件命名带参数摘要,比如Au_disk_d120_p300_h40_theta0.txt;同时在项目笔记里记录当天的修改内容和结果现象。
对于周期性结构 + 多极子展开这种多步骤流程,一条完整记录应该包括:几何参数、材料数据来源、网格参数、频扫设置、端口模式数、多极子展开的文件名与代码版本。这样即使三个月后回过头来看,也能完全复现当时的计算。这不是形式主义,是做研究的基本功。毕竟,仿真的核心价值不只是“得到结果”,而是“让结果可以被检验、被复现、被信任”。