简介:针对物理光学中多光束干涉的教学与仿真需求,这份资源以Matlab脚本为核心,复现了不同反射率条件下透射光条纹强度分布曲线,对应教材图4.3的经典结果,适用于高校光学课程学生、仿真初学者及需要快速验证干涉理论的科研人员。压缩包共4个文件,整体仅77KB,包含一个可直接运行的Intensity_Distribution.m脚本,一张干涉条纹图像,一份透射光强度分布分析文档和简要的Readme说明,覆盖从代码运行到结果解读的完整链路。通过修改脚本中的反射率参数,可直观观察条纹明暗对比、间距及相位变化,理解反射率对多光束干涉条纹的调制作用;附带的docx分析文档则进一步阐释了条纹特征与物理机理,便于对照理论公式和实验现象。目前已有1596人学习使用,适合作为光学仿真入门练习或课程设计参考。
1. 多光束干涉仿真能干什么:一张透射曲线图背后藏着三个物理量
多光束干涉是物理光学里少数几个"公式看着简单、图像却藏着丰富信息"的主题。透射光强度分布曲线——就是书上图4.3那种一族不同反射率下的曲线——把反射率、相位差、条纹精细度三个物理量压缩在一张图里。第一次接触的人容易误以为这只是把公式画出来而已,实际上高反射率区域的尖峰对采样点数量、数值格式和坐标范围极其敏感,稍不注意画出来的图就和理论对不上。这个MATLAB仿真资源解决的就是这件事:给定反射率集合,准确画出透射光强度随相位差的变化曲线,并保持数值上的严格一致性。适合正在学物理光学需要复现教材图、做课程设计或者给论文补仿真配图的人。
2. 平行平板多光束模型:从复振幅累加到透射光强公式
2.1 相位差的来源与定义:δ = 4πnhcosθ/λ
多光束干涉的物理场景是一块平行平板。光线以入射角进入折射率为 n、厚度为 h 的平板后,在上下两个表面之间不断反射和透射。相邻两束从下表面出射的光,几何路径差对应光程差为 2nh·cosθ,换算成相位差就是:
δ = 4πnh·cosθ / λ
这个 δ 是整个仿真唯一的横轴变量。教材作图时一般不写具体 h、n、λ,直接把 δ 当作自变量,画 I_t/I_0 与 δ 的关系曲线,所以代码里也直接用 delta 表示相位差,单位是弧度。正入射时 cosθ = 1,公式退化成 4πnh/λ,是最常用的特例;斜入射时 θ 指的是平板内部的折射角,外部入射角需要先用折射定律换算,仿真里如果只画归一化强度曲线完全可以不涉及这些细节。
2.2 等比级数求和:透射光强公式推导
设两个表面的振幅反射系数为 r,透射系数为 t,能量反射率 R = r²,透射率 T = t²,无吸收时 T = 1 - R。第一束透射光的复振幅相对入射场是 t²,第二束经过两次反射多走一个来回,复振幅是 t²·r²·e^{iδ},第三束是 t²·r⁴·e^{i2δ},以此类推。所有透射光在透镜焦平面上叠加,总复振幅是一个公比为 r²e^{iδ} 的等比级数:
E_t = E0·t²·(1 + r²e^{iδ} + r⁴e^{i2δ} + ...) = E0·t² / (1 - r²e^{iδ})
强度取模平方,注意分母展开时用到 |1 - Re^{iδ}|² = 1 + R² - 2Rcosδ = (1-R)² + 4R·sin²(δ/2),最终得到标准的 Airy 函数形式:
I_t/I_0 = (1-R)² / [(1-R)² + 4R·sin²(δ/2)]
这个公式干净到只有两个参数:R 和 δ。R 是整个仿真的"形状旋钮",δ 是自变量。推导中假定反射没有引入额外的半波损失相位,平行平板的对称结构下这个假定是成立的,教材里也默认这么做,仿真时不需要额外处理。
2.3 反射率如何塑造条纹形状:精细度、半高宽与极限行为
先看两个边界值。当 sin²(δ/2) = 1,也就是 δ = (2k+1)π 时,透射光强取最小值 I_min = (1-R)²/(1+R)²。R=0.04 时这个值约 0.85,条纹几乎淹没在背景里;R=0.98 时约 0.0001,暗区接近全黑。当 δ = 2kπ 时,sin² = 0,透射光强严格等于 1,与 R 无关。所以无论反射率多高,峰值永远固定在 1,变的是峰值的宽度。
峰值的尖锐程度用精细度描述:
F = π√R / (1 - R)
R=0.04 时 F≈0.65,条纹宽到几乎没有选频能力;R=0.5 时 F≈4.4;R=0.87 时 F≈23;R=0.98 时 F≈156。对应的半高全宽 FWHM = 2π/F:R=0.98 时只有约 0.04 弧度。这个数字直接决定仿真需要多少采样点——如果横轴从 0 到 8π 覆盖 4 个周期,4001 个点每弧度约 160 个点,能在一个 FWHM 内采到约 6 个点;如果只用 201 个点,每弧度只有 8 个点,尖峰就会被采成三角形甚至完全丢在采样间隙里。
极限行为也值得注意:R→0 时公式趋近于双光束干涉的余弦平方形式,条纹平缓;R→1 时透射峰趋向于宽度为 0 的脉冲串,向狄拉克梳靠近。仿真里选一组从小到大排列的 R 值,正好能把这两种极限和中间过渡状态连贯地画出来。
3. MATLAB 实现步骤:从参数设置到曲线族出图
3.1 参数区:反射率集合、相位差范围与采样点数
%% 参数设置 clear; clc; close all; R_list = [0.04, 0.5, 0.87, 0.98]; % 四档反射率, 覆盖低/中/高三档典型区间 delta = linspace(0, 8*pi, 4001); % 相位差范围: 4个完整条纹周期反射率集合的选择依据在 2.3 节已经说过:0.04 接近裸玻璃界面反射率,0.5 是中等反射率,0.87 和 0.98 对应镀高反射膜的场景。四档足够把条纹从平坦到锐化的过程完整呈现,又不至于图面太乱。相位差覆盖 4 个周期是为了让图的横轴能标出 0、1、2、3、4 这些整数位置,方便和教材图 4.3 对照。4001 个点的采样密度是针对 R=0.98 那条最窄曲线设计的,如果只算到 R=0.87,2000 点也够,但既然对比族里含高反射率,取这个数量是省心的下限。
3.2 核心计算:矢量化写法与数值稳定性处理
%% 计算透射光强 I_td = zeros(length(R_list), length(delta)); % 预分配: 4行 x 4001列 for i = 1:length(R_list) epsn = 1 - R_list(i); % 无吸收时透射率 = 1 - R R = R_list(i); I_td(i, :) = epsn^2 ./ (epsn^2 + 4*R*sin(delta/2).^2); end逻辑说明:先把 epsn 算出来再整体代入公式,而不是写 (1-R)^2 加一个防除零的 eps。原因在于 R=0.98 时 (1-R)^2 = 4e-4,这个数本身很小,如果分母上再加 1e-10 级别的数值小量,峰值位置会出现微小的偏移和抖动。用 epsn^2 直接作为分母第一项,峰值处 sin=0,式子变成 epsn²/epsn²,严格等于 1,不需要任何特殊处理。
参数说明:sin(delta/2).^2 是逐元素平方,注意那个点不能少,矩阵乘方 ^ 在这里会报维度错误。预分配 I_td 是好习惯,虽然四条曲线 4001 个点总共才 16k 个元素,不预分配也不会卡,但后来改成 50 条曲线扫描时,预分配能明显提速。
3.3 绘图区:坐标轴归一化、图例和导出
%% 绘图 figure('Color', 'w', 'Position', [80 80 720 460]); hold on; grid on; plot(delta/(2*pi), I_td(1,:), 'LineWidth', 1.6); plot(delta/(2*pi), I_td(2,:), 'LineWidth', 1.6); plot(delta/(2*pi), I_td(3,:), 'LineWidth', 1.6); plot(delta/(2*pi), I_td(4,:), 'LineWidth', 1.6); hold off; xlim([0 4]); ylim([0 1.08]); set(gca, 'XTick', 0:4, 'FontName', 'Times New Roman', 'FontSize', 12); xlabel('\delta / 2\pi', 'FontSize', 13); ylabel('Transmittance I_t / I_0', 'FontSize', 13); legend('R=0.04', 'R=0.50', 'R=0.87', 'R=0.98', 'Location', 'north'); exportgraphics(gcf, 'multibeam_transmission.png', 'Resolution', 300);横轴写成 delta/(2π) 后,透射峰落在 0、1、2、3、4 这些整数坐标上,读图时一眼就能确认周期位置。ylim 给到 1.08 而不是 1,是因为高反射率曲线在峰值两侧陡降,绘图边框如果刚好切在 1 上,尖峰顶端容易被裁掉一条线。位置属性里的 north 图例在这类多曲线对比图里一般不会遮挡峰值,但如果你的 R 集合里出现了非对称分布,改成 northeast 或手动拖动即可。
exportgraphics 是 2016b 之后引入的函数,旧版本可以换成 print('-dpng', '-r300', 'multibeam_transmission.png')。另外提醒一句,MATLAB 默认的 parula 配色下,R=0.04 和 R=0.5 两条曲线在低光强区颜色接近,若打印黑白版要区分它们,建议手动指定颜色或线型。
3.4 验证曲线正确性:峰值检查与半高宽对比
%% 验证: 三条硬指标 max(I_td(4,:)) % 必须严格等于 1 min(I_td(1,:)) % 应接近 (1-0.04)^2/(1+0.04)^2 ≈ 0.852 max(I_td(4,:) >= 0.5) % R=0.98 峰值半高处是否被采样到逻辑说明:第一条验证峰值归一化,第二条验证暗场背景,第三条验证采样密度够不够。第三行的逻辑判断返回的是 0/1 数组,任何一个 1 代表至少有一个点落在半高以上,如果返回全 0,说明采样点数严重不足,回去把 linspace 的 4001 改成 10001。这三个指标走一遍,曲线族基本可信,可以继续做后面的进阶分析。
4. 避坑与常见问题:五个让透射曲线翻车的细节
4.1 维度错误:sin(delta/2).^2 里那个点不能丢
现象:运行时报错"内部矩阵维度必须一致",光标指向 sin(delta/2)^2 这行。
原因:^ 是矩阵乘方,对向量执行矩阵乘方时要求向量能被当作方阵处理,1×4001 和 1×4001 的矩阵乘方不满足维度规则,直接报错。.^ 才是逐元素运算。
解决:统一写成 sin(delta/2).^2。如果是从别处复制来的公式,先扫描一遍是不是所有的乘方都带了点。这个坑在 R=0.04 时不会触发,因为 0.04 的计算结果里 sin 的平方恰好能碰巧算过去,但换到 R=0.98 就一定会炸。
4.2 峰值变矮:R=0.98 那条曲线最高点不到 0.9
现象:图出来了,四条曲线整体形状对,但高反射率那条尖峰明显比其他三条矮,峰顶像被切了一刀。
原因:最常见的是采样点数不足。R=0.98 的 FWHM 约 0.04 弧度,用 101 个点覆盖 8π,平均每个点间隔 0.25 弧度,尖峰宽度内一个点都落不进去,max 自然采不到 1。其次是数值写法问题,如果在分母上加了防止除零的 eps = 1e-10,峰值附近就可能被压偏。
解决:先用 max(I_td(4,:)) 检查,如果不是 1,把点数提到 10000 再试;如果还是不对,查分母是否误加了 eps。有一种偷懒但有效的中间做法是把横轴范围缩小到 0 到 2π,只画一个周期,这样同样点数下分辨率翻倍。
4.3 图例错位:四条曲线的颜色和图例对不上
现象:图上绿色曲线是 R=0.98 的尖峰,图例却标在 R=0.50 的位置;或者图例只有三条。
原因:legend 默认按绘图顺序取名字。如果中间插入过 set、plot3、双 y 轴或者其他绘图指令,图例顺序就乱了。还有就是循环里画图,直接在循环尾写 legend,每次循环都覆盖一次之前的图例。
解决:给每条曲线加 DisplayName:
plot(delta/(2*pi), I_td(1,:), 'DisplayName', 'R=0.04'); plot(delta/(2*pi), I_td(4,:), 'DisplayName', 'R=0.98'); legend(); % 不带参数, 自动按 DisplayName 生成这样图例名称和曲线绑定,顺序永远不会错。
4.4 三维曲面图轴序颠倒:meshgrid 转置陷阱
现象:想画一张 R-δ-I_t 的三维曲面,用 surf 得到的结果网格扭曲,x 轴和 y 轴的数据对不上,曲面形状完全不对。
原因:surf(X, Y, Z) 要求 X、Y 是 meshgrid 生成的同尺寸矩阵,Z 的尺寸必须等于 size(X)。常见写法是 [X, Y] = meshgrid(delta, R_list),这时 X 是 length(R_list) 行、length(delta) 列,而 I_td 是 length(R_list)×length(delta),正好匹配。如果反过来写 [X, Y] = meshgrid(R_list, delta),维度就反了。
解决:
[X, Y] = meshgrid(delta/(2*pi), R_list); surf(X, Y, I_td); xlabel('δ / 2π'); ylabel('R'); zlabel('I_t / I_0'); view(45, 30);记住一条规律:meshgrid 的第一个输出沿行方向变化,第二个沿列方向变化,Z 的第 i 行第 j 列对应 X(i,j) 和 Y(i,j) 处的函数值。不确定时先看 size(X) 和 size(I_td) 是否一致,不一致就转置。
4.5 导出的位图发虚:分辨率不够
现象:仿真图放到论文或报告里,曲线边缘有锯齿,放大后发虚。
原因:直接截图或默认保存是屏幕分辨率,96 dpi 左右,打印出来明显不够。
解决:用 exportgraphics 指定分辨率导出,想要印刷级质量直接上 600 dpi;如果要插入 Word 并允许放大,导出矢量格式更好:
exportgraphics(gcf, 'multibeam_transmission.pdf', 'ContentType', 'vector');Word 支持嵌入 PDF 矢量图,放大不失真。旧版本 MATLAB 没有 exportgraphics,用 print('-dpdf', '-r600', 'multibeam_transmission.pdf') 替代,效果一样。
5. 进阶用法:从曲线半高宽反推反射率与精细度
仿真跑通之后,最大的价值其实是反向用:手里有一条实测透射强度曲线,通过半高宽反推腔体反射率。这对做滤波片、气体吸收池选型的人很实用。
5.1 半高宽的数值提取
假设已经算好了 R=0.87 那条曲线的 I_td,取其中第二个峰做半高分析:
I_one = I_td(3, :); half = 0.5; % 归一化半高 above = I_one >= half; cross_up = find(diff(above) == 1); % 上升沿穿越点 cross_down = find(diff(above) == -1); % 下降沿穿越点 beta_idx = cross_down(2) - cross_up(2); % 第二个峰的宽度(采样点间隔数) beta_rad = beta_idx * (delta(2) - delta(1)); % 换算成弧度逻辑说明:above 是一个逻辑数组,diff 找状态跳变位置,上升沿到下降沿的距离就是半高宽对应的采样点数,乘上横轴步长得到弧度值。需要注意 findpeaks 在 MATLAB 里也能直接做,但对这种周期性函数,用阈值穿越法反而更稳,不会误检到旁瓣。
5.2 反推反射率与动态演示
得到半高宽 β 后,精细度 F = 2π/β,然后从 F 反推 R:
R = (F - π) / (F + π)
这个公式在 F 较大时精度足够,R=0.87 时理论 F≈23,反推回来误差在 1% 以内。验证方法很简单:用反推的 R 代回 Airy 函数重新画一条曲线,和原始曲线重叠就说明提取流程正确。
如果想把反射率连续变化的过程做成动画,只需要把 R_list 换成向量并循环绘图:
R_sweep = linspace(0.02, 0.99, 50); for i = 1:numel(R_sweep) I_cur = (1-R_sweep(i)).^2 ./ ((1-R_sweep(i)).^2 + 4*R_sweep(i)*sin(delta/2).^2); plot(delta/(2*pi), I_cur, 'LineWidth', 1.5); ylim([0 1.05]); grid on; title(sprintf('R = %.3f', R_sweep(i))); drawnow; end这段动画放到课程汇报里比静态曲线有说服力得多,条纹从平坦的余弦形状逐渐"竖起来"的过程一眼就能看懂。仿真做多了以后,我形成了一个习惯:任何一次跑多光束干涉,先确认峰值严格等于 1,再用 F = π√R/(1-R) 对半高宽做一次独立验算,两件事都通过才敢说曲线是对的。从那以后我每次改参数,都强制走一遍这个流程,翻车的次数基本归零。希望帮到你。
本文还有配套的精品资源,点击获取