numpy数组的精度变化?

时间:2017-05-02 18:26:16

标签: python arrays numpy precision

我一直致力于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()

enter image description here

0 个答案:

没有答案