黃信娥,劉夢禹,狄佳雨,錢磊
(天津科技大學,天津,300452)
光柵衍射不僅是波動光學的重點內容,而且是進一步學習激光醫學、全息學、通信學等專業領域知識的基礎0,在天文學、激光器、光通訊、信息存儲、新能源等現代光學乃至現代物理學和科學技術等諸多領域中具有廣泛的應用[2][3]。隨著國家政策對光學器件產業的支持,拓展光學儀器國際市場需求日益強烈。因此,掌握光柵衍射的基本原理對未來的生產實踐以及打破光領域科技壁壘意義非凡。
但光柵衍射的實驗操作不僅需要特定的儀器和場所,實驗現象也會受到許多非相關因素的影響。隨著計算機的日益普及,計算機仿真技術作為虛擬實驗已成為認識客觀世界規律的新型手段[4]。
目前大多數實驗室選擇的光學專業軟件為seelight、zemax 等,其容易受到操作平臺與軟件版本的限制,安裝時不得不考慮兼容性問題;而且大多數支持自主開發功能的仿真平臺受語言限制,如MATLAB App Designer 依賴于MATLAB 語言;一些獨立開發的光學仿真軟件存在未實現可見光漸變算法、未全面考慮衍射參數影響等缺陷。
因此針對以上不足,本文提出利用PythonGUI 編程設計仿真模擬程序,該語言的跨平臺性較高。利用QTDesigner 構件程序框架、設計圖像用戶界面,輕松實現了實驗數據的交互式顯示。
在構建物理實驗程序時,需要利用Python 的基本語法,調用PyQt5、Numpy、Matplotlib 等Python 提供的科學計算庫,以及使用PyQt5 自帶的QtDesigner 編輯器來輔助開發。
本文利用QtDesigner 進行排版,搭建程序UI 界面,并且自動生成代碼,搭建的程序UI 界面如圖1 所示。

圖1 程序UI 界面
保存該文件將會生成后綴為.ui 的文件,但如需生成后綴為.py的代碼頁,只需在上方工具欄的“窗體”中選擇“View Python Code”,保存即可。
程序界面如圖2 所示,需要創建以下控件并且綁定固定方法實現對應交互功能。

圖2 控件類型
(1)按鈕QPushButton
QPushButton 類是用來創建可按壓的按鈕,在程序中用來實現打開新窗口、切換模式等功能。

表1 QPushButton類按鈕及實現效果
(2)標簽QLabel
QLabel 類可以顯示讀取文字。

表2 QLabel類標簽及實現效果
(3)滾動數值條QSpinBox
QSpinBox 類用來顯示當前參數數值,不僅可以輸入值,還可以連續變化數值。

表3 QSpinBox類滾動條及實現效果
(4)表盤QDial
QDial 類可以創建一個旋鈕。QDial 和QSpinBox 功能基本一致,語法大體相同,但需要注意,同一個參數變化時,滾動數值條和表盤變化需一致,即改變滾動數值條數值時,表盤需變化到相應數值;改變表盤數值時,滾動數值條也需變化到相應數值。
在MainWindow 窗口類中書寫方法以實現該功能,代碼示例如下:
# 以spinbox 為例配置參數
self.spinbox_x = QSpinBox(self.centralwidget)
self.spinbox_x.setObjectName(u"spinbox_x")
self.spinbox_x.setMinimum(1)
self.spinbox_x.setMaximum(100)
self.spinbox_x.setSingleStep(1)
self.spinbox_x.setValue(10)
self.spinbox_x.setStyleSheet("background-color:#313034; color:white;border:2px solid" "#423f48;")
當表盤數值改變時,滾動數值條相應改變,并觸發相關函數。
①繪圖窗口MPLWIDGET。
②MPLWIDGET 窗口是自定義的類,利用該類實現用matplotlib 將光柵光譜圖和光強分布圖呈現出來。
③新建代碼頁mplwidget,在各個UI 代碼頁前加上from mplwidget import MPL_WIDGET,代碼如下:
# MPL_WIDGET
class MplCanvas(FigureCanvas):
def __init__(self, dpi=100):
self.fig = Figure(dpi=dpi)
self.ax = self.fig.add_subplot(211) FigureCanvas.__init__(self, self.fig)
FigureCanvas.setSizePolicy(
self, QSizePolicy.Expanding, QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
class MPL_WIDGET(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.canvas = MplCanvas()
self.navi_toolbar=NavigationToolbar(self.canvas, self)
self.navi_toolbar.setStyleSheet("backgroundcolor:white;")
self.vbl = QVBoxLayout()
self.vbl.addWidget(self.canvas)
self.vbl.addWidget(self.navi_toolbar)
self.setLayout(self.vbl)
該仿真模擬程序通過調用tkinter 庫實現界面交互,點擊主界面的切換按鈕,即可實現“主界面、Dsi&Ssd 界面和狹縫界面”這三種不同功能界面的切換。用戶在仿真不同的實驗時會顯示相應的參數設置控件,通過直接在交互界面的組合框內輸入或通過定位旋鈕設置參數范圍內的數值,便可實時動態地觀測光譜圖或光強分布圖的變化,從而定性分析各個物理量對光柵衍射實驗結果的影響。
當復色光照射時,不同波長所對應顏色的光的同一級亮線,除零級為白光外,其它均不重合,即有色散,此即為光柵的分光原理[5]。
多年來,許多研究者致力于發展升級實現光柵衍射色散的儀器,陳振宇等人[6]基于RPi 設計的可見光光譜儀能基本準確地表現光源的光譜特性,但由于該光譜儀分辨率有限,無法分辨出低壓鈉燈的雙波長。隨著計算機的發展,許多研究者開始利用仿真實驗模擬分光現象,但大部分作者[7][8]做出的光學圖像顏色單一,即入射特定波長的光沒有顏色漸變過程,實驗結果和視覺效果不佳。
本文以汞燈的主要光譜線波長為例,根據其波長與顏色的映射關系計算光強,得到衍射條紋[9]。在主界面開發模擬不同波長的單色光入射和可見光范圍內的連續復色光入射的功能,輔助研究色散和判斷影響色分辨率的因素。
利用 Python 語言可編寫出如下的可見光顏色漸變仿真程序:
# make_cmap
def cmap(self):
def getRGB(dWave, maxPix=1, gamma=1):
waveArea = [380, 440, 490, 510, 580, 645, 780]
minusWave = [0, 440, 440, 510, 510, 645, 780]
deltWave = [1, 60, 50, 20, 70, 65, 35]
for p in range(len(waveArea)):
if dWave < waveArea[p]: break
pVar = abs(minusWave[p] - dWave) / deltWave[p]
rgbs = [[0, 0, 0], [pVar, 0, 1], [0, pVar, 1], [0, 1, pVar],[pVar, 1, 0], [1, pVar, 0], [1, 0, 0], [0, 0, 0]]
if (dWave >= 380) & (dWave < 420):
alpha = 0.3 + 0.7 * (dWave - 380) / (420 - 380)
elif (dWave >= 420) & (dWave < 701):
alpha = 1.0
elif (dWave >= 701) & (dWave < 780):
alpha = 0.3 + 0.7 * (780 - dWave) / (780 - 700)
else:
alpha = 0
return [maxPix * (c * alpha) ** gamma for c in rgbs[p]]
def drawSpec():
pic = zeros([1, 361, 3])
rgb = [getRGB(d) for d in range(400, 761)]
pic = (pic + rgb)
plt.imshow(pic, aspect='auto')
plt.yticks([])
# plt.tick_params(axis='x',colors='w')
plt.xticks(range(0, 361, 50), ['400', '450', '500', '550', '600', '650', '700', '750'])
return pic
pic = drawSpec()
cdict = pic[0]
proj = dict()
for i in range(400, 761):
proj[i] = cdict[i - 400]
return proj
若把可調參數設置為狹縫總數N=10,遮光寬度b=15μm,透光寬度a=5μm,透鏡焦距f=40mm,分別仿真“入射波長為579nm 的單色光、同時入射波長為708nm 和579nm 的離散復色光、入射可見光范圍內的連續復色光”實驗,運行程序,即可得出如圖 3(a)~(b)所示的可見光顏色漸變仿真實驗結果。

圖 3 (a-b)見光顏色漸變仿真實驗結果
光柵是由大量等寬等間距的平行狹縫構成的具有納米
光柵衍射強度分布公式為:
其中,I0為單縫衍射零級處的衍射光強,
根據以上公式算法,利用 Python 語言可編寫出如下的仿真程序:
# 入射光數量
self.lamda = self.spinbox_l.value() * 1.E-6
# 透光寬度a um
self.a = self.spinbox_a.value() * 1.E-3
# 遮光寬度b um
# 屏幕寬度
self.s = self.spinbox_x.value()
# 狹縫數N
self.N = self.spinbox_n.value()
# 焦距f
self.f = 40
# 遮光寬度b um
self.b = self.spinbox_d.value() * 1.E-3
# 光柵常數 nm
self.d = (self.a + self.b)
"'邏輯計算"'
self.x = np.round(linspace(-self.s, self.s, 1000 * self.s), 3)
self.u = ((pi * self.a) / self.lamda) * (self.x / ((self.x ** 2 + self.f ** 2) ** 0.5))
self.I = (((sin(self.u) / self.u) ** 2) * ((sin(self.d * self.u * self.N / self.a) /
sin(self.d * self.u / self.a)) ** 2))
下面利用該程序從波長,狹縫總數,透光寬度,遮光寬度和缺級現象這5 個角度對光強分布和譜線特征進行全面地模擬仿真。
2.2.1 波長λ 對光柵衍射實驗結果的影響
實驗給定狹縫總數N=10,透光寬度a=5μm,遮光寬度b=15μm,圖樣寬度為10nm,透鏡焦距f=40mm,改變參數數值,使得依次入射波長為434nm,577nm,708nm的單色光。實驗結果如圖4 所示。

圖4 不同波長的光柵衍射圖樣
實驗結果為:光波長越長,各級條紋間距越寬,主(次)極大的半角寬度也越大。
2.2.2 狹縫總數對光柵衍射實驗結果的影響
實驗給定波長λ=546nm,透光寬度a=5μm,遮光寬度b=15μm,圖樣寬度為10nm,透鏡焦距f=40mm,改變狹縫總數,使得狹縫數目N=1,N=2,N=6,N=20。實驗結果如圖5 所示。

圖5 不同狹縫總數的光柵衍射圖樣
實驗結果為:當狹縫數目為1 時,形成單縫衍射;當狹縫數目為2 時,形成雙縫干涉。狹縫數目越多,主極大亮線的半角寬度越小,且銳度越大。次極大線寬和亮度變小。
2.2.3 透光寬度對光柵衍射實驗結果的影響
實驗給定狹縫總數N=10,波長λ=546nm,遮光寬度b=15μm,圖樣寬度為10nm,透鏡焦距f=40mm,改變透光寬度參數數值,使得透光寬度a=3μm,a=5μm,a=11μm。實驗結果如圖6 所示。

圖6 不同透光寬度的光柵衍射圖樣
實驗結果為:隨著各透光寬度a 的增加,中央明紋寬度減小,但并不改變明條紋所在位置,衍射效應變弱。
2.2.4 遮光寬度對光柵衍射實驗結果的影響
遮光寬度的大小與會直接影響到單縫衍射因子的變化,對多光束干涉條紋的強度起到了重要的調制作用。實驗給定狹縫總數N=10,波長λ=607nm,透光寬度a=5μm,圖樣寬度為10nm,透鏡焦距f=40mm,改變遮光寬度參數數值,使得遮光寬度b=5μm,b=15μm,b=18μm。實驗結果如圖7 所示。

圖7 不同遮光寬度的光柵衍射圖樣
實驗結果為:隨著各縫寬b 的增加,主極大的位置、半角寬度及主極大條紋的間距沒有發生變化,但是主極大的光強度逐漸降低。
2.2.5 缺級現象
當在θ 角位置既滿足干涉明條紋條件,也滿足單縫衍射暗紋條件時,出現光強度為零的“干涉加強”,此現象即為缺級現象[13]。實驗給定狹縫總數N=10,波長λ=607nm,圖樣寬度為15nm,透鏡焦距f=40mm。改變透光寬度和遮光寬度數值,使得光柵常數與透光寬度的比值為d/a=3,d/a=4,d/a=5。實驗結果如圖8 所示。

圖8 缺級現象
實驗結果為:圖8(a)的缺級現象出現在k 為3 的整數倍位置;圖8(b)的缺級現象出現在k 為4 的整數倍位置;圖8(c)的缺級現象出現在k 為5 的整數倍位置。
光柵衍射是縫間干涉和單縫衍射的綜合效應[14]。因此,程序設計了“Dsi&Ssd 界面”來展示基于在主界面操作下的光柵衍射實驗條件的單縫衍射因子和縫間干涉因子的相對光強圖。
利用 Python 語言可編寫出如下的單縫衍射和縫間干涉仿真程序:
lamda = self.lamda
a = self.a
s = self.s
f = self.f
b = self.b
d = self.d
N = self.N
x = np.round(linspace(-s, s, 1000 * s), 3)
# 繪圖
mpl2d = self.View_2.canvas
mpl2d.fig.clear()
mpl2d.fig.patch.set_facecolor('k')
"""邏輯計算"""
# 單縫衍射
u = ((pi * a) / lamda) * (x / ((x ** 2 + f ** 2) ** 0.5))
I_diff = (sin(u) / u)
** 2
# 多光干涉
A_x = 0
A_y = 0
for i in range(1, N):
A_x += cos((i - 1) * 2 * pi * d * (x / (f ** 2 + x ** 2) ** 0.5) / lamda)
A_y += sin((i - 1) * 2 * pi * d * (x / (f ** 2 + x ** 2) ** 0.5) / lamda)
I_int = A_x ** 2 + A_y ** 2
# 總光強
I = I_int * I_diff
# 單縫衍射
self.fig_1 = mpl2d.fig.add_subplot(2, 1, 1)
# self.fig_1.set_alpha(0.5)
self.fig_1.spines['right'].set_color('white')
self.fig_1.spines['top'].set_color('white')
self.fig_1.spines['bottom'].set_color('white')
self.fig_1.spines['left'].set_color('white')
self.fig_1.set_facecolor((37/255, 36/255, 36/255))
self.fig_1.plot(x, I_diff,color='w')
self.fig_1.set_xticks([])
self.fig_1.tick_params(axis='x', colors='w')
self.fig_1.tick_params(axis='y', colors='w')
# 縫間干涉
self.fig_2 = mpl2d.fig.add_subplot(2, 1, 2)
self.fig_2.set_facecolor((37/255, 36/255, 36/255))
self.fig_2.plot(x, I_int, color='w')
self.fig_2.spines['right'].set_color('white')
self.fig_2.spines['top'].set_color('white')
self.fig_2.spines['bottom'].set_color('white')
self.fig_2.spines['left'].set_color('white')
self.fig_2.tick_params(axis='x', colors='w')
self.fig_2.tick_params(axis='y', colors='w')
若在主界面把可調參設置為 N=10,b=15μm,a=5μm,λ=579nm,運行程序,模擬光柵衍射實驗。點擊“Dsi&Ssd”按鈕,切換界面,即可得到該實驗條件下如圖9 所示的單縫衍射因子和縫間干涉因子的相對光強圖。

圖9 單縫衍射因子和縫間干涉因子的相對光強圖
有研究表明有意改變光柵的刻槽間距(即選擇性地遮擋狹縫)和曲率以及基底面形,能提高光柵的分辨力和改善光學系統的成像的特性,并能節省輔助透鏡、減少雜散光、增加出射光強和提高光學系統的性能,使光路更為簡便[15~16]。因此程序在探究光柵狹縫總數對衍射圖樣影響的基礎上,設計了“探究遮擋不同位置的狹縫時對透射光強的影響”,為選擇性地遮擋狹縫提供實驗手段。
該實驗分為無規律遮擋和有規律遮擋兩大類。無規律遮擋包括隨機分布30%、隨機分布50%、隨機分布70%;有規律遮擋包括滿足間隙分布和斐波那契分布。通過對比遮擋前后的光強分布圖,可探究遮擋不同位置時狹縫對透射光強的影響。
該部分采用振幅矢量法和圖解法來完成光強分布的計算。如圖10 與圖11 所示,A1為在P 點產生的、振幅為A1和初相位為α的振幅矢量。假設各次波(Ai)到達P 點都有相同的振幅A,令A=1,相應的相位差以第一條光所在的方向為x 軸正方向建立坐標系,則第i 條光在x 方向的分量為:

圖10 光柵衍射原理圖

圖11 振幅矢量法
則第i 條光在y 方向的分量為:
光在x 方向和y 方向的分量之和分別為:
多光干涉光強為:
加入衍射的影響后光強為:
基于上述原理開發“狹縫界面”——“遮擋不同位置的狹縫對透射光強的影響”創新實驗,利用 Python 語言可編寫出如下仿真程序:
# 遮擋
A_xs = A_x
A_ys = A_y
if len(self.idset) != 0:
for i in self.idset:
i = 2 * i if i > 0 else -2 * i + 1
A_xs -= cos((i - 1)*2*pi*d*(x/(f**2+x**2)**0.5)/lamda)
A_ys -=sin((i-1)*2*pi*d*(x/(f**2+x**2)**0.5)/lamda)
I_ints = A_xs**2+A_ys**2
I_s=np.round(I_ints*I_diff, 3)
self.fig_2=mpl2d.fig.add_subplot(2, 1, 2)
self.fig_2.set_facecolor((37/255, 36/255, 36/255))
self.fig_2.plot(x, I_s,color='w')
self.fig_2.axis([-s, s, -1, 1.1*max(I)])
self.fig_2.spines['right'].set_color('white')
self.fig_2.spines['top'].set_color('white')
self.fig_2.spines['bottom'].set_color('white')
self.fig_2.spines['left'].set_color('white')
self.fig_2.tick_params(axis='x', colors='w')
self.fig_2.tick_params(axis='y', colors='w')
通過改變狹縫總數以及遮擋規律,可得到如圖12 所示的不同光強分布圖。

圖12 遮擋不同位置狹縫對透射光強的影響
應用該理論的聚焦和消像差性能對核心色散元件和聚焦元件的制作和研究具有一定的指導意義[17],并且在未來的空間光譜儀、等離子體診斷、同步輻射單色儀、光纖通信等領域的生產實踐中具有其獨特的應用價值[18~19]。
作為一款基于C/S 架構模式的軟件,PythonGUI 能良好地運行于多平臺中,如Unix、Windows 和Macintosh等等,程序最終通過軟件包安裝的方式集成到桌面上[20],具有操作容易、計算功能強大以及無延遲反應等優勢,有助于解決疫情背景下實驗條件受限的問題;該程序包含了較為完善的光柵衍射仿真模擬體系,有助于加強用戶對光柵衍射知識的理解,培養了自主研究的綜合創新能力,為推進創新實驗的設計開辟了新路徑。