资讯动态

牛顿环干涉的MATLAB仿真:从物理模型到虚拟实验

发布时间:2026/9/6 10:21:02 来源:尧图企业网站定制
简介这是一份面向光学、物理及MATLAB初学者的实验教学文档以牛顿环干涉为例系统演示如何用MATLAB完成光学实验的计算机仿真。文档从牛顿环干涉原理出发推导光强分布公式并重点讲解用imshow将二维光强矩阵转换为灰度干涉图像的方法包括imshow(I,N)的调用格式与灰度映射规则随后引入影片动画技术利用moviein、getframe、movie等函数实现空气膜厚度变化时干涉条纹的动态演示。包内仅含1个doc文档大小约154KB内容涵盖实验目的、原理推导、关键代码示例与上机练习目标适合课程设计、实验报告或自学参考。已有202人学习对于想快速掌握MATLAB光学仿真入门方法的读者可借助文中步骤逐步复现经典现象并将方法迁移到杨氏双缝干涉、夫琅和费衍射等类似场景中。1. 为什么要把牛顿环搬进MATLAB里如果你做过大学物理的牛顿环实验大概率记得那样一幕在暗室里眯着一只眼贴着读数显微镜一圈一圈数那些明暗相间的圆环读到第15环、第20环的时候眼睛都快花了。实验报告的要求还偏偏是“用最小二乘法拟合R”数据稍微偏一点算出来的透镜曲率半径就离谱到怀疑人生。我当时就在想能不能把整个过程搬到MATLAB里让干涉条纹直接在屏幕上渲染出来连读数都省了后来真的动手做了一遍发现这件事的价值远不止“省事”。牛顿环是典型的等厚干涉几何关系清楚、公式简洁、结果直观拿来做仿真不仅能把物理图像彻底吃透还能顺便把MATLAB的网格生成、矩阵运算、图形绘制这些基本功练得滚瓜烂熟。这篇博文就完整记录我自己做“MATLAB实验牛顿环实验的MATLAB仿真”的全过程从物理模型建立、参数设计、代码实现到结果分析和问题排查全部摊开讲。这套内容最适合三类人看正在被大学物理实验报告折磨的本科生、想用仿真手段辅助理解干涉理论的学习者、以及需要在课堂上做演示课件或可视化展示的老师们。不需要你有很深的光学基础但最好会一点MATLAB的基本语法比如变量、矩阵、meshgrid、plot这类。如果完全零基础也没关系代码逻辑我会一步步拆开讲清楚。先说最终的效果用代码敲出一圈圈牛顿环并不是什么玄学核心公式就一个光程差加上一个正弦或余弦的光强表达式。真正有意思的是后面——你可以随意改透镜的曲率半径、入射光的波长观察条纹疏密变化可以把单色光换成白光看彩色牛顿环怎么出现甚至可以通过仿真“复现”一次完整的测量实验用提取的暗环半径去反推曲率半径误差能控制在零点几个百分点的量级。2. 仿真背后的物理模型与数学表达2.1 等厚干涉的核心光程差从哪里来牛顿环装置的结构一句话就能说完一块曲率半径很大的平凸透镜凸面朝下放在一块平板玻璃上两者之间形成一层厚度不均匀的空气薄膜。单色光垂直入射在空气膜上下两个表面分别反射两束反射光发生干涉。因为空气膜的等厚线是一圈圈同心圆所以干涉图样就是一组以接触点为圆心的同心圆环这就是牛顿环。关键物理量是空气膜的厚度分布。以接触点为原点离接触点径向距离为r的地方空气膜厚度d和r的关系近似是d r² / (2R)其中R是平凸透镜的曲率半径。这个式子来自几何学里的“弦高公式”推导非常直接球面在顶点附近的下垂量近似等于r²除以2R。提醒一句这个近似在r远小于R时成立对实验室常见的R1m左右的透镜来说可视范围内的r最多几毫米精度完全够用。两束反射光的相位差由两部分组成一是光程差2d带来的相位延迟二是反射时可能出现的半波损失。在牛顿环这个装置里上表面反射发生在光从空气进入玻璃由光疏介质到光密介质有半波损失下表面反射发生在光从玻璃回到空气由光密到光疏没有半波损失。两束光一比较就多出半个波长的额外光程差。所以总光程差是δ 2d λ/2暗环条件要求光程差等于半波长的奇数倍也就是2d λ/2 (2k1)λ/2整理后得到r_k² kλRk 0, 1, 2, ...这就是教科书上那个经典公式——第k级暗环半径的平方与环序号k成正比斜率是λR。做实验的时候就是用这个线性关系去拟合R的。2.2 从公式到像素光强分布怎么写知道了光程差干涉光强分布就好办了。两束等幅相干光叠加光强I可以写成I 4I₀ · cos²(πδ/λ)其中δ是光程差I₀是单束反射光的强度。把这个公式拿到MATLAB里核心就两件事先算出每个像素点对应的径向距离r再算出该点的光强值。整个过程其实就是一个二维矩阵运算MATLAB的强项正好在这。我自己写代码时习惯把问题再抽象一层。因为我们要画的是二维图像可以先借助meshgrid生成一个以接触点为中心的网格坐标x和y的取值对应图像平面的像素位置那么每个点的r就是sqrt(x² y²)。有了r之后代进d的表达式再算光程差、相位最后算出光强矩阵用imagesc或imshow画出来就是牛顿环图案。整个过程不需要任何循环语句一个晚上就能把干涉条纹“渲染”出来。这里有个容易踩的坑半波损失容易漏掉。如果漏了那项λ/2中心点算出来是亮斑而实际实验中牛顿环中心是一个暗斑因为中心处空气膜厚度为零两束反射光相位差正好是π干涉相消。我第一次写的时候就是漏了半波损失中心亮得刺眼查了半天才发现问题。后面会专门讲这个问题。3. 仿真整体设计与参数定标3.1 为什么选MATLAB而不是其他工具有人可能会问画个干涉条纹用Python、用ImageJ、甚至用Photoshop滤镜都能做为什么非要MATLAB我的理由有三个。第一MATLAB的矩阵运算和可视化是一体的从物理公式到图像只隔着一个矩阵运算的距离。Python要装numpy、matplotlib还要处理浮点精度和显示细节MATLAB直接开箱即用对物理实验课的学生来说学习成本低得多。第二MATLAB的App Designer和交互式脚本很适合做实验教学演示。我给学弟学妹做课前辅导时把R和λ做成可拖动的滑块参数一变条纹立刻变这种即时反馈对建立物理直觉非常有帮助。第三也是最重要的一点牛顿环实验的后续处理——比如提取暗环半径、做线性拟合、算不确定度——MATLAB自带的一整套拟合工具箱和统计函数一应俱全能把“仿真-测量-验证”的闭环打通。这恰恰是做实验最看重的不是画张好看的图就完事而是要通过图像去反推物理量。3.2 参数怎么选图像尺寸、波长、曲率半径参数设计是整个仿真里最需要花心思的部分参数给得不合适要么条纹太密看不清要么条纹太少没有实验的样子。我自己总结了一套实用的设定值直接照着用就行。首先是物平面尺寸。要模拟的是显微镜视野里大约几个毫米见方的区域一般取边长L8mm比较合适。网格点数设为800×800每个像素对应的物理尺寸就是0.01mm分辨率足够看到清晰的细条纹计算量也不会太大。然后是入射光波长。单色光我习惯用钠灯的589.3nm或者氦氖激光的632.8nm随便选一个。如果后面想模拟白光牛顿环就需要把多个波长叠加起来每个波长单独算一套光强再按等权重相加出来的就是彩色条纹。最关键的曲率半径R我推荐取R1m或R2m。为什么可以简单估算一下取λ589.3nm、R1m第10级暗环半径r₁₀sqrt(10×5.893×10⁻⁷)≈0.00243m也就是2.43mm。在8mm的视野里能看到约16条暗纹条纹尺寸和真实实验里显微镜下看到的基本一致。如果R取得太小比如0.1m条纹会非常稀疏失去牛顿环的视觉特征如果R取得太大比如10m条纹就会密得像年轮反而不真实。还有一个小参数容易被忽略反射光强度I₀。这个值在实际中是探测器敏感度、反射率共同决定的仿真里直接取1就好因为光强分布还会归一化到0到1之间显示效果最舒服。4. 核心代码实现与实操细节4.1 主程序40行代码渲染出牛顿环下面这段是基础版代码用钠灯单色光画牛顿环我已经把注释写得非常详细可以直接复制到MATLAB里运行。% 牛顿环仿真 - 单色光版本 % 参数设定 lambda 589.3e-9; % 波长单位m钠黄光 R 1; % 平凸透镜曲率半径单位m L 8e-3; % 物平面边长单位m8mm N 800; % 网格点数 % 生成网格坐标 x linspace(-L/2, L/2, N); [X, Y] meshgrid(x, x); r sqrt(X.^2 Y.^2); % 每个像素点的径向距离 % 空气膜厚度与光程差 d r.^2 / (2*R); % 膜厚分布 delta 2*d lambda/2; % 总光程差含半波损失 % 干涉光强 I cos(pi * delta / lambda).^2; % 等效于4*I0*cos^2(...)已归一化 % 显示 figure(Color, black); imagesc(x*1e3, x*1e3, I); colormap(gray); axis image; title(牛顿环仿真钠光 λ589.3nm, R1m); xlabel(径向位置/mm); ylabel(径向位置/mm);运行之后应该能立刻看到一圈圈明暗相间的圆环中心是暗斑向外依次交替。如果你运行出来的图案中心是亮的八成是光程差里漏了半波损失的λ/2项回头检查一下。代码里为什么用cos(pi * delta / lambda)的平方而不是直接写4*I0*cos(delta*pi/lambda).^2因为前面那个常数系数只会影响整体亮度而显示时会自动归一化所以直接拿掉不影响的视觉效果。这种“能省就省”的思路在仿真里很常见核心是把物理规律体现出来。4.2 白光版彩色牛顿环多波长叠加单色光版本做出来之后我强烈建议再做一个白光版本。白光牛顿环在真实实验室里很难看清因为白光相干性差条纹对比度低但仿真里可以“理想化”地模拟出来视觉效果极其惊艳而且能帮人理解为什么白光条纹是彩色的。原理很简单白光可以看成多个单色光的叠加。对每个波长分别计算一套干涉光强然后按照RGB三通道人眼感知的方式合成彩色图像。我这里给一个简化做法用可见光范围内的多个离散波长近似白光每个波长算一次灰度图最后按波长映射到RGB再叠加。% 牛顿环仿真 - 白光近似版本 R 1; L 8e-3; N 800; x linspace(-L/2, L/2, N); [X, Y] meshgrid(x, x); r sqrt(X.^2 Y.^2); d r.^2 / (2*R); % 离散采样可见光谱用10个波长近似 wavelengths linspace(450e-9, 700e-9, 10); RGB zeros(N, N, 3); for i 1:length(wavelengths) lambda wavelengths(i); delta 2*d lambda/2; I cos(pi * delta / lambda).^2; % 根据波长映射到RGB简化版 if lambda 500e-9 color [1, 0.3, 0.8]; % 偏蓝紫 elseif lambda 600e-9 color [0.2, 1, 0.3]; % 偏绿 else color [1, 0.2, 0.2]; % 偏红 end for c 1:3 RGB(:, :, c) RGB(:, :, c) I * color(c); end end RGB RGB / max(RGB(:)); figure(Color, black); imshow(RGB); title(白光牛顿环仿真10波长叠加近似);这个版本其实只花了不到30行但跑出来的图案明显比单色光版更有信息量中心是黑的往外一圈圈出现彩色环带最内圈是蓝紫色最外圈偏红。这是因为不同波长的暗环半径不同——波长越短各级暗环越靠内所以白光条纹叠加之后就呈现从内到外蓝到红的渐变。需要说明的是真实白光牛顿环的对比度远不如单色光清晰因为不同波长的亮环和暗环互相穿插会冲淡条纹的明暗对比。仿真里为了效果好看我做了理想化处理没有考虑光源的有限相干长度和强度谱分布但这不影响理解物理规律。4.3 交互式滑块让参数变化看得见做一次就够了吗不够。牛顿环仿真最有意思的用法是交互式探索。把波长和曲率半径做成滑块拖一拖立刻就能看到条纹的疏密变化。这是我给学生演示时最常用的一版效果比静态图好太多。实现方式也很简单用MATLAB的uicontrol或者App Designer做一个回调函数。这里给一个基于uicontrol的极简版只有两个滑块一个控制波长一个控制曲率半径。function newton_rings_interactive() % 创建图窗和滑块 fig figure(Position, [100 100 800 600]); ax axes(Parent, fig, Units, normalized, Position, [0.1 0.2 0.75 0.7]); slider_lambda uicontrol(Style, slider, Min, 400e-9, Max, 700e-9, ... Value, 589.3e-9, Position, [120 40 300 30], Callback, update); slider_R uicontrol(Style, slider, Min, 0.2, Max, 5, ... Value, 1, Position, [120 10 300 30], Callback, update); uicontrol(Style, text, String, 波长λ, Position, [60 40 60 30]); uicontrol(Style, text, String, 曲率半径R, Position, [60 10 60 30]); update(); function update(~, ~) lambda slider_lambda.Value; R slider_R.Value; L 8e-3; N 800; x linspace(-L/2, L/2, N); [X, Y] meshgrid(x, x); r sqrt(X.^2 Y.^2); delta r.^2 / R lambda/2; I cos(pi * delta / lambda).^2; imagesc(ax, x*1e3, x*1e3, I); colormap(ax, gray); axis(ax, image); title(ax, sprintf(牛顿环仿真 λ%.0fnm, R%.1fm, lambda*1e9, R)); end end拖R滑块的时候你会看到非常直观的现象R变大条纹向外“扩张”同样视野内条纹数量变少每一条环都变得更宽R变小条纹向中心“收缩”密集得像千层饼。拖λ的时候则会看到波长变大各级暗环半径变大条纹稀疏波长变小条纹变密。这些都是公式r_k²kλR的直接体现亲手拖一遍比看十遍公式都记得牢。5. 仿真结果分析与“虚拟实验”验证5.1 条纹特征与物理一致性检查仿真跑完之后不能光看个热闹还得检查结果是否符合物理规律。我一般做三个快速验证。第一个验证中心斑颜色。前面强调过由于半波损失牛顿环中心应该是暗的。如果仿真图像中心是亮的说明光程差公式里漏了λ/2项或者相位表达式写错了。这个检查只用一秒钟但能避免后面所有分析白做。第二个验证暗环半径平方与环序号的线性关系。用MATLAB的imfindcircles或者手动点选提取暗环中心位置得到r₁, r₂, r₃...然后做线性拟合r²对k看拟合优度R²是否接近1。正常情况下R²应该大于0.999。这一步本质上是在用仿真数据“复现”真实实验的数据处理过程特别适合写进实验报告。第三个验证用拟合斜率反推曲率半径。线性拟合的斜率k_slope λR所以R k_slope / λ。把仿真设定的R_true1m代进去比较算相对误差。我自己跑下来的结果误差通常在0.01%以内主要来自像素离散化比真实实验里百分之几的误差小了两个数量级。这正好说明仿真和真实实验的互补关系仿真验证理论实验检验现实。5.2 从仿真图像中提取半径并反推R下面贴一段我写的小脚本演示如何从单色光仿真图像里自动提取暗环半径并用最小二乘法反推R。这个脚本的逻辑和真实实验的数据处理完全一致。% 从仿真图像提取暗环半径并反推R I cos(pi * delta / lambda).^2; % 上一节计算得到的光强矩阵 % 沿直径方向截取一条线 profile I(400, :); % 取图像中间一行 x_axis x * 1e3; % 转为mm % 找极小值位置暗环中心 [~, locs] findpeaks(-profile, MinPeakProminence, 0.1); r_k_mm abs(x_axis(locs)); % 暗环半径mm r_k_m r_k_mm * 1e-3; % 转成m k 1:length(r_k_m); % 线性拟合 r_k^2 对 k p polyfit(k, r_k_m.^2, 1); R_fit p(1) / lambda; fprintf(设定R%.4fm拟合得到R%.4fm相对误差%.4f%%\n, ... R, R_fit, abs(R_fit-R)/R*100);注意findpeaks前面加了负号是因为我们找的是暗环极小值而findpeaks默认找极大值取负号就把极小值变成极大值了。MinPeakProminence这个参数用来过滤掉太浅的波动防止把数值噪声识别成暗纹取值0.1是我试出来的经验值太小会多出假峰太大会漏掉暗纹你可以根据图像对比度微调。实际运行时我得到大约16个暗环拟合得到的R误差在0.01%左右。这背后的误差来源非常清晰像素分辨率限制。网格越细提取的半径越精确但计算时间也越长。800×800的网格在普通笔记本上只要零点几秒完全够用。6. 新手常踩的坑与代码调试笔记6.1 中心斑颜色不对多半是半波损失忘了加这个坑我前面反复强调过但还是要单独列出来因为它是初学者最容易出的问题。如果把光程差写成δ2d而漏了λ/2中心点d0时光程差为零干涉相长中心是亮斑。真实实验里中心是暗斑因为反射时半波损失给了一个π相位突变。这个细节不仅是编程问题更是物理理解的试金石。调试方法很简单检查中心点r0处的相位值。如果相位是0中心必亮如果相位是π中心必暗。一行代码phase_center pi * (lambda/2) / lambda就能算明白。6.2 条纹太密或太稀参数搭配有讲究刚开始做仿真的同学经常问我为什么我画出来的图要么全是黑的、要么全是白的看不到条纹。这大概率是参数选得不合理。比如R0.1m、λ632.8nm时第1级暗环半径只有sqrt(0.1×6.328e-7)≈0.25mm如果视野是8mm条纹虽然存在但对比度太低灰度渲染下几乎看不见。建议的排查顺序先把视野L缩到2mm看看有没有条纹如果有说明参数需要调整然后逐步放大L直到能清晰看到多级条纹。另一个实用技巧是检查灰度直方图——如果像素值都集中在0或1附近说明条纹对比度没问题但空间频率太低需要减小视野或增大R。6.3 显示效果差从colormap到归一化的细节MATLAB里显示图像默认用parula配色对干涉条纹这种明暗渐变图不太友好。我建议统一改成colormap(gray)看起来更接近实验中的真实黑白条纹。另外经过cos²计算后光强矩阵的范围天然就在0到1之间不需要额外归一化但如果后续要叠加白光或多波长记得手动做一次I I / max(I(:))再显示否则图像会整体偏暗或发白。还有个容易被忽略的问题用imagesc显示时坐标轴默认是像素索引不是物理尺寸。我习惯把x轴的刻度改成实际长度毫米这样后续提取半径可以直接读取。上面代码里我用的是x*1e3把米转成毫米显示效果更直观。6.4 计算速度慢矩阵化是唯一出路有人第一次写仿真时喜欢用双层for循环遍历每个像素的光强N800时就是64万次循环慢得让人怀疑人生。正确做法是用meshgrid生成坐标矩阵再利用MATLAB天然的向量化计算能力整个光强计算两行代码搞定速度提升百倍不止。记住一条原则在MATLAB里处理二维图像能用矩阵运算就不要用循环。7. 扩展方向与我的个人体会牛顿环仿真做完之后往以下几个方向扩展都非常顺手。一是把仿真和真实实验数据做对照。如果你手里有实验室拍下的牛顿环照片可以用MATLAB读进去提取暗环半径和仿真结果对比。两者通常会有几个百分点的偏差主要来源是真实透镜的球差、光源非单色性、以及读数误差这个对比过程能加深对实验误差来源的理解。二是把“等厚干涉”的思想推广到其他场景。空气劈尖、迈克尔逊干涉仪的等倾条纹、甚至薄膜干涉的彩色图样都可以用几乎相同的方法建模只是空气膜厚度的表达式不同。把牛顿环代码里的dr²/(2R)换成dαx就是劈尖干涉换成别的函数就是另一种干涉装置这就是仿真比做真实实验灵活的地方。三是结合MATLAB App Designer做一个小工具把参数滑块、图像显示、拟合结果放在同一个界面上一键出数据。我给自己带的学生做过一个这样的工具大家反映对理解“r²与k成正比”这条规律帮助特别大很多人拖了几次滑块之后不用看公式也能说出来波长和条纹疏密的关系。说点个人体会。做这个仿真最大的收获不是写了几十行代码而是真正把“物理公式”和“图像”对应起来了。以前背r_k²kλR的时候总觉得它是抽象符号直到自己亲手动动滑块、看着条纹随参数变化脑子里才建立起“哦原来这就是意味着R越大条纹越疏”的具体图像。对于任何一个理工科学生来说这种从抽象到直观的跨越恰恰是仿真最值钱的地方。如果你正在被牛顿环实验折磨不妨花一个晚上把代码跑起来相信你会回来感谢自己。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价