我一直致力于Mie散射粒子。其背后的理论在这里并不重要,但计算确实涉及估计Riccati-Bessel部分的重现。我最初是通过"蛮力"逐步通过各种粒度的方法,以及相应的贝塞尔函数递归。这需要很长时间(但有效),所以我尝试使用数组进行优化。令人惊讶的是,阵列方法甚至没有接近正确的输出。我唯一能想到的是数组并不像更简单的逐点方法那样精确(这没有意义,但我能想到的就是这一点)。
差异可以在下面发布的代码创建的图中看到。任何人都可以肯定地说这是一个聚合的舍入误差,还是还有其他需要考虑的因素?我看到我的代码中没有错误,但这并不意味着错误就在那里!
import numpy as np
import pylab as pl
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# BRUTE FORCE (STEP-BY-STEP) METHOD
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# user-defined parameters
N1 = complex(4 / 3, 1E-8) # refractive index of particle
Nair = complex(1, 0) # refractive index of air
wl = 0.500 # wavelength of light (microns)
i = complex(0, 1) # complex number (root of -1)
m = N1 / Nair # ratio of refractive indices
r = [0.250] # particle radius (microns)
alpha = 2 * np.pi * r[0] / wl # size parameter
max_iterations = 20 # maximum number of iterations
y = alpha * m
# define initial recurrence value for zeta
zeta_minus1 = np.cos(alpha) - i * np.sin(alpha)
A = np.zeros((max_iterations, 1), dtype=complex)
zeta = np.zeros((max_iterations, 1), dtype=complex)
an = np.zeros((max_iterations, 1), dtype=complex)
bn = np.zeros((max_iterations, 1), dtype=complex)
# calculate Qext, Qsca, A and zeta by recurrence
A[0] = np.cos(y) / np.sin(y)
zeta[0] = np.sin(alpha) + i * np.cos(alpha)
# calculate initial an and bn
n = 0
an_upper = (A[n] / m + n / alpha) * zeta[n].real - zeta_minus1.real
an_lower = (A[n] / m + n / alpha) * zeta[n] - zeta_minus1
an[n] = an_upper / an_lower
bn_upper = (A[n] * m + n / alpha) * zeta[n].real - zeta_minus1.real
bn_lower = (A[n] * m + n / alpha) * zeta[n] - zeta_minus1
bn[n] = bn_upper / bn_lower
for n in np.arange(1, max_iterations):
A[n] = (-n / y) + (n / y - A[n - 1])**-1
zeta[n] = (2 * n - 1) / alpha
if n == 1:
zeta[n] = zeta[n] * zeta[n - 1] - zeta_minus1
else:
zeta[n] = zeta[n] * zeta[n - 1] - zeta[n - 2]
# calculate an and bn
an_upper = (A[n] / m + n / alpha) * zeta[n].real - zeta[n - 1].real
an_lower = (A[n] / m + n / alpha) * zeta[n] - zeta[n - 1]
an[n] = an_upper / an_lower
bn_upper = (A[n] * m + n / alpha) * zeta[n].real - zeta[n - 1].real
bn_lower = (A[n] * m + n / alpha) * zeta[n] - zeta[n - 1]
bn[n] = bn_upper / bn_lower
an_bruteforce = an.real.copy()
bn_bruteforce = bn.real.copy()
数组/基质方法
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# ARRAY/MATRIX METHOD
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# user-defined parameters
N1 = complex(4 / 3, 1E-8) # refractive index of particle
Nair = complex(1, 0) # refractive index of air
wl = 0.500 # wavelength of light (microns)
i = complex(0, 1) # complex number (root of -1)
m = N1 / Nair # ratio of refractive indices
r = np.array([0.250]) # particle radius (microns)
alpha = 2 * np.pi * r / wl # size parameter
max_iterations = 20 # maximum number of iterations
y = alpha * m
# pre-allocate arrays
A = np.zeros((alpha.shape[0], max_iterations), dtype=np.complex)
zeta = np.zeros((alpha.shape[0], max_iterations), dtype=np.complex)
an = np.zeros((alpha.shape[0], max_iterations), dtype=np.complex)
bn = np.zeros((alpha.shape[0], max_iterations), dtype=np.complex)
# define initial values for Riccati-Bessel functions
zeta_minus1 = np.cos(alpha) - i * np.sin(alpha)
n = 1
A[:, 0] = np.cos(y) / np.sin(y)
A[:, n] = (-n / y) + (n / y - A[:, n - 1])**-1
zeta[:, 0] = np.sin(alpha) + i * np.cos(alpha)
zeta[:, n] = ((2 * n - 1) / alpha) * zeta[:, n - 1] - zeta_minus1
# define initial values for an and bn matrices since the next "for" loop starts
# iterating on 2
an_upper = (A[:, 0] / m) * zeta[:, 0].real - zeta_minus1.real
an_lower = (A[:, 0] / m) * zeta[:, 0] - zeta_minus1
bn_upper = (A[:, 0] * m) * zeta[:, 0].real - zeta_minus1.real
bn_lower = (A[:, 0] * m) * zeta[:, 0] - zeta_minus1
an[:, 0] = an_upper / an_lower
bn[:, 0] = bn_upper / bn_lower
# now for n=1
an_upper = (A[:, 1] / m) * zeta[:, 1].real - zeta[:, 0].real
an_lower = (A[:, 1] / m) * zeta[:, 1] - zeta[:, 0]
bn_upper = (A[:, 1] * m) * zeta[:, 1].real - zeta[:, 0].real
bn_lower = (A[:, 1] * m) * zeta[:, 1] - zeta[:, 0]
an[:, 1] = an_upper / an_lower
bn[:, 1] = bn_upper / bn_lower
# calculate zeta, A, an, and bn via recurrence
for n in range(2, max_iterations):
zeta[:, n] = ((2 * n - 1) / alpha) * (zeta[:, n - 1] - zeta[:, n - 2])
A[:, n] = (-n / y) + (n / y - A[:, n - 1])**(-1)
an_upper = (A[:, n] / m) * zeta[:, n].real - zeta[:, n - 1].real
an_lower = (A[:, n] / m) * zeta[:, n] - zeta[:, n - 1]
bn_upper = (A[:, n] * m) * zeta[:, n].real - zeta[:, n - 1].real
bn_lower = (A[:, n] * m) * zeta[:, n] - zeta[:, n - 1]
an[:, n] = an_upper / an_lower
bn[:, n] = bn_upper / bn_lower
an_array = an.real.copy()
bn_array = bn.real.copy()
作图
pl.close('all')
fig = pl.figure(figsize=(5, 5))
ax0 = fig.add_subplot(111)
x = np.arange(20)[np.newaxis, :]
ax0.plot(x[0], an_bruteforce[:, 0] - an_array[0], 'k')
ax0.plot(x[0], bn_bruteforce[:, 0] - bn_array[0], 'r')
ax0.set_ylabel('Brute - Array', fontsize=10)
ax0.set_xlabel('Iteration', fontsize=10)
ax0.legend(('a$_n$', 'b$_n$'), fontsize=10, fancybox=True)
fig.show()