Source code for spharpy.spatial.spatial

import numpy as np
import scipy.spatial as sspat
from spharpy._deprecation import convert_coordinates


[docs] def greens_function_plane_wave( source_points, receiver_points, wave_number, gradient=False): """The matrix describing the propagation of a plane wave from a direction of arrival defined by the azimuth and elevation angles of the source points to the receiver points. The phase sign convention reflects a direction of arrival from the source position. Parameters ---------- source_points : :class:`spharpy.samplings.Coordinates`, :doc:`pf.Coordinates <pyfar:classes/pyfar.coordinates>` The source points defining the direction of incidence for the plane wave. Note that the radius on which the source is positioned has no relevance. receiver_points : :class:`spharpy.samplings.Coordinates`, :doc:`pf.Coordinates <pyfar:classes/pyfar.coordinates>` The receiver points. wave_number : double The wave number of the wave speed_of_sound : double The speed of sound gradient : bool If True, the gradient will be returned as well Returns ------- M : ndarray, complex, shape(n_receiver, n_sources) The plane wave propagation matrix """ # noqa: 501 source_points = convert_coordinates(source_points) receiver_points = convert_coordinates(receiver_points) e_doa = source_points.cartesian / \ np.linalg.norm(source_points.cartesian, axis=0) k_vec = np.squeeze(wave_number*e_doa) # avoid using the complex exponential since it's slower than sin and cos arg = receiver_points.cartesian.T @ k_vec plane_wave_matrix = np.cos(arg) + 1j*np.sin(arg) if not gradient: return plane_wave_matrix else: plane_wave_gradient_matrix_x = (plane_wave_matrix * 1j*k_vec[0]) plane_wave_gradient_matrix_y = (plane_wave_matrix * 1j*k_vec[1]) plane_wave_gradient_matrix_z = (plane_wave_matrix * 1j*k_vec[2]) return plane_wave_matrix, \ [plane_wave_gradient_matrix_x, plane_wave_gradient_matrix_y, plane_wave_gradient_matrix_z]
[docs] def greens_function_point_source(sources, receivers, k, gradient=False): r"""Green's function for point sources in free space in matrix form. The phase sign convention corresponds to a direction of propagation away from the source at position $r_s$. .. math:: G(k) = \\frac{e^{- k\\|\\mathbf{r_s} - \\mathbf{r_r}\\|}} {4 \\pi \\|\\mathbf{r_s} - \\mathbf{r_r}\\|} Parameters ---------- source : :class:`spharpy.samplings.Coordinates`, :doc:`pf.Coordinates <pyfar:classes/pyfar.coordinates>` source points as Coordinates object receivers : :class:`spharpy.samplings.Coordinates`, :doc:`pf.Coordinates <pyfar:classes/pyfar.coordinates>` receiver points as Coordinates object k : ndarray, double wave number Returns ------- G : ndarray, double Green's function """ # noqa: 501 sources = convert_coordinates(sources) receivers = convert_coordinates(receivers) dist = sspat.distance.cdist(receivers.cartesian.T, sources.cartesian.T) dist = np.squeeze(dist) cexp = np.cos(k*dist) - 1j*np.sin(k*dist) G = cexp/dist/4/np.pi if not gradient: return G else: def lambda_cdiff(u, v): return u-v diff_x = sspat.distance.cdist( np.atleast_2d(receivers.x).T, np.atleast_2d(sources.x).T, lambda_cdiff) diff_y = sspat.distance.cdist( np.atleast_2d(receivers.y).T, np.atleast_2d(sources.y).T, lambda_cdiff) diff_z = sspat.distance.cdist( np.atleast_2d(receivers.z).T, np.atleast_2d(sources.z).T, lambda_cdiff) G_dx = G/dist * np.squeeze(diff_x) * (-1j-1/dist) G_dy = G/dist * np.squeeze(diff_y) * (-1j-1/dist) G_dz = G/dist * np.squeeze(diff_z) * (-1j-1/dist) return G, (G_dx, G_dy, G_dz)