sfstoolbox/sfs-python

Division by zero in NFC-HOA 2.5D plane driving function

hagenw opened this issue · 3 comments

Start with these settings

X = [-1.75, 1.75]
Y = [-1.75, 1.75]
Z = 0
nk = [0, -1, 0]
omega = 2 * np.pi * 1000
R0 = 1.5

First, try this one, this should still work:

>>> x0, n0, a0 = sfs.array.circular(100, R0)
>>> d = sfs.mono.drivingfunction.nfchoa_25d_plane(omega, x0, R0, nk)

Now increase the number of secondary sources and we will get a division by zero:

>>> x0, n0, a0 = sfs.array.circular(1000, R0)
>>> d = sfs.mono.drivingfunction.nfchoa_25d_plane(omega, x0, R0, nk)
/home/hagen/git/sfs-python/sfs/mono/drivingfunction.py:229: RuntimeWarning: divide by zero encountered in true_divide
  a = 1 / _sph_hn2(M, k * r0)
/home/hagen/git/sfs-python/sfs/mono/drivingfunction.py:229: RuntimeWarning: invalid value encountered in true_divide
  a = 1 / _sph_hn2(M, k * r0)

The number of secondary sources (times 0.5) is used as maximum modal order.
The imaginary part of the Hankel-function blows up.
For values larger than double precision range, sph_jnyn seems to return 0.

Maybe it is then a good idea to check if this always happens for the same maximum modal order and add a warning or better error message to the code.

From what I've gathered:

sph_jnyn is deprecated in scipy 0.18.0
The new spherical_yn properly returns -inf for the blown-up Neumann function.

Unfortunately, this does not solve the problem:

In Matlab, large orders are fail-safe because "division by blown-up Hankel yields 0" works.
This does not seem to be the case with Python's complex type, e.g.:

Matlab: a*(x + 1j*inf) = (a*x + 1j*inf)

Python: a*(x + 1j*inf) = (nan + 1j*inf)

Bottom line:
A reasonable maximum order should be used.