PASCO的实体实验效果不是很理想,和仿真差别还挺大的,可惜时间不太够没有深究实体实验不成功的原因(下图为实体实验结果图,氦的原子光谱,标注的是红外光)。
实验仿真程序原理其实和迈克尔逊干涉仪的仿真差别不大,其中做了一些适当的简化,并不影响最后的实验结果:认为总光强是不同波长的光衍射后光强的叠加;不同波长的光入射前光强相等(其实是我没有查到相关数据。。。。原谅我还没开始学原子物理学)。
仿真代码如下:
from tkinter import *
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import matplotlib as mpl
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
import numpy as np
class GratingSpectrometerSimulation:
def __init__(self):
self.window = Tk()
self.window.title("光栅光谱仪实验仿真")
self.window.geometry("1500x750")
self.window.resizable(False, False)
self.fig = Figure()
self.image = self.fig.add_subplot()
self.image.set_title('The Experimental Result')
self.fig_frame = Frame(self.window, width=500, height=500)
self.fig_frame.place(x=20, y=150)
self.canvas = FigureCanvasTkAgg(self.fig, self.fig_frame)
self.canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=YES)
self.toolbar = NavigationToolbar2Tk(self.canvas, self.fig_frame, pack_toolbar=False)
self.toolbar.update()
self.toolbar.pack(side=RIGHT)
plt.ion() # Open the interactive mode.
mpl.use('TkAgg') # Tkinter & matplotlib linker.
self.window.bind('<ButtonRelease>', self.SettingsChange)
self.slit_width_doublevar = DoubleVar()
self.slit_width = 0.0002
self.grating_constant_intvar = IntVar()
self.grating_constant = 1 / 600
self.grating_N_intvar = IntVar()
self.grating_N = 20
self.current_element = ''
self.I = np.zeros(314000)
self.button = {'H': Button(self.window, text='氢', activebackground='red', font=('', 20),
command=self.SetElementH, relief=RAISED, height=2, width=4),
'He': Button(self.window, text='氦', activebackground='red', font=('', 20),
command=self.SetElementHe, relief=RAISED, height=2, width=4),
'Ne': Button(self.window, text='氖', activebackground='red', font=('', 20),
command=self.SetElementNe, relief=RAISED, height=2, width=4),
'Hg': Button(self.window, text='汞', activebackground='red', font=('', 20),
command=self.SetElementHg, relief=RAISED, height=2, width=4)
}
self.button['H'].place(x=300, y=20)
self.button['He'].place(x=380, y=20)
self.button['Ne'].place(x=460, y=20)
self.button['Hg'].place(x=540, y=20)
self.scale = [Scale(), Scale(), Scale()]
self.scale[0] = Scale(self.window, length=400, orient=HORIZONTAL, activebackground='red', from_=1, to=400,
digits=3, resolution=1, label='光栅总缝数N', variable=self.grating_N_intvar)
self.scale[0].set(20)
self.scale[0].place(x=750, y=20)
self.scale[1] = Scale(self.window, length=400, orient=HORIZONTAL, activebackground='red', from_=10, to=1000,
digits=4, resolution=10, label='光栅每mm缝数', variable=self.grating_constant_intvar)
self.scale[1].set(600)
self.scale[1].place(x=750, y=100)
self.scale[2] = Scale(self.window, length=396, orient=HORIZONTAL, activebackground='red', from_=0.01, to=0.99,
digits=2, resolution=0.01, label='光栅缝宽占比', variable=self.slit_width_doublevar)
self.scale[2].set(0.12)
self.scale[2].place(x=750, y=180)
self.label = [Label(), Label(), Label()]
self.label_ = Label(self.window, text="请选择实验用灯:", font=("", 20))
self.label_.place(x=20, y=30)
self.label[0] = Label(self.window, text="光栅缝数:{:.0f}".format(self.grating_N), font=("", 20))
self.label[0].place(x=1200, y=50)
self.label[1] = Label(self.window, text="光栅常量:{:.5f}".format(self.grating_constant) + 'mm', font=("", 20))
self.label[1].place(x=1200, y=130)
self.label[2] = Label(self.window, text="光栅缝宽:{:.5f}".format(self.slit_width) + 'mm', font=("", 20))
self.label[2].place(x=1200, y=210)
self.element_wavelength = {'H': [397.01, 410.17, 434.05, 486.13, 656.28],
'He': [388.87, 402.62, 447.15, 471.31, 492.19, 501.57, 587.56, 667.82, 706.52],
'Ne': [585.25, 588.19, 614.31, 621.73, 626.65, 638.30, 640.23, 650.65],
'Hg': [404.66, 435.83, 491.60, 546.07, 576.96, 579.07, 623.44]}
def SetElementH(self):
self.current_element = 'H'
self.ImageRefresh()
def SetElementHe(self):
self.current_element = 'He'
self.ImageRefresh()
def SetElementNe(self):
self.current_element = 'Ne'
self.ImageRefresh()
def SetElementHg(self):
self.current_element = 'Hg'
self.ImageRefresh()
def SettingsChange(self, event):
self.grating_N = self.grating_N_intvar.get()
self.grating_constant = 1.0 / self.grating_constant_intvar.get()
self.slit_width = self.slit_width_doublevar.get() * self.grating_constant
self.label[0].config(text="光栅缝数:{:.0f}".format(self.grating_N))
self.label[1].config(text="光栅常量:{:.5f}".format(self.grating_constant) + 'mm')
self.label[2].config(text="光栅缝宽:{:.5f}".format(self.slit_width) + 'mm')
if self.current_element != '' and not (20 < event.x < 620 and 150 < event.y < 750):
self.ImageRefresh()
def ImageRefresh(self):
self.image.cla()
self.I = np.zeros(314000)
theta = np.linspace(-1.7, 1.7, 314000)
for wave_length in self.element_wavelength[self.current_element]:
alpha = np.pi * self.grating_constant * np.sin(theta) / wave_length * 1000000
beta = np.pi * self.slit_width * np.sin(theta) / wave_length * 1000000
self.I += (np.sinc(beta) ** 2) * ((np.sin(self.grating_N * alpha) / np.sin(alpha)) ** 2)
self.image.set_title('The Experimental Result of ' + self.current_element)
self.image.set_xlim(-np.pi / 2, np.pi / 2)
self.image.set_xlabel('Angle/rad')
self.image.set_ylabel('Relative Light Intensity')
self.image.set_xticks([-np.pi / 2, -np.pi / 3, -np.pi / 6, 0, np.pi / 6, np.pi / 3, np.pi / 2])
self.image.plot(theta, self.I)
self.fig.canvas.draw()
def Run(self):
self.window.mainloop()
window = GratingSpectrometerSimulation()
window.Run()
运行结果图: