def point_25d(omega, x0, n0, xs, *, xref=[0, 0, 0], c=None): r"""Driving function for 2.5-dimensional SDM for a virtual point source. Parameters ---------- omega : float Angular frequency of point source. x0 : (N, 3) array_like Sequence of secondary source positions. n0 : (N, 3) array_like Sequence of normal vectors of secondary sources. xs: (3,) array_like Position of virtual point source. xref : (3,) array_like, optional Reference point for synthesized sound field. c : float, optional Speed of sound. Returns ------- d : (N,) numpy.ndarray Complex weights of secondary sources. selection : (N,) numpy.ndarray Boolean array containing ``True`` or ``False`` depending on whether the corresponding secondary source is "active" or not. secondary_source_function : callable A function that can be used to create the sound field of a single secondary source. See `sfs.fd.synthesize()`. Notes ----- The secondary sources have to be located on the x-axis (y0=0). Driving function from :cite:`Spors2010`, Eq.(24). Examples -------- .. plot:: :context: close-figs d, selection, secondary_source = sfs.fd.sdm.point_25d( omega, array.x, array.n, xs, xref=[0, -1, 0]) plot(d, selection, secondary_source) """ x0 = _util.asarray_of_rows(x0) n0 = _util.asarray_of_rows(n0) xs = _util.asarray_1d(xs) xref = _util.asarray_1d(xref) k = _util.wavenumber(omega, c) ds = x0 - xs r = _np.linalg.norm(ds, axis=1) d = 1/2 * 1j * k * _np.sqrt(xref[1] / (xref[1] - xs[1])) * \ xs[1] / r * _hankel2(1, k * r) selection = _util.source_selection_all(len(x0)) return d, selection, _secondary_source_point(omega, c)
def line_2d(omega, x0, n0, xs, *, c=None): r"""Driving function for 2-dimensional WFS for a virtual line source. Parameters ---------- omega : float Angular frequency of line source. x0 : (N, 3) array_like Sequence of secondary source positions. n0 : (N, 3) array_like Sequence of normal vectors of secondary sources. xs : (3,) array_like Position of virtual line source. c : float, optional Speed of sound. Returns ------- d : (N,) numpy.ndarray Complex weights of secondary sources. selection : (N,) numpy.ndarray Boolean array containing ``True`` or ``False`` depending on whether the corresponding secondary source is "active" or not. secondary_source_function : callable A function that can be used to create the sound field of a single secondary source. See `sfs.fd.synthesize()`. Notes ----- .. math:: D(\x_0,\w) = \frac{\i}{2} \wc \frac{\scalarprod{\x-\x_0}{\n_0}}{|\x-\x_\text{s}|} \Hankel{2}{1}{\wc|\x-\x_\text{s}|} Examples -------- .. plot:: :context: close-figs d, selection, secondary_source = sfs.fd.wfs.line_2d( omega, array.x, array.n, xs) plot(d, selection, secondary_source) """ x0 = _util.asarray_of_rows(x0) n0 = _util.asarray_of_rows(n0) xs = _util.asarray_1d(xs) k = _util.wavenumber(omega, c) ds = x0 - xs r = _np.linalg.norm(ds, axis=1) d = -1j/2 * k * _inner1d(ds, n0) / r * _hankel2(1, k * r) selection = _util.source_selection_line(n0, x0, xs) return d, selection, _secondary_source_line(omega, c)
def line_2d(omega, x0, n0, xs, *, c=None): r"""Driving function for 2-dimensional WFS for a virtual line source. Parameters ---------- omega : float Angular frequency of line source. x0 : (N, 3) array_like Sequence of secondary source positions. n0 : (N, 3) array_like Sequence of normal vectors of secondary sources. xs : (3,) array_like Position of virtual line source. c : float, optional Speed of sound. Returns ------- d : (N,) numpy.ndarray Complex weights of secondary sources. selection : (N,) numpy.ndarray Boolean array containing ``True`` or ``False`` depending on whether the corresponding secondary source is "active" or not. secondary_source_function : callable A function that can be used to create the sound field of a single secondary source. See `sfs.fd.synthesize()`. Notes ----- .. math:: D(\x_0,\w) = \frac{\i}{2} \wc \frac{\scalarprod{\x-\x_0}{\n_0}}{|\x-\x_\text{s}|} \Hankel{2}{1}{\wc|\x-\x_\text{s}|} Examples -------- .. plot:: :context: close-figs d, selection, secondary_source = sfs.fd.wfs.line_2d( omega, array.x, array.n, xs) plot(d, selection, secondary_source) """ x0 = _util.asarray_of_rows(x0) n0 = _util.asarray_of_rows(n0) xs = _util.asarray_1d(xs) k = _util.wavenumber(omega, c) ds = x0 - xs r = _np.linalg.norm(ds, axis=1) d = -1j / 2 * k * _inner1d(ds, n0) / r * _hankel2(1, k * r) selection = _util.source_selection_line(n0, x0, xs) return d, selection, _secondary_source_line(omega, c)
def plane_25d(omega, x0, n0, n=[0, 1, 0], *, xref=[0, 0, 0], c=None): r"""Driving function for 2.5-dimensional SDM for a virtual plane wave. Parameters ---------- omega : float Angular frequency of plane wave. x0 : (N, 3) array_like Sequence of secondary source positions. n0 : (N, 3) array_like Sequence of normal vectors of secondary sources. n: (3,) array_like, optional Normal vector (traveling direction) of plane wave. xref : (3,) array_like, optional Reference point for synthesized sound field. c : float, optional Speed of sound. Returns ------- d : (N,) numpy.ndarray Complex weights of secondary sources. selection : (N,) numpy.ndarray Boolean array containing ``True`` or ``False`` depending on whether the corresponding secondary source is "active" or not. secondary_source_function : callable A function that can be used to create the sound field of a single secondary source. See `sfs.fd.synthesize()`. Notes ----- The secondary sources have to be located on the x-axis (y0=0). Eq.(3.79) from :cite:`Ahrens2012`. Examples -------- .. plot:: :context: close-figs d, selection, secondary_source = sfs.fd.sdm.plane_25d( omega, array.x, array.n, npw, xref=[0, -1, 0]) plot(d, selection, secondary_source) """ x0 = _util.asarray_of_rows(x0) n0 = _util.asarray_of_rows(n0) n = _util.normalize_vector(n) xref = _util.asarray_1d(xref) k = _util.wavenumber(omega, c) d = 4j * _np.exp(-1j*k*n[1]*xref[1]) / _hankel2(0, k*n[1]*xref[1]) * \ _np.exp(-1j*k*n[0]*x0[:, 0]) selection = _util.source_selection_all(len(x0)) return d, selection, _secondary_source_point(omega, c)
def line_2d_edge_dipole_ssd(omega, x0, xs, *, alpha=_np.pi*3/2, Nc=None, c=None): r"""Driving function for 2-dimensional line source with edge dipole ESA. Driving function for a virtual line source using the 2-dimensional ESA for an edge-shaped secondary source distribution consisting of dipole line sources. Parameters ---------- omega : float Angular frequency. x0 : (N, 3) array_like Sequence of secondary source positions. xs : (3,) array_like Position of synthesized line source. alpha : float, optional Outer angle of edge. Nc : int, optional Number of elements for series expansion of driving function. Estimated if not given. c : float, optional Speed of sound Returns ------- d : (N,) numpy.ndarray Complex weights of secondary sources. selection : (N,) numpy.ndarray Boolean array containing ``True`` or ``False`` depending on whether the corresponding secondary source is "active" or not. secondary_source_function : callable A function that can be used to create the sound field of a single secondary source. See `sfs.fd.synthesize()`. Notes ----- One leg of the secondary sources has to be located on the x-axis (y0=0), the edge at the origin. Derived from :cite:`Spors2016` """ x0 = _np.asarray(x0) k = _util.wavenumber(omega, c) phi_s = _np.arctan2(xs[1], xs[0]) if phi_s < 0: phi_s = phi_s + 2 * _np.pi r_s = _np.linalg.norm(xs) L = x0.shape[0] r = _np.linalg.norm(x0, axis=1) phi = _np.arctan2(x0[:, 1], x0[:, 0]) phi = _np.where(phi < 0, phi + 2 * _np.pi, phi) if Nc is None: Nc = _np.ceil(2 * k * _np.max(r) * alpha / _np.pi) epsilon = _np.ones(Nc) # weights for series expansion epsilon[0] = 2 d = _np.zeros(L, dtype=complex) idx = (r <= r_s) for m in _np.arange(Nc): nu = m * _np.pi / alpha f = 1/epsilon[m] * _np.cos(nu*phi_s) * _np.cos(nu*phi) d[idx] = d[idx] + f[idx] * _jn(nu, k*r[idx]) * _hankel2(nu, k*r_s) d[~idx] = d[~idx] + f[~idx] * _jn(nu, k*r_s) * _hankel2(nu, k*r[~idx]) return -1j*_np.pi/alpha * d
def plane_2d(omega, x0, r0, n=[0, 1, 0], *, max_order=None, c=None): r"""Driving function for 2-dimensional NFC-HOA for a virtual plane wave. Parameters ---------- omega : float Angular frequency of plane wave. x0 : (N, 3) array_like Sequence of secondary source positions. r0 : float Radius of circular secondary source distribution. n : (3,) array_like, optional Normal vector (traveling direction) of plane wave. max_order : float, optional Maximum order of circular harmonics used for the calculation. c : float, optional Speed of sound. Returns ------- d : (N,) numpy.ndarray Complex weights of secondary sources. selection : (N,) numpy.ndarray Boolean array containing only ``True`` indicating that all secondary source are "active" for NFC-HOA. secondary_source_function : callable A function that can be used to create the sound field of a single secondary source. See `sfs.fd.synthesize()`. Notes ----- .. math:: D(\phi_0, \omega) = -\frac{2\i}{\pi r_0} \sum_{m=-M}^M \frac{\i^{-m}}{\Hankel{2}{m}{\wc r_0}} \e{\i m (\phi_0 - \phi_\text{pw})} See :sfs:`d_nfchoa/#equation-fd-nfchoa-plane-2d` Examples -------- .. plot:: :context: close-figs d, selection, secondary_source = sfs.fd.nfchoa.plane_2d( omega, array.x, R, npw) plot(d, selection, secondary_source) """ if max_order is None: max_order = _util.max_order_circular_harmonics(len(x0)) x0 = _util.asarray_of_rows(x0) k = _util.wavenumber(omega, c) n = _util.normalize_vector(n) phi, _, r = _util.cart2sph(*n) phi0 = _util.cart2sph(*x0.T)[0] d = 0 for m in range(-max_order, max_order + 1): d += 1j**-m / _hankel2(m, k * r0) * _np.exp(1j * m * (phi0 - phi)) selection = _util.source_selection_all(len(x0)) return -2j / (_np.pi * r0) * d, selection, _secondary_source_line(omega, c)
def line_2d_edge_dipole_ssd(omega, x0, xs, *, alpha=_np.pi * 3 / 2, Nc=None, c=None): r"""Driving function for 2-dimensional line source with edge dipole ESA. Driving function for a virtual line source using the 2-dimensional ESA for an edge-shaped secondary source distribution consisting of dipole line sources. Parameters ---------- omega : float Angular frequency. x0 : (N, 3) array_like Sequence of secondary source positions. xs : (3,) array_like Position of synthesized line source. alpha : float, optional Outer angle of edge. Nc : int, optional Number of elements for series expansion of driving function. Estimated if not given. c : float, optional Speed of sound Returns ------- d : (N,) numpy.ndarray Complex weights of secondary sources. selection : (N,) numpy.ndarray Boolean array containing ``True`` or ``False`` depending on whether the corresponding secondary source is "active" or not. secondary_source_function : callable A function that can be used to create the sound field of a single secondary source. See `sfs.fd.synthesize()`. Notes ----- One leg of the secondary sources has to be located on the x-axis (y0=0), the edge at the origin. Derived from :cite:`Spors2016` """ x0 = _np.asarray(x0) k = _util.wavenumber(omega, c) phi_s = _np.arctan2(xs[1], xs[0]) if phi_s < 0: phi_s = phi_s + 2 * _np.pi r_s = _np.linalg.norm(xs) L = x0.shape[0] r = _np.linalg.norm(x0, axis=1) phi = _np.arctan2(x0[:, 1], x0[:, 0]) phi = _np.where(phi < 0, phi + 2 * _np.pi, phi) if Nc is None: Nc = _np.ceil(2 * k * _np.max(r) * alpha / _np.pi) epsilon = _np.ones(Nc) # weights for series expansion epsilon[0] = 2 d = _np.zeros(L, dtype=complex) idx = (r <= r_s) for m in _np.arange(Nc): nu = m * _np.pi / alpha f = 1 / epsilon[m] * _np.cos(nu * phi_s) * _np.cos(nu * phi) d[idx] = d[idx] + f[idx] * _jn(nu, k * r[idx]) * _hankel2(nu, k * r_s) d[~idx] = d[~idx] + f[~idx] * _jn(nu, k * r_s) * _hankel2( nu, k * r[~idx]) return -1j * _np.pi / alpha * d