我编写了以下代码来绘制出光学元件的光强度,它基本上是入射场上的球面傅立叶积分,因此它具有贝塞尔函数。其参数取决于积分变量(x
)和绘图变量(r
)。
from sympy import *
import matplotlib.pyplot as plt
import numpy as np
from scipy.integrate import quad
from scipy.special import jn
#constants
mm = 1
um = 1e-3 * mm
nm = 1e-6 * mm
wavelength = 532*nm
klaser = 2*np.pi / wavelength
waist = 3.2*mm
angle = 2 #degrees
focus = 125 * mm
ng = 1.5 # refractive index of axicon
upperintegration = 5
#integrals
def b(angle):
radians = angle* np.pi/180
return klaser * (ng-1) * np.tan(radians)
def delta(angle):
return np.pi/(b(angle)*waist)
def integrand(x, r):
return klaser/focus * waist**2 * np.exp(-x**2) * np.exp(-np.pi * 1j * x/delta(angle)) * jn(0, waist*klaser*r*x/focus) * x
def intensity1D(r):
return np.sqrt(quad(lambda x: np.real(integrand(x, r)), 0, upperintegration)[0]**2 + quad(lambda x: np.imag(integrand(x, r)), 0, upperintegration)[0]**2)
fig = plt.figure()
ax = fig.add_subplot(111)
t = np.linspace(-3.5, 3.5, 25)
plt.plot(t, np.vectorize(intensity1D)(t))
问题在于,当我绘制时,当我更改我在linspace
中使用的点数时,情节会发生剧烈变化。
我怀疑这可能是因为积分的振荡性质,所以所采用的步长可以极大地改变指数的值,从而改变积分的值。
quad
如何处理这个问题?是否有更好的方法可以在数字上集成这个特定的应用程序?
答案 0 :(得分:2)
在对quad
的调用中,将limit
参数设置为较大的数字。这增加了quad
允许用于估计积分的最大子区间数。当我使用
def intensity1D(r):
re = quad(lambda x: np.real(integrand(x, r)), 0, upperintegration, limit=8000)[0]
im = quad(lambda x: np.imag(integrand(x, r)), 0, upperintegration, limit=8000)[0]
return np.sqrt(re**2 + im**2)
并使用定义为
的数组t
计算函数
t = np.linspace(1.5, 3, 1000)
我得到以下情节:
(我也删除了行from sympy import *
。sympy
似乎没有被使用
你的剧本。)
您应该始终检查作为quad
的第二个返回值的错误估计值。
例如:
In [14]: r = 3.0
In [15]: val, err = quad(lambda x: np.real(integrand(x, r)), 0, upperintegration, limit=8000)
In [16]: val
Out[16]: 2.975500141416676e-11
In [17]: err
Out[17]: 1.4590630152807049e-08
如您所见,误差估计远大于近似积分。 quad
返回的估算可能是保守的,但是如此大的误差估计结果仍应谨慎对待。我们来看看相应的虚部:
In [25]: val, err = quad(lambda x: np.imag(integrand(x, r)), 0, upperintegration, limit=8000)
In [26]: val
Out[26]: 0.0026492702707317257
In [27]: err
Out[27]: 1.4808416189183e-08
val
现在比估计的误差大几个数量级。因此,当在intensity1D()
中计算复数值的大小时,我们最终会得到大约1e-5的估计相对误差。这可能足以进行计算。
在r = 2.1825附近的峰值处,误差估计的幅度仍然很小,并且 小于计算的积分:
In [32]: r = 2.1825
In [33]: quad(lambda x: np.real(integrand(x, r)), 0, upperintegration, limit=8000)
Out[33]: (6.435730031424414, 8.801375195176556e-08)
In [34]: quad(lambda x: np.imag(integrand(x, r)), 0, upperintegration, limit=8000)
Out[34]: (-6.583055286038913, 9.211333259956749e-08)