简介:面向光电信息科学与工程及物理光学课程的本科生与研究者,这套MATLAB仿真资源以钠黄双线(D1、D2)为例,完整复现教材中法布里-泊罗干涉仪的干涉结果,帮助理解F-P平板中的多光束干涉、腔长调谐及双线叠加后的条纹形态,也适合作为课程设计或虚拟实验的起点。资源压缩包共7个文件,约280KB,包含两个MATLAB脚本(主程序与绘图模块)、一份Word理论分析文档、三张干涉图样JPG以及一个Readme说明,覆盖从参数设置、数值计算到结果可视化的完整流程,脚本中涉及网格坐标生成、二维傅里叶变换和相位运算等典型光学仿真方法。目前已有1437人学习使用。通过运行脚本可自由调整波长、腔厚、初始相位等参数,观察不同条件下干涉条纹的变化规律;配套Word文档给出理论背景与结果分析,JPG图片则直观展示多组仿真输出,便于对照教材图4.7查漏补缺。对不便开展实物实验的读者而言,这是一份开箱即用的虚拟实验参考。 法布里-珀罗干涉仪(Fabry-Perot Interferometer,简称F-P)是光学里一个特别经典的器件,它的核心玩法就是“多次反射,多光束干涉”,能把很接近的两个波长分开。我当年学物理光学的时候,书上差不多都会放一张图,展示不同反射率下透射峰的锐度变化,又或者用钠黄双线来做分辨率的例子。这篇博文就带着大家用Matlab把这个仿真复现一遍,重点模拟F-P平板对不同反射率下的透射率响应,以及钠黄双线(589.0 nm和589.6 nm)在这种干涉仪里是怎么一步步被分辨出来的。
为什么要写这个?因为光学仿真最怕的不是公式难,而是“公式懂了,代码不知道从哪里下手”。尤其是F-P这类多光束干涉,相位差、反射率、波长、板间距之间的关系如果不理清楚,仿出来的图很容易和书上对不上。这篇内容适合正在学物理光学、需要做课程仿真作业的大学生,也适合想快速复现经典干涉现象、加深理解的工程人员。我会把光学原理、参数设计、Matlab代码实现、结果分析和常见坑都讲一遍,代码可以直接复制运行,图出来之后你就能直观看到F-P干涉仪为什么能当“波长筛选器”用。
1. 光学原理与仿真目标拆解
1.1 F-P平板干涉的核心公式
F-P干涉仪本质上是一块两面镀高反射膜的平行平板,光在板内来回反射,每次透射出一部分光。这些透射光在无穷远处(或透镜焦平面上)叠加,形成多光束干涉。假设平板两侧介质相同,入射角为θ,平板折射率为n,厚度为d,则相邻两束透射光之间的相位差为:
δ = (4π n d cosθ) / λ
如果用反射率R来表示两面反射膜的振幅反射率,不考虑吸收,那么透射光强与入射光强之比就是:
T(δ) = 1 / (1 + F·sin²(δ/2))
其中F是精细度系数:
F = 4R / (1 - R)²
这个公式是所有F-P仿真里最核心的东西。可以看到透射率是δ的周期函数,当δ = 2mπ的时候,sin²(δ/2) = 0,透射率达到峰值1;其他位置透射率下降,下降的剧烈程度由F决定,也就是由反射率R决定。R越接近1,F越大,透射峰就越窄越尖锐,干涉条纹的精细度(Finesse)也越高。精细度定义为:
Finesse = π·√F / 2 = π√R / (1 - R)
1.2 钠黄双线为什么是经典案例
钠黄光是很多光学实验的“标准光源”。它的发光谱线里有两根特别靠近的强线,波长分别是589.0 nm和589.6 nm,波长差只有0.6 nm。这个差值放在普通光谱仪里很容易被当成一条线,但对F-P干涉仪来说,只要选合适的板间距和反射率,就能把这两条线分别“顶”出来。
在F-P仿真里,两条谱线其实就是在同一个干涉仪下,由于波长λ不同,导致同一级干涉对应的相位差δ不同,于是两个透射峰在波长轴上会错开。关键问题是你能不能分辨它们。判断标准通常是瑞利判据:当一个波长的透射峰中心刚好落在另一个波长的透射峰第一个零点附近时,认为刚好可分辨。对于F-P,这要求仪器的分辨本领够高,而分辨本领正比于精细度和干涉级次。
1.3 目标:复现书上图4.7的物理图像
大多数物理光学教材里的图4.7,一般会画出透射率随相位差δ变化的曲线,并且在一张图上对比不同反射率R的情形。这样能直观看出:R越大,透射峰越窄,背景越暗,条纹对比度越高。我这个仿真就做成两种结果:
- 画出不同反射率下的T(δ)曲线,对应书上的经典图;
- 在这个基础上,把横轴从相位差δ转换成波长λ,固定d和θ,模拟钠黄双线分别产生的透射峰,观察R变化时两个峰能否被分辨。
这样就既覆盖了原理图,又结合了钠黄双线这个具体例子,仿真结果可以直接和教材对照。
2. 仿真参数设计与Matlab实现思路
2.1 关键参数的物理量纲与取值
做仿真之前,先把参数的单位和物理意义敲定。波长全部用纳米(nm)比较直观,但公式里相位差需要波长,所以单位只要统一即可。板间距d是决定干涉级次的核心参数,我这里的取值会直接影响两条谱线的峰间距。比如d = 1 mm时,对于589 nm的光,干涉级次大约m = 2nd/λ ≈ 3395级,这是一个很大的数。此时波长改变0.6 nm,对应的相位差变化大约是:
Δδ = (4π n d / λ²)·Δλ
代入d = 1 mm、n = 1、λ = 589.3 nm、Δλ = 0.6 nm,可以估算出Δδ约为6.5 rad左右,这个量级下两个峰在相位轴上能明显分开。但如果d太小,比如0.1 mm,Δδ不到1 rad,分辨就很难。
反射率R的选择上,我建议从0.2、0.6、0.9这几个档位开始,最后可以加到0.98看看极限情况。R越高,透射峰越窄,但需要注意的是数值计算时分母会非常小,容易造成精度问题,这个后面在常见问题里细说。
2.2 计算公式的离散化:横轴到底该取什么
仿真透射率,本质上是把连续波长轴/相位轴离散成一批点,然后逐个计算T(δ)。如果直接用for循环扫描,代码简单但效率低;更推荐用Matlab的向量化写法,一次生成整个横轴数组,然后对整个数组做运算。
在画不同反射率的对比图时,横轴用δ(0到2π)最干净,因为透射率是周期函数,一个周期就能看清所有特征。画钠黄双线时,横轴最好用波长λ,这样更接近实际光谱仪读出来的结果。这两种横轴之间可以通过公式互相转换。
2.3 代码的整体框架
我的代码分了三个部分:
- 第一部分:设置物理常量(波长、折射率、板间距、反射率数组);
- 第二部分:定义透射率函数,用向量化方式计算不同反射率下的透射率曲线;
- 第三部分:绘图,包括对比不同R的T-δ曲线,以及钠黄双线在特定R下的T-λ曲线。
这样模块清晰,后面想改参数也方便。
3. 完整Matlab代码与分步解读
3.1 可直接运行的完整代码
下面这版代码我在R2021a和R2023b上跑过,不需要额外工具箱,纯基础函数。代码里有注释,方便对着原理看。
%% 法布里-珀罗干涉仪仿真:不同反射率下的透射率曲线与钠黄双线分辨 clear; clc; close all; %% 1. 物理常量与参数设置 lambda1 = 589.0; % 钠黄双线 D1,单位 nm lambda2 = 589.6; % 钠黄双线 D2,单位 nm n = 1.0; % 空气折射率,平板两侧介质近似为空气 d = 1.0; % 平板间距,单位 mm(注意后面换算成 nm) d_nm = d * 1e6; % 1 mm = 1e6 nm theta = 0; % 正入射,cosθ = 1 % 反射率数组,用于对比图 R_list = [0.2, 0.6, 0.9, 0.98]; %% 2. 定义透射率函数(向量化写法) % 相位差 delta = 4*pi*n*d*cos(theta) / lambda % 注意 lambda 要传入 nm 单位,d 也要用 nm F_coeff = @(R) 4*R ./ (1-R).^2; T_func = @(delta, R) 1 ./ (1 + F_coeff(R) .* sin(delta/2).^2); %% 3. 图1:透射率随相位差变化(对比不同反射率) delta = linspace(0, 2*pi, 2001); % 一个周期,足够光滑 figure('Color','w', 'Position',[100 100 800 600]); hold on; colors = lines(length(R_list)); for i = 1:length(R_list) T = T_func(delta, R_list(i)); plot(delta*180/pi, T, 'LineWidth', 1.6, 'Color', colors(i,:), ... 'DisplayName', sprintf('R = %.2f, Finesse = %.1f', R_list(i), pi*sqrt(R_list(i))/(1-R_list(i)))); end hold off; xlabel('相位差 δ (度)'); ylabel('透射率 T'); ylim([0 1.05]); title('F-P平板透射率随相位差变化(不同反射率)'); legend('Location', 'northwest', 'FontSize', 9); grid on; set(gca, 'FontName', 'Times New Roman', 'FontSize', 12); %% 4. 图2:钠黄双线透射率随波长变化 % 选择两个反射率:R=0.6 时可能分辨不开,R=0.98 时可以分辨 lambda_axis = linspace(588.0, 590.6, 4001); % 波长范围覆盖双线 figure('Color','w', 'Position',[120 120 800 600]); for i = 1:length(R_list) % 计算每个波长的相位差 delta_lambda = 4*pi*n*d_nm*cos(theta) ./ lambda_axis; T_lambda = T_func(delta_lambda, R_list(i)); % 单独画一个子图,方便观察 subplot(2,2,i); plot(lambda_axis, T_lambda, 'LineWidth', 1.5, 'Color', colors(i,:)); xlabel('波长 (nm)'); ylabel('透射率 T'); ylim([0 1.05]); title(sprintf('R = %.2f', R_list(i))); grid on; xline(589.0, '--', 'D1', 'LabelVerticalAlignment','bottom'); xline(589.6, '--', 'D2', 'LabelVerticalAlignment','bottom'); set(gca, 'FontName', 'Times New Roman', 'FontSize', 10); end sgtitle('钠黄双线经F-P平板后的透射光谱');3.2 关键代码逐行拆解
第一段参数设置里,最容易踩的坑是单位换算。我把d写成1.0 mm,然后立刻用d_nm = d * 1e6转成纳米。因为波长用了纳米,相位差公式里所有长度必须一致。如果你写成d = 1.0后又直接除以lambda1(纳米),算出来会差10的6次方倍。
第二段里我用匿名函数定义了F_coeff和T_func,这是向量化写法的核心。F_coeff(R)把反射率R映射为精细度系数F,T_func(delta, R)直接返回透射率数组。注意sin(delta/2)前面用点乘.*,因为delta是数组,R是标量。Matlab里匿名函数可以直接捕获工作区的变量,这样T_func只用传delta和R两个参数就行,简洁很多。
绘图部分有两个细节值得提:第一个是画T-δ曲线时,我把横轴从弧度转成了角度(delta*180/pi),因为看书上的图时大家更习惯用角度或者π的倍数,转成角度后刻度更直观。第二个是画钠黄双线时,我用了xline函数来画竖直参考线,标出589.0和589.6的位置,这样能直接看出两个透射峰相对谱线的偏移。
3.3 为什么图2要分成四个子图
如果四个反射率画在同一张图里,R=0.2和R=0.98的曲线会“挤”在一起,R=0.2的透射峰宽到把相邻峰都盖住,根本看不出细节。分成四个子图,每个子图独立纵坐标和横坐标,反而能清楚看到R增大时透射峰从“胖墩”变成“细针”的过程。我特意把R=0.98放到最后一个子图,你会看到在589.0和589.6附近各出现一个极窄的尖峰,这就是分辨成功的画面。
4. 结果分析与物理图像验证
4.1 反射率对透射峰锐度的影响
运行代码后,第一张图上能看到四条周期曲线。R=0.2时,透射率在相位差0、2π处达到1,但其他地方没有压到很低,整个曲线看起来像一条平缓的山脉;R=0.6时,峰值依然为1,但峰底明显收窄;R=0.9时,峰已经变成竖起的“竹签”;R=0.98时,峰宽度肉眼几乎看不出起伏。这就是F-P干涉仪的精髓:反射率越高,腔内的有效反射次数越多,干涉效果越强,透射峰越尖锐。用精细度来衡量,R=0.98时精细度已经超过150,相当于相同自由光谱范围内能塞进去约150个分辨单元。
4.2 钠黄双线的分辨与瑞利判据
第二张图的结果更有意思。R=0.2时,589.0 nm和589.6 nm两个波长对应的透射峰几乎重叠成一个宽包,看不出双线;R=0.6时能看出主峰旁边有“鼓包”,但两个峰没有彻底分开;R=0.9时两个峰已经分离,中间有明显的凹陷;R=0.98时两个峰几乎变成两条竖线,完全分开。这个演化过程完美对应了光学书上讲的“要分辨波长差很小的两条谱线,必须提高反射率或增大板间距”。因为钠黄双线波长差固定,要分辨它,需要F-P的透射峰半宽小于两峰间距。半宽近似为:
Δλ_half ≈ λ² / (2π n d cosθ) · (1 - R) / √R
从公式可以看出,R越大,(1-R)/√R越小,半宽越窄,越容易分辨。同时,d越大,半宽也越小。这就是为什么高反射率和大腔长是提升光谱分辨率的两个主要手段。
4.3 与理论解析结果对照
你可以用代码里的参数手算一下自由光谱范围(FSR)。FSR是相邻两个干涉级对应的波长间隔,近似为:
FSR ≈ λ² / (2 n d cosθ)
正入射、n=1、d=1 mm、λ≈589.3 nm时,FSR约等于0.174 nm。这个值比钠黄双线的波长差0.6 nm要小!这说明两级干涉之间会出现更密的光谱结构,实际光谱上会看到多组双峰。不过在我们的波长扫描范围(588.0~590.6 nm)内,正好覆盖约15个FSR,所以子图里应该能看到很多尖峰。细看的话,每个FSR内都有一对靠近的峰,分别对应D1和D2。书上图4.7如果只画出其中一个级次附近的峰,那也是一样的道理。
这里顺便提醒一下:如果你希望只观察一对双峰,可以把d改小,比如设d = 0.1 mm,FSR变为约1.74 nm,这样就大于双线波长差0.6 nm,扫描宽度内出现的重复峰会少很多。实际做实验时往往也会调节腔长,使得FSR和待测谱线间隔匹配。
5. 常见问题与排查技巧实录
5.1 相位差算出来是天文数字,曲线全都重叠在一起
这是新手最容易出的问题。原因几乎都是单位混用。你如果d用毫米、波长用纳米,算出来的相位差会巨大,导致sin函数因为数值震荡产生随机数,画出来的图乱七八糟。解决办法是统一长度单位。我的习惯是:所有长度都用纳米,计算完相位差后如果需要打印,再换算成毫米或微米。可以在代码开头加一句断言,比如assert(d_nm > 0 && d_nm < 1e9),提醒自己数值数量级正常。
5.2 R特别接近1时,透射率尖峰出现“毛刺”或下溢
R=0.999时,(1-R)²在分母里会变得极小,T_func里的sin项稍有波动就会导致结果在0和1之间剧烈跳变。这并不是物理问题,而是数值精度问题。我建议在计算时不要用single类型,Matlab默认double就够了;另外横轴点数至少要2000个,否则峰太窄,采样点不够,画出来的峰高度不到1。如果点数增加到5000,尖峰依然很突兀,那说明确实是物理上峰太窄,这时候就该考虑缩小横轴范围,放大观察单个峰。
5.3 想画“书上那种在不同反射率下透射率随相位差变化的对比图”,但我的横轴不是0到2π
有的教材会把横轴画成相位差和π的比值,比如0、π、2π,有的画成角度0到360度,还有的画成条纹级次m。这些本质上都一样,你只需要把delta做线性变换即可。如果横轴是“相位差/π”,那么代码里的横轴就是delta/pi;如果是角度就是delta*180/pi。我自己习惯用角度,因为xlabel写“相位差(度)”更直观。
5.4 钠黄双线的两个峰分不开,怎么办
先别急着加反射率。分不开有两种可能:第一,反射率R太小,峰太宽,两峰叠在一起;第二,板间距d太小,导致两峰在波长轴上的间距不到一个峰的半宽。你可以先看FSR和双线波长差的关系:FSR必须大于双线间隔(至少两倍以上),否则不同级次的峰互相干扰。然后看精细度:精细度必须大于FSR/双线间隔。比如d=0.5 mm时,FSR约0.35 nm,双线间隔0.6 nm,FSR小于间隔,即使R=0.98也很难干净分辨。所以调试时优先调大d,再调大R。
5.5 绘图时如何让峰变得“又细又好看”
用plot画密集尖峰时,如果点数不够,峰顶会被削平。我的经验是:在需要重点观察的峰附近,把波长轴做成非均匀网格,中心区域用细网格,两侧用粗网格。不过这样代码复杂度高一点。简单做法是直接用linspace(588.0, 590.6, 8001),也就是8000个点,计算量不大,画出来已经很平滑。另外注意xline()在旧版Matlab里可能不支持,如果报错可以改成plot([589.0 589.0], [0 1.05], 'k--', 'LineWidth', 1)。
6. 从仿真到实验:一些个人体会
仿真跑到这一步,基本把F-P干涉仪最核心的透射特性和钠黄双线的分辨过程复现出来了。我自己做这套仿真的时候,最大的感受是:光学里的公式一定要带着单位去演算,尤其是纳米和毫米之间换算,错一位小数点,整个图像就会变成一坨乱码。相信跑完代码的读者,会对“反射率-精细度-分辨率”三者的关系有更直观的理解。
最后分享一个扩展玩法:你可以把波长轴固定为589.3 nm,横轴改成入射角θ,仿真不同角度下的透射率,这样就能模拟F-P干涉仪的等倾干涉条纹,是一圈一圈的同心环。再把反射率R和板间距d做成可拖动的UI控件,用Matlab的uifigure和slider,就能做一个小型交互式光学仿真演示工具,上课展示或者自己理解干涉现象都非常好用。代码我这边就不贴了,原理和上面的完全一样,只是把自变量换一下就行。希望这篇内容能帮你顺利跑通自己的F-P仿真,也欢迎在评论区交流你遇到的报错或者新的想法。
本文还有配套的精品资源,点击获取