基于Python 的光栅衍射仿真模拟

2023-04-13 02:02黄信娥刘梦禹狄佳雨钱磊
电子制作 2023年4期
关键词:光栅波长宽度

黄信娥,刘梦禹,狄佳雨,钱磊

(天津科技大学,天津,300452)

0 引言

光栅衍射不仅是波动光学的重点内容,而且是进一步学习激光医学、全息学、通信学等专业领域知识的基础0,在天文学、激光器、光通讯、信息存储、新能源等现代光学乃至现代物理学和科学技术等诸多领域中具有广泛的应用[2][3]。随着国家政策对光学器件产业的支持,拓展光学仪器国际市场需求日益强烈。因此,掌握光栅衍射的基本原理对未来的生产实践以及打破光领域科技壁垒意义非凡。

但光栅衍射的实验操作不仅需要特定的仪器和场所,实验现象也会受到许多非相关因素的影响。随着计算机的日益普及,计算机仿真技术作为虚拟实验已成为认识客观世界规律的新型手段[4]。

目前大多数实验室选择的光学专业软件为seelight、zemax 等,其容易受到操作平台与软件版本的限制,安装时不得不考虑兼容性问题;而且大多数支持自主开发功能的仿真平台受语言限制,如MATLAB App Designer 依赖于MATLAB 语言;一些独立开发的光学仿真软件存在未实现可见光渐变算法、未全面考虑衍射参数影响等缺陷。

因此针对以上不足,本文提出利用PythonGUI 编程设计仿真模拟程序,该语言的跨平台性较高。利用QTDesigner 构件程序框架、设计图像用户界面,轻松实现了实验数据的交互式显示。

1 程序框架构建

1.1 编程基础与导入库

在构建物理实验程序时,需要利用Python 的基本语法,调用PyQt5、Numpy、Matplotlib 等Python 提供的科学计算库,以及使用PyQt5 自带的QtDesigner 编辑器来辅助开发。

本文利用QtDesigner 进行排版,搭建程序UI 界面,并且自动生成代码,搭建的程序UI 界面如图1 所示。

图1 程序UI 界面

保存该文件将会生成后缀为.ui 的文件,但如需生成后缀为.py的代码页,只需在上方工具栏的“窗体”中选择“View Python Code”,保存即可。

1.2 控件定义与方法

程序界面如图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)

2 功能实现

该仿真模拟程序通过调用tkinter 库实现界面交互,点击主界面的切换按钮,即可实现“主界面、Dsi&Ssd 界面和狭缝界面”这三种不同功能界面的切换。用户在仿真不同的实验时会显示相应的参数设置控件,通过直接在交互界面的组合框内输入或通过定位旋钮设置参数范围内的数值,便可实时动态地观测光谱图或光强分布图的变化,从而定性分析各个物理量对光栅衍射实验结果的影响。

2.1 可见光颜色渐变仿真

当复色光照射时,不同波长所对应颜色的光的同一级亮线,除零级为白光外,其它均不重合,即有色散,此即为光栅的分光原理[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)见光颜色渐变仿真实验结果

2.2 光栅衍射仿真

光栅是由大量等宽等间距的平行狭缝构成的具有纳米

光栅衍射强度分布公式为:

其中,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 的整数倍位置。

2.3 单缝衍射和缝间干涉仿真

光栅衍射是缝间干涉和单缝衍射的综合效应[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 单缝衍射因子和缝间干涉因子的相对光强图

3 创新实验设计

有研究表明有意改变光栅的刻槽间距(即选择性地遮挡狭缝)和曲率以及基底面形,能提高光栅的分辨力和改善光学系统的成像的特性,并能节省辅助透镜、减少杂散光、增加出射光强和提高光学系统的性能,使光路更为简便[15~16]。因此程序在探究光栅狭缝总数对衍射图样影响的基础上,设计了“探究遮挡不同位置的狭缝时对透射光强的影响”,为选择性地遮挡狭缝提供实验手段。

该实验分为无规律遮挡和有规律遮挡两大类。无规律遮挡包括随机分布30%、随机分布50%、随机分布70%;有规律遮挡包括满足间隙分布和斐波那契分布。通过对比遮挡前后的光强分布图,可探究遮挡不同位置时狭缝对透射光强的影响。

3.1 实验原理

该部分采用振幅矢量法和图解法来完成光强分布的计算。如图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')

3.2 仿真结果

通过改变狭缝总数以及遮挡规律,可得到如图12 所示的不同光强分布图。

图12 遮挡不同位置狭缝对透射光强的影响

应用该理论的聚焦和消像差性能对核心色散元件和聚焦元件的制作和研究具有一定的指导意义[17],并且在未来的空间光谱仪、等离子体诊断、同步辐射单色仪、光纤通信等领域的生产实践中具有其独特的应用价值[18~19]。

4 结束语

作为一款基于C/S 架构模式的软件,PythonGUI 能良好地运行于多平台中,如Unix、Windows 和Macintosh等等,程序最终通过软件包安装的方式集成到桌面上[20],具有操作容易、计算功能强大以及无延迟反应等优势,有助于解决疫情背景下实验条件受限的问题;该程序包含了较为完善的光栅衍射仿真模拟体系,有助于加强用户对光栅衍射知识的理解,培养了自主研究的综合创新能力,为推进创新实验的设计开辟了新路径。

猜你喜欢
光栅波长宽度
HPLC-PDA双波长法同时测定四季草片中没食子酸和槲皮苷的含量
双波长激光治疗慢性牙周炎的疗效观察
CDIO教学模式在超声光栅实验教学中的实践
日本研发出可完全覆盖可见光波长的LED光源
基于LabView的光栅衍射虚拟实验研究
红细胞分布宽度与血栓的关系
便携式多用途光波波长测量仪
孩子成长中,对宽度的追求更重要
光栅衍射实验教学中的体会
用实函数直接计算光栅衍射的光强分布