Source code for spharpy.interpolate
"""Interpolation module for spherical data."""
from scipy import interpolate as spinterpolate
import numpy as np
[docs]
class SmoothSphereBivariateSpline(spinterpolate.SmoothSphereBivariateSpline):
"""Smooth bivariate spline approximation in spherical coordinates.
The implementation uses the method proposed by Dierckx [#]_.
Parameters
----------
sampling : :py:class:`pyfar.Coordinates`
Coordinates object containing the positions for which the data
is sampled
data : array, float
Array containing the data at the sampling positions. Has to be
real-valued.
w : array, float
Weighting coefficients. The default is ``None``, which sets the
weighting coefficients to ``1``.
s : float, 1e-4
Smoothing factor > 0
Positive smoothing factor defined for estimation condition:
``sum((w(i)*(r(i) - s(theta(i), phi(i))))**2, axis=0) <= s``
Default ``s=len(w)`` which should be a good value if ``1/w[i]`` is
an estimate of the standard deviation of ``r[i]``. The default
value is ``1e-4``
eps : float, 1e-16
Sets the threshold used to determine the effective rank of the
underlying linear system of equations. Values smaller than this
threshold are treated as zero during the fitting process.
Depends on the used data type and numerical precision. The default
is ``1e-16``.
Note
----
This is a wrapper for scipy's SmoothSphereBivariateSpline only using
Coordinates objects as container for the azimuth and elevation angles.
For detailed information see scipy's documentation.
References
----------
.. [#] P. Dierckx, “Algorithms for smoothing data on the sphere with
tensor product splines,” p. 24, 1984.
Examples
--------
>>> n_max = 10
>>> sampling = spharpy.samplings.equalarea(
... n_max, n_points=500, condition_num=np.inf)
>>> Y = spharpy.spherical.spherical_harmonic_basis_real(n_max, sampling)
>>> y_vec = spharpy.spherical.spherical_harmonic_basis_real(
... n_max, Coordinates(1, 0, 0))
>>> data = Y @ y_vec.T
>>> data = np.sin(sampling.elevation)*np.sin(2*sampling.azimuth)
>>> interp_grid = spharpy.samplings.hyperinterpolation(35)
>>> data_grid = np.sin(interp_grid.elevation)*np.sin(2*interp_grid.azimuth)
>>> interpolator = interpolate.SmoothSphereBivariateSpline(
... sampling, data, s=1e-4)
...
>>> interp_data = interpolator(interp_grid)
""" # noqa: 501
def __init__(self, sampling, data, w=None, s=1e-4, eps=1e-16):
theta = sampling.colatitude
phi = sampling.azimuth
if np.any(np.iscomplex(data)):
raise ValueError("Complex data is not supported.")
super().__init__(theta, phi, data, w, s, eps)
[docs]
def __call__(self, interp_grid, dtheta=0, dphi=0):
"""Evaluate the spline on a new sampling grid.
Parameters
----------
interp_grid : :py:class:`pyfar.Coordinates`
Coordinates object containing a new set of points for which data
is to be interpolated.
dtheta : int, optional
Order of theta derivative. Default is ``0``.
dphi : int, optional
Order of phi derivative. Default is ``0``.
""" # noqa: 501
theta = interp_grid.colatitude
phi = interp_grid.azimuth
return super().__call__(
theta, phi, dtheta=dtheta, dphi=dphi, grid=False)
[docs]
def get_coeffs(self):
"""Get the coefficients of the spline.
Returns
-------
coeffs : ndarray, float
The coefficients of the spline. The shape is
(n_coeffs_theta, n_coeffs_phi, n_coefficients).
The coefficients are ordered by increasing degree and order.
"""
return super().get_coeffs()
[docs]
def get_knots(self):
"""Get the knots of the spline.
Returns
-------
knots : tuple of ndarray, float
The knots of the spline. The first element is the knots in theta
direction and the second element is the knots in phi direction.
"""
return super().get_knots()
[docs]
def get_residual(self):
"""Get the residual of the spline.
Returns
-------
residual : float
The residual of the spline, which is the sum of squared errors
between the data and the spline evaluation.
"""
return super().get_residual()