双缝干涉:把两条缝的图样叠起来,光为什么自己跟自己打架

举报
deli007 发表于 2026/09/29 14:12:19 2026/09/29
【摘要】 双缝干涉:把两条缝的图样叠起来,光为什么自己跟自己打架

一块挡板上开两条平行细缝,单色光打过去,屏幕上映出的不是两条亮线,而是一排等间距的明暗条纹。把其中一条缝遮住,条纹立刻消失、只剩一团中间亮两边暗的光斑——同一束光,只因「知道不知道它走了哪条缝」,结果就完全不同。

静态图讲不清两件事:条纹间距到底由什么决定?为什么挡住一条缝,条纹就没了? 所以我把它做成了一个能拖、能遮、能一颗一颗发射光子的网页:上半屏是俯视波浪场(两条缝当成两个同频点波源,实时叠加并着色),下半屏是屏上光强曲线 I(y)/I₀ 与光子累积点阵,右边一块数值面板把 ΔY 和 y₁/y₂/y₃ 算给你看。

几条关键信息先摆出来:

  • 源码:Demo Park 公开仓库 → https://atomgit.com/deli007/demo_park/tree/main/codearts-double-slit-lab,index.html 可直接下载
  • 生成物:单个 index.html(约 28 KB),纯前端、零依赖、不联网、不上传,全部计算在本地完成
  • 本地运行:双击文件即可;或 python -m http.server 8000
  • 本地验证:1920×1200 视口;默认 λ=550nm、d=0.30mm、L=1.50m 下 ΔY=2.750mm、y₁/y₂/y₃=2.750/5.500/8.250mm;自检 8/8 通过;连发 3600 颗光子后主峰落在 2.649mm,与理论 2.750mm 差 3.7%

它算的是理想化双缝。缝是无限细的抽象线(只有一个「缝间距 d」,没有缝宽对条纹的调制),光是标量波、没有偏振,也没有单光子探测器的计数噪声模型。下面会如实写它的边界。

图 1:默认参数(λ=550nm、d=0.30mm、L=1.50m)。上半屏两个点波源各自向外发圆波,叠加后往右拉出一束束射线状的加强/相消方向;右侧数值面板给出 ΔY=2.750mm、y₁=2.750mm;下半屏是 cos²(πdy/λL) 给出的等间距光强曲线

为什么值得看:两条缝的差别,全在一个相位差里

屏上某点 y 到底亮还是暗,只看两条缝过来的光差了多少路程。这个路程差 Δ 写成相位就是 φ = π·d·y / (λ·L)(d 是缝间距、L 是缝到屏的距离),两束光叠加后的相对光强是:

I(y)/I₀ = cos²(π·d·y / (λ·L))        光强
ΔY      = λ·L / d                     条纹间距
yₘ      = m·λ·L / d                   第 m 级亮纹位置
  • y=0(屏中心)处两条缝的路程完全相等,φ=0,cos²=1——所以中心永远是亮纹,不管参数怎么改;
  • 相邻亮纹之间相位正好涨 π,于是 y 走 λL/d 就又亮一次,这就是 ΔY;
  • ΔY 和 d 成反比:缝拉得越开、条纹越密;ΔY 和 λ、L 都成正比:波长越长、屏越远,条纹越宽。

页面里有三个实现决定值得说清楚:

  1. 波浪场和光强曲线共用同一套公式。 phaseRad() 把物理量统一换算成相位,Irel() 再取 cos²;波浪场那两个点源用的也是同一个随距离衰减的相位差。所以上图里加强的方向和下图曲线的高峰位置是对齐的,不是两张各画各的图。
  2. 光子落点是按 I(y) 的累积分布采样出来的。 makeSampler() 先把曲线在 [-Ymax, Ymax] 上离散成 3000 段的累积分布,再反解出落点。所以「一颗一颗发射」不会均匀乱撒,而是老老实实按亮纹概率多、暗纹概率少来落——累积久了就还原出条纹。
  3. 波长到颜色是一条真正的光谱映射。 wavelengthToRGB() 用分段线性插值算出 RGB(紫→蓝→绿→黄→红),再乘一个端部衰减因子压暗两端,而不是简单按色相环取色。

也说几处真实的边界:

  • 缝是理想细缝。真实双缝实验里缝宽决定了单缝衍射包络——条纹会被一个中间亮、两边递减的包络调制,所以远处的条纹会越来越暗。这里干涉项是纯 cos²,两侧条纹一样高(单缝模式下的包络是另一套 sinc² 公式)。
  • 光是标量波。没有偏振、没有光子的路径纠缠,屏幕亮度是概率意义上的,不是单个光子的轨迹。
  • 光点累积没有固定种子,用的是 Math.random();每次连发点阵都不一样,但直方图轮廓会稳定收敛到同一条 I(y) 曲线上。

任务描述

需求是直接粘进码道 Web 输入框的,原文如下:

开发一个单文件 index.html 的「双缝干涉实验室」网页应用,纯前端、零依赖、不联网、不上传任何数据。

画面分两块:
1) 上方是俯视波浪场:两条缝当作两个同频点波源,各自向右侧发出圆形波,叠加处按瞬时振幅着色(波峰偏暖色、波谷偏冷色),能直接看出加强区和相消区连成的射线状条纹。
2) 下方是观察屏上的光强分布图:横轴是屏上位置 y(单位毫米),纵轴是相对光强 I/I0,曲线随参数实时重画。

物理公式必须真算,不要假数据:
- 双缝干涉相对光强 I(y)/I0 = cos^2(pi * d * y / (lambda * L))
- 条纹间距 deltaY = lambda * L / d
- 第 m 级亮纹位置 y_m = m * lambda * L / d
- 波长到颜色用可见光谱近似映射(380nm 偏紫,450nm 蓝,520nm 绿,590nm 黄,620nm 橙,700nm 红)

交互:
- 波长滑杆 380~750 nm,默认 550
- 缝间距滑杆 0.10~1.00 mm,默认 0.30
- 屏距离滑杆 0.50~3.00 m,默认 1.50
- 每个滑杆旁边配一个数字输入框可以精确输入;输入为空、非数字或超出范围时,页面上要给出明确中文提示(说明合法范围),并且保留上一次的有效值继续显示,页面不能崩
- 「光点累积」模式:可以点「发射 1 颗光子」单发,也可以点「连发 300 颗」;每颗光子按 I(y) 归一化后的概率密度随机落在屏上,累积成点阵条纹;提供「清空」按钮把累积点清零
- 「挡住一条缝」开关:关掉其中一条缝后,波浪场只剩一个波源,光强曲线从等间距干涉条纹变成单缝衍射包络(中央最亮、两侧迅速衰减),用来对比「知道走了哪条缝,条纹就没了」;再打开恢复干涉条纹
- 右上角数值面板实时显示:当前波长对应颜色、条纹间距 deltaY(毫米)、中央到第 1/2/3 级亮纹的位置 y1/y2/y3(毫米)、以及当前参数下一条缝与另一条缝到屏中心的光程差

自检:放一个「运行自检」按钮,点下去跑 8 条数值断言并在页面上逐条显示通过/失败,最后显示「自检 8/8 通过」或列出失败条目。断言至少包含:I(0) 等于 I0;y = deltaY/2 处强度约等于 0;条纹间距与缝间距成反比;条纹间距与波长成正比;条纹间距与屏距离成正比;650nm 的条纹间距大于 450nm 的;屏中心永远是亮纹;光子累积直方图的峰位与理论 y_m 的相对误差小于 10%。

界面:深色、简洁、字号够大,画布随窗口自适应。完成后打开预览,让我直接看到运行效果。

码道 Web 交回的是单文件 index.html,自己起了内置预览。下面的数字全部来自我在本机浏览器里对这个文件的重跑,不是转述它的总结。

它实际长成了什么样:三个滑杆各拖一遍,ΔY 跟着怎么动

面板上默认参数是 λ=550nm、d=0.30mm、L=1.50m,它算出的 ΔY=2.750mm、y₁/y₂/y₃=2.750/5.500/8.250mm,屏中心光程差 0.0000mm。为了看清 ΔY 到底由谁决定,我把三个滑杆分别扫了一遍,每次都只动一个变量:

固定 变动 ΔY 实测 ΔY × 变量
d=0.30、L=1.50 λ=450nm 2.250 mm ΔY/λ = 0.00500
d=0.30、L=1.50 λ=550nm 2.750 mm ΔY/λ = 0.00500
d=0.30、L=1.50 λ=650nm 3.250 mm ΔY/λ = 0.00500
λ=550、L=1.50 d=0.10mm 8.250 mm ΔY·d = 0.825
λ=550、L=1.50 d=0.30mm 2.750 mm ΔY·d = 0.825
λ=550、L=1.50 d=0.45mm 1.833 mm ΔY·d = 0.825
λ=550、d=0.30 L=1.00m 1.833 mm ΔY/L = 1.833
λ=550、d=0.30 L=1.50m 2.750 mm ΔY/L = 1.833
λ=550、d=0.30 L=3.00m 5.500 mm ΔY/L = 1.833

三列比值全是常数,说明页面里 ΔY 确实严格正比于 λ 和 L、反比于 d,没有掺进别的因子。波长那一档最直观:450nm 的蓝光条纹最密,650nm 的红光最疏,同一个屏幕上条纹宽度差出 44%(2.250 → 3.250)。

光子累积那部分是这篇的主角。 连点 12 次「连发 300 颗」,累积到 3600 颗,屏幕上的点阵是这样的:

图 2:连发 3600 颗光子后的屏幕。白点是每颗光子的落点,它们自发聚成一束束与理论曲线高峰重合的点带;暗纹位置上基本没有点,只有零星几颗散布的噪声

  • 点阵主峰落在 2.649mm,理论 y₁=2.750mm,相对偏差 3.7%;
  • 3600 颗里有 1542 颗(42.8%) 落在 |y| < 1.5ΔY 的范围内,也就是被压进了中央那几条亮纹里;
  • 页面自检用 16000 颗光子重跑同一项,峰位 2.605mm、相对误差 5.29%——样本更多时峰位抖动量级就在几个百分点,这是蒙特卡洛的噪声底线,不是公式不准。

把一条缝挡住,条纹就没了。 打开「挡住一条缝(单缝模式)」开关后:波浪场只剩一个点源向外发散(另一条缝被标了红叉),屏上曲线从等间距的 cos² 换成单缝的 sinc² 包络——中央最高、往两侧迅速衰减,而且面板里 ΔY、y₁、y₂、y₃ 四格直接变成「—(单缝)」。

图 3:单缝模式。波浪场只剩上缝一个源,画面上另一条缝被标了红叉;屏上曲线从等间距条纹变成中央最亮的单缝衍射包络,面板里 ΔY 与 y₁/y₂/y₃ 全部显示「—(单缝)」

之所以会有这个对比:干涉条纹的前提是「不知道光子走的哪条缝」。两条缝都开着时,屏上每一点都是两条路径的叠加,相位差决定加减;一旦遮掉一条,只剩一条路径可走,就不存在「两条路径差多少」这件事,条纹自然消失。这也是量子力学里那句常被引用的话的直观版本。

踩坑与边界:四处真实的不一致

一、590nm 的颜色名字不是需求里说的「黄」。 我在需求里点名了「590nm 黄」,但页面把色名分成了 7 档:紫(<430)、蓝(430~479)、蓝绿(480~514)、绿(515~559)、黄绿(560~589)、橙(590~629)、红(≥630)。整套档位里没有单独的「黄」,590nm 正好落在「橙」档。实测 590nm 与 620nm 都是「橙」,560/570/580nm 都是「黄绿」。它的 RGB 插值其实是按物理分段来的(590nm 给的是偏黄橙的 r=1、g≈0.85),所以问题只出在色名的分档阈值上,不是颜色算错了。这提醒我:需求里点名的锚点,最好连「分几档、档位边界在哪」一起写清楚。

二、「必须是数字」这条提示,实际操作中走不到。 三个输入框都是 <input type="number">。浏览器不允许把 abc 这类文本写进 number 输入框的 value——脚本里赋值后读回来已经是空字符串,所以页面永远命中「不能为空」那条分支,而不是「必须是数字」。我实测:给 d 填 abc,提示是「缝间距 d不能为空,请输入 0.1 ~ 1 之间的数字(单位 mm)。已恢复上次有效值。」,和真的留空完全一样。三条校验分支写得很全,但其中一条被输入框类型挡在了更前面。

三、错误提示 5 秒后自动消失。 showErr() 里挂了一个 5 秒的 setTimeout 把提示清空,而输入框和滑杆已经立刻回退到旧值。所以填错之后如果没马上看,画面上只会看到「数值没变」,看不到任何解释——想核对提示原文得赶在 5 秒内,或者再填一次。这个是设计选择(提示不长期占位),但它让「页面给出明确提示」这件事变得有时效性。

四、切到单缝模式后,数值面板有几格变空。 需求写的是「数值面板实时显示 ΔY 和 y₁/y₂/y₃」,而单缝模式下这四格显示的是「—(单缝)」。从物理上讲这是对的(单缝没有干涉条纹间距),但严格对照需求就是「有 4 格不再是数值」。

顺带一个没踩到的点: 我本来担心「连发 300 颗」点太快会让累积超过上限,实测光子有硬上限 5000 颗,到了会提示「已达上限 5000 颗,请清空后再发射。」,不会越界也不会卡死。

自检 8/8,但自检不能当验收

点「运行自检」,8 条断言我本机重跑的原文(面板逐条列出)是:

自检 8/8 通过 ✅
✓ 通过:I(0) 恒等于 I₀            屏中心相对光强 = cos²(0) = 1
✓ 通过:y = ΔY/2 处强度 ≈ 0       半条纹间距处相位差为 π,cos²(π/2)=0;I(1.375mm)=2.59e-32
✓ 通过:条纹间距与缝间距成反比     ΔY·d 为常数:0.825000 = 0.825000
✓ 通过:条纹间距与波长成正比       ΔY/λ 为常数:0.005000000 ≈ 0.005000000
✓ 通过:条纹间距与屏距离成正比     ΔY/L 为常数:1.833333 = 1.833333
✓ 通过:650nm 的条纹间距 > 450nm 的 ΔY(650nm)=3.2500mm > ΔY(450nm)=2.2500mm
✓ 通过:屏中心永远是亮纹           对多组参数 I(0)=1(含单缝模式)
✓ 通过:光子累积峰位与理论 y₁ 误差 < 10%  实测峰位 2.605mm,理论 ΔY=2.750mm,相对误差 5.29%

八条覆盖了「中心恒亮」「半间距处相消」「ΔY 与三个变量的比例关系」「颜色对应的单调性」「光子分布收敛」。但它验的是公式和采样的自洽性,不验画面:曲线画没画对、纹理对不对、单缝包络长得对不对,这些它一句都没查——图上那两种情况(图 2 的点阵聚束、图 3 的包络切换)是我自己一张张看出来的。

图 4:点「运行自检」,8 条断言分两列列出、全部打勾,每条后面带着实测数字(I(1.375mm)=2.59e-32、ΔY·d=0.825000、光子峰位 2.605mm 相对误差 5.29%)

失败路径写得不错,但提示是短暂出现的,三种非法输入的实际提示原文如下:

输入 提示原文
缝间距填 2 缝间距 d超出范围:2mm。合法范围:0.1 ~ 1 mm,已恢复上次有效值。
屏距离填 0.2 屏距离 L超出范围:0.2m。合法范围:0.5 ~ 3 m,已恢复上次有效值。
波长留空 波长 λ不能为空,请输入 380 ~ 750 之间的数字(单位 nm)。已恢复上次有效值。

三种都回退了上一次的有效值(550/0.30/1.50),页面继续正常显示,没有白屏。

图 5:失败路径。三个输入框先后填了空值、越界值,于是三条中文红字提示同时挂在各自控件下面;输入框已经回退到 550 / 0.30 / 1.50,画面照常运行

准备环境:进入码道 Web

浏览器打开码道 Web 版:https://devcloud.cn-north-4.huaweicloud.com/chat?source=dmzntgwsf&sourcead=dmzntgwwbwz,登录后就能在对话窗口输入需求,不需要装软件。

码道有三种使用方式:WebUI(浏览器对话)、TUI(终端命令行)和桌面 IDE(IDE 插件)。本文用 WebUI 版演示。

本地复现

生成物只有一个 index.html,复现没有依赖:

  1. 从 Demo Park 本案例目录下载 index.html。
  2. 双击打开。默认 λ=550nm、d=0.30mm、L=1.50m,上半屏立刻能看到两个波源叠出的射线状条纹。
  3. 想走静态服务也行:python -m http.server 8000,然后访问 http://localhost:8000。
  4. 把窗口拉到一个较大的视口(我用的是 1920×1200),两块画布都会跟着窗口自适应重画。

下面这些数是我本地逐条跑出来的,都能自己复验:

  1. 画布:视口 1920×1200 时波浪场画布 1302×552、光强画布 1302×444,都随窗口宽度自适应。
  2. 默认参数:ΔY=2.750mm,y₁=2.750mm、y₂=5.500mm、y₃=8.250mm,屏中心光程差 0.0000mm。
  3. 三组扫描:ΔY/λ=0.00500(450/550/650nm)、ΔY·d=0.825(0.10/0.30/0.45mm)、ΔY/L=1.833(1.00/1.50/3.00m),各自都是常数。
  4. 光子累积:3600 颗时主峰 2.649mm(理论 2.750mm,偏差 3.7%),其中 42.8% 落在 |y|<1.5ΔY 内。
  5. 单缝模式:波浪场只剩一个波源,曲线换成 sinc² 包络,ΔY 与 y₁/y₂/y₃ 显示「—(单缝)」。
  6. 自检:点「运行自检」8/8 通过,每条都带实测数字。
  7. 非法输入:越界 / 空值都给出中文提示并回退旧值,不白屏。

使用码道体会

  • 把公式三件套都写进需求。 我在需求里同时给了 I(y)/I₀、ΔY、yₘ 三个公式和各自的单位,它交回来的页面就有了「曲线 + 面板数字 + 自检断言」三层互相印证的东西。只写「做一个双缝干涉动画」,很可能只会得到好看的波纹,量不出 ΔY。
  • 要求它把关键中间量摆出来。 「数值面板实时显示 ΔY 和 y₁/y₂/y₃」这一条回报最大:上面那张扫描表我一次都没用计算器——改一个滑杆、读一次面板,三次就够看出比例关系。
  • 物理量之间的比例关系,交给它做成断言。 需求里的 8 条自检断言(反比、正比、单调、中心恒亮)不是随便写的,它把「公式对不对」变成了「点一下就能看的勾」,我才敢在文章里直接引用后续测量的数字。
  • 没写进需求的分档细节,它就自己定一套。 颜色那条我只给了 6 个锚点(380 紫 / 450 蓝 / 520 绿 / 590 黄 / 620 橙 / 700 红),没有给分档边界,于是它把「黄绿」当一档、让 590nm 落进了「橙」。锚点写清楚,档位边界也得写清楚。
  • 验收要自己动手。 自检 8/8 全绿,但它验的是公式自洽,没验画面;点阵有没有真的聚成条纹、单缝包络有没有真的切过去,都是我自己看图确认的。Agent 说完成不算验收。

亲手点三下

页面打开就能验,三下够了:

  1. 看条纹间距:把「波长 λ」滑杆从 380 慢慢推到 750,盯住面板里的 ΔY 和屏上的曲线。曲线会跟着疏密变化,ΔY 从 1.900mm 一路涨到 3.750mm;换成推「缝间距 d」,方向正好相反——d 越大条纹越密。
  2. 看条纹消失:把「挡住一条缝(单缝模式)」开关打开,上半屏的波浪场会从两个源变成一个源,下半屏的曲线从等间距条纹变成中间高两边低的包络,面板里 ΔY 那几格变成「—(单缝)」;再关掉开关,条纹原样回来。
  3. 看失败路径:在「缝间距 d」的数字框里填 2 回车,必须看到一行中文红字提示、输入框退回 0.30、页面不白屏;再把「波长 λ」清空回车,提示会换成「不能为空」那一条。

直接下载试玩

总结

把双缝干涉做成能拖的页面之后,最值得记住的不是那排条纹,而是「挡住一条缝」那一下:条纹之所以存在,靠的是两条路径的相位差——把其中一条断掉,屏上每一点就只剩一个来源,装不出来干涉。所以条纹不是光照出来的花纹,而是「同一个光子有两条路可走」的直接后果;ΔY = λL/d 只是这件事在几何上的刻度。想接着玩,可以试试把缝间距 d 拉到最小(0.10mm)看条纹宽到只剩一两条、把 L 推到 3m 看条纹被拉得多开,或者在单缝模式下把波长换成 380nm,看单缝包络的中心亮斑是怎么收窄的。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。