def _focused(omega, x0, n0, xs, ns, *, c=None): r"""Driving function for 2/3-dimensional WFS for a focused source. Parameters ---------- omega : float Angular frequency of focused 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 focused source. ns : (3,) array_like Direction of focused 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) = \i\wc \frac{\scalarprod{\x_0-\x_\text{s}}{\n_0}} {|\x_0-\x_\text{s}|^\frac{3}{2}} \e{\i\wc |\x_0-\x_\text{s}|} Examples -------- .. plot:: :context: close-figs d, selection, secondary_source = sfs.fd.wfs.focused_3d( omega, array.x, array.n, xs_focused, ns_focused) 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 * k * _inner1d(ds, n0) / r ** (3 / 2) * _np.exp(1j * k * r) selection = _util.source_selection_focused(ns, x0, xs) return d, selection, _secondary_source_point(omega, c)
def _focused(omega, x0, n0, xs, ns, *, c=None): r"""Driving function for 2/3-dimensional WFS for a focused source. Parameters ---------- omega : float Angular frequency of focused 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 focused source. ns : (3,) array_like Direction of focused 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) = \i\wc \frac{\scalarprod{\x_0-\x_\text{s}}{\n_0}} {|\x_0-\x_\text{s}|^\frac{3}{2}} \e{\i\wc |\x_0-\x_\text{s}|} Examples -------- .. plot:: :context: close-figs d, selection, secondary_source = sfs.fd.wfs.focused_3d( omega, array.x, array.n, xs_focused, ns_focused) 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 * k * _inner1d(ds, n0) / r**(3 / 2) * _np.exp(1j * k * r) selection = _util.source_selection_focused(ns, x0, xs) return d, selection, _secondary_source_point(omega, c)
def plane_25d(x0, n0, n=[0, 1, 0], xref=[0, 0, 0], c=None): r"""Plane wave model by 2.5-dimensional WFS. Parameters ---------- x0 : (N, 3) array_like Sequence of secondary source positions. n0 : (N, 3) array_like Sequence of secondary source orientations. n : (3,) array_like, optional Normal vector (propagation direction) of synthesized plane wave. xref : (3,) array_like, optional Reference position c : float, optional Speed of sound Returns ------- delays : (N,) numpy.ndarray Delays of secondary sources in seconds. weights : (N,) numpy.ndarray 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.td.synthesize()`. Notes ----- 2.5D correction factor .. math:: g_0 = \sqrt{2 \pi |x_\mathrm{ref} - x_0|} d using a plane wave as source model .. math:: d_{2.5D}(x_0,t) = h(t) 2 g_0 \scalarprod{n}{n_0} \dirac{t - \frac{1}{c} \scalarprod{n}{x_0}} with wfs(2.5D) prefilter h(t), which is not implemented yet. See :sfs:`d_wfs/#equation-td-wfs-plane-25d` Examples -------- .. plot:: :context: close-figs delays, weights, selection, secondary_source = \ sfs.td.wfs.plane_25d(array.x, array.n, npw) d = sfs.td.wfs.driving_signals(delays, weights, signal) plot(d, selection, secondary_source) """ if c is None: c = _default.c x0 = _util.asarray_of_rows(x0) n0 = _util.asarray_of_rows(n0) n = _util.normalize_vector(n) xref = _util.asarray_1d(xref) g0 = _np.sqrt(2 * _np.pi * _np.linalg.norm(xref - x0, axis=1)) delays = _inner1d(n, x0) / c weights = 2 * g0 * _inner1d(n, n0) selection = _util.source_selection_plane(n0, n) return delays, weights, selection, _secondary_source_point(c)
def focused_25d(x0, n0, xs, ns, xref=[0, 0, 0], c=None): r"""Point source by 2.5-dimensional WFS. Parameters ---------- x0 : (N, 3) array_like Sequence of secondary source positions. n0 : (N, 3) array_like Sequence of secondary source orientations. xs : (3,) array_like Virtual source position. ns : (3,) array_like Normal vector (propagation direction) of focused source. This is used for secondary source selection, see `sfs.util.source_selection_focused()`. xref : (3,) array_like, optional Reference position c : float, optional Speed of sound Returns ------- delays : (N,) numpy.ndarray Delays of secondary sources in seconds. weights: (N,) numpy.ndarray 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.td.synthesize()`. Notes ----- 2.5D correction factor .. math:: g_0 = \sqrt{\frac{|x_\mathrm{ref} - x_0|} {|x_0-x_s| + |x_\mathrm{ref}-x_0|}} d using a point source as source model .. math:: d_{2.5D}(x_0,t) = h(t) \frac{g_0 \scalarprod{(x_0 - x_s)}{n_0}} {|x_0 - x_s|^{3/2}} \dirac{t + \frac{|x_0 - x_s|}{c}} with wfs(2.5D) prefilter h(t), which is not implemented yet. See :sfs:`d_wfs/#equation-td-wfs-focused-25d` Examples -------- .. plot:: :context: close-figs delays, weights, selection, secondary_source = \ sfs.td.wfs.focused_25d(array.x, array.n, xf, nf) d = sfs.td.wfs.driving_signals(delays, weights, signal) plot(d, selection, secondary_source, t=tf) """ if c is None: c = _default.c x0 = _util.asarray_of_rows(x0) n0 = _util.asarray_of_rows(n0) xs = _util.asarray_1d(xs) xref = _util.asarray_1d(xref) ds = x0 - xs r = _np.linalg.norm(ds, axis=1) g0 = _np.sqrt(_np.linalg.norm(xref - x0, axis=1) / (_np.linalg.norm(xref - x0, axis=1) + r)) delays = -r/c weights = g0 * _inner1d(ds, n0) / (2 * _np.pi * r**(3/2)) selection = _util.source_selection_focused(ns, x0, xs) return delays, weights, selection, _secondary_source_point(c)
def point_25d_legacy(omega, x0, n0, xs, xref=[0, 0, 0], c=None, omalias=None): r"""Driving function for 2.5-dimensional WFS for a virtual point source. .. versionadded:: 0.5 `point_25d()` was renamed to `point_25d_legacy()` (and a new function with the name `point_25d()` was introduced). See notes for further details. 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. omalias: float, optional Angular frequency where spatial aliasing becomes prominent. 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 ----- `point_25d_legacy()` derives 2.5D WFS from the 2D Neumann-Rayleigh integral (i.e. the approach by Rabenstein & Spors), cf. :cite:`Spors2008`. .. math:: D(\x_0,\w) = \sqrt{\i\wc |\x_\text{ref}-\x_0|} \frac{\scalarprod{\x_0-\x_\text{s}}{\n_0}} {|\x_0-\x_\text{s}|^\frac{3}{2}} \e{-\i\wc |\x_0-\x_\text{s}|} The theoretical link of `point_25d()` and `point_25d_legacy()` was introduced as *unified WFS framework* in :cite:`Firtha2017`. Also cf. Eq. (2.145)-(2.147) :cite:`Schultz2016`. Examples -------- .. plot:: :context: close-figs d, selection, secondary_source = sfs.fd.wfs.point_25d_legacy( omega, array.x, array.n, xs) normalize_gain = np.linalg.norm(xs) plot(normalize_gain * 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 = ( preeq_25d(omega, omalias, c) * _np.sqrt(_np.linalg.norm(xref - x0)) * _inner1d(ds, n0) / r ** (3 / 2) * _np.exp(-1j * k * r)) selection = _util.source_selection_point(n0, x0, xs) return d, selection, _secondary_source_point(omega, c)
def point_25d(omega, x0, n0, xs, xref=[0, 0, 0], c=None, omalias=None): r"""Driving function for 2.5-dimensional WFS of a virtual point source. .. versionchanged:: 0.5 see notes, old handling of `point_25d()` is now `point_25d_legacy()` 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 xref or contour xref(x0) for amplitude correct synthesis. c : float, optional Speed of sound in m/s. omalias: float, optional Angular frequency where spatial aliasing becomes prominent. 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 ----- `point_25d()` derives 2.5D WFS from the 3D Neumann-Rayleigh integral (i.e. the TU Delft approach). The eq. (3.10), (3.11) in :cite:`Start1997`, equivalent to Eq. (2.137) in :cite:`Schultz2016` .. math:: D(\x_0,\w) = \sqrt{8 \pi \, \i\wc} \sqrt{\frac{|\x_\text{ref}-\x_0| \cdot |\x_0-\x_\text{s}|}{|\x_\text{ref}-\x_0| + |\x_0-\x_\text{s}|}} \scalarprod{\frac{\x_0-\x_\text{s}}{|\x_0-\x_\text{s}|}}{\n_0} \frac{\e{-\i\wc |\x_0-\x_\text{s}|}}{4\pi\,|\x_0-\x_\text{s}|} is implemented. The theoretical link of `point_25d()` and `point_25d_legacy()` was introduced as *unified WFS framework* in :cite:`Firtha2017`. Examples -------- .. plot:: :context: close-figs d, selection, secondary_source = sfs.fd.wfs.point_25d( omega, array.x, array.n, xs) normalize_gain = 4 * np.pi * np.linalg.norm(xs) plot(normalize_gain * 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 dr = xref - x0 s = _np.linalg.norm(ds, axis=1) r = _np.linalg.norm(dr, axis=1) d = ( preeq_25d(omega, omalias, c) * _np.sqrt(8 * _np.pi) * _np.sqrt((r * s) / (r + s)) * _inner1d(n0, ds) / s * _np.exp(-1j * k * s) / (4 * _np.pi * s)) selection = _util.source_selection_point(n0, x0, xs) return d, selection, _secondary_source_point(omega, c)
def point_25d_legacy(omega, x0, n0, xs, xref=[0, 0, 0], c=None, omalias=None): r"""Driving function for 2.5-dimensional WFS for a virtual point source. .. versionadded:: 0.5 `point_25d()` was renamed to `point_25d_legacy()` (and a new function with the name `point_25d()` was introduced). See notes for further details. 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. omalias: float, optional Angular frequency where spatial aliasing becomes prominent. 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 ----- `point_25d_legacy()` derives 2.5D WFS from the 2D Neumann-Rayleigh integral (i.e. the approach by Rabenstein & Spors), cf. :cite:`Spors2008`. .. math:: D(\x_0,\w) = \sqrt{\i\wc |\x_\text{ref}-\x_0|} \frac{\scalarprod{\x_0-\x_\text{s}}{\n_0}} {|\x_0-\x_\text{s}|^\frac{3}{2}} \e{-\i\wc |\x_0-\x_\text{s}|} The theoretical link of `point_25d()` and `point_25d_legacy()` was introduced as *unified WFS framework* in :cite:`Firtha2017`. Also cf. Eq. (2.145)-(2.147) :cite:`Schultz2016`. Examples -------- .. plot:: :context: close-figs d, selection, secondary_source = sfs.fd.wfs.point_25d_legacy( omega, array.x, array.n, xs) normalize_gain = np.linalg.norm(xs) plot(normalize_gain * 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 = (preeq_25d(omega, omalias, c) * _np.sqrt(_np.linalg.norm(xref - x0)) * _inner1d(ds, n0) / r**(3 / 2) * _np.exp(-1j * k * r)) selection = _util.source_selection_point(n0, x0, xs) return d, selection, _secondary_source_point(omega, c)
def point_25d(omega, x0, n0, xs, xref=[0, 0, 0], c=None, omalias=None): r"""Driving function for 2.5-dimensional WFS of a virtual point source. .. versionchanged:: 0.5 see notes, old handling of `point_25d()` is now `point_25d_legacy()` 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 xref or contour xref(x0) for amplitude correct synthesis. c : float, optional Speed of sound in m/s. omalias: float, optional Angular frequency where spatial aliasing becomes prominent. 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 ----- `point_25d()` derives 2.5D WFS from the 3D Neumann-Rayleigh integral (i.e. the TU Delft approach). The eq. (3.10), (3.11) in :cite:`Start1997`, equivalent to Eq. (2.137) in :cite:`Schultz2016` .. math:: D(\x_0,\w) = \sqrt{8 \pi \, \i\wc} \sqrt{\frac{|\x_\text{ref}-\x_0| \cdot |\x_0-\x_\text{s}|}{|\x_\text{ref}-\x_0| + |\x_0-\x_\text{s}|}} \scalarprod{\frac{\x_0-\x_\text{s}}{|\x_0-\x_\text{s}|}}{\n_0} \frac{\e{-\i\wc |\x_0-\x_\text{s}|}}{4\pi\,|\x_0-\x_\text{s}|} is implemented. The theoretical link of `point_25d()` and `point_25d_legacy()` was introduced as *unified WFS framework* in :cite:`Firtha2017`. Examples -------- .. plot:: :context: close-figs d, selection, secondary_source = sfs.fd.wfs.point_25d( omega, array.x, array.n, xs) normalize_gain = 4 * np.pi * np.linalg.norm(xs) plot(normalize_gain * 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 dr = xref - x0 s = _np.linalg.norm(ds, axis=1) r = _np.linalg.norm(dr, axis=1) d = (preeq_25d(omega, omalias, c) * _np.sqrt(8 * _np.pi) * _np.sqrt( (r * s) / (r + s)) * _inner1d(n0, ds) / s * _np.exp(-1j * k * s) / (4 * _np.pi * s)) selection = _util.source_selection_point(n0, x0, xs) return d, selection, _secondary_source_point(omega, c)
def point_25d_legacy(x0, n0, xs, xref=[0, 0, 0], c=None): r"""Driving function for 2.5-dimensional WFS of a virtual point source. .. versionadded:: 0.61 `point_25d()` was renamed to `point_25d_legacy()` (and a new function with the name `point_25d()` was introduced). See notes below for further details. Parameters ---------- x0 : (N, 3) array_like Sequence of secondary source positions. n0 : (N, 3) array_like Sequence of secondary source orientations. xs : (3,) array_like Virtual source position. xref : (3,) array_like, optional Reference position c : float, optional Speed of sound Returns ------- delays : (N,) numpy.ndarray Delays of secondary sources in seconds. weights: (N,) numpy.ndarray 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.td.synthesize()`. Notes ----- 2.5D correction factor .. math:: g_0 = \sqrt{2 \pi |x_\mathrm{ref} - x_0|} d using a point source as source model .. math:: d_{2.5D}(x_0,t) = \frac{g_0 \scalarprod{(x_0 - x_s)}{n_0}} {2\pi |x_0 - x_s|^{3/2}} \dirac{t - \frac{|x_0 - x_s|}{c}} \ast_t h(t) with wfs(2.5D) prefilter h(t), which is not implemented yet. See :sfs:`d_wfs/#equation-td-wfs-point-25d` `point_25d_legacy()` derives 2.5D WFS from the 2D Neumann-Rayleigh integral (i.e. the approach by Rabenstein & Spors), cf. :cite:`Spors2008`. The theoretical link of `point_25d()` and `point_25d_legacy()` was introduced as *unified WFS framework* in :cite:`Firtha2017`. Examples -------- .. plot:: :context: close-figs delays, weights, selection, secondary_source = \ sfs.td.wfs.point_25d(array.x, array.n, xs) d = sfs.td.wfs.driving_signals(delays, weights, signal) plot(d, selection, secondary_source, t=ts) """ if c is None: c = _default.c x0 = _util.asarray_of_rows(x0) n0 = _util.asarray_of_rows(n0) xs = _util.asarray_1d(xs) xref = _util.asarray_1d(xref) g0 = _np.sqrt(2 * _np.pi * _np.linalg.norm(xref - x0, axis=1)) ds = x0 - xs r = _np.linalg.norm(ds, axis=1) delays = r / c weights = g0 * _inner1d(ds, n0) / (2 * _np.pi * r**(3 / 2)) selection = _util.source_selection_point(n0, x0, xs) return delays, weights, selection, _secondary_source_point(c)
def point_25d(x0, n0, xs, xref=[0, 0, 0], c=None): r"""Driving function for 2.5-dimensional WFS of a virtual point source. .. versionchanged:: 0.61 see notes, old handling of `point_25d()` is now `point_25d_legacy()` Parameters ---------- x0 : (N, 3) array_like Sequence of secondary source positions. n0 : (N, 3) array_like Sequence of secondary source orientations. xs : (3,) array_like Virtual source position. xref : (N, 3) array_like or (3,) array_like Reference curve of correct amplitude xref(x0) c : float, optional Speed of sound Returns ------- delays : (N,) numpy.ndarray Delays of secondary sources in seconds. weights: (N,) numpy.ndarray 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.td.synthesize()`. Notes ----- Eq. (2.138) in :cite:`Schultz2016`: .. math:: d_{2.5D}(x_0, x_{ref}, t) = \sqrt{8\pi} \frac{\scalarprod{(x_0 - x_s)}{n_0}}{|x_0 - x_s|} \sqrt{\frac{|x_0 - x_s||x_0 - x_{ref}|}{|x_0 - x_s|+|x_0 - x_{ref}|}} \cdot \frac{\dirac{t - \frac{|x_0 - x_s|}{c}}}{4\pi |x_0 - x_s|} \ast_t h(t) .. math:: h(t) = F^{-1}(\sqrt{\frac{j \omega}{c}}) with wfs(2.5D) prefilter h(t), which is not implemented yet. `point_25d()` derives WFS from 3D to 2.5D via the stationary phase approximation approach (i.e. the Delft approach). The theoretical link of `point_25d()` and `point_25d_legacy()` was introduced as *unified WFS framework* in :cite:`Firtha2017`. Examples -------- .. plot:: :context: close-figs delays, weights, selection, secondary_source = \ sfs.td.wfs.point_25d(array.x, array.n, xs) d = sfs.td.wfs.driving_signals(delays, weights, signal) plot(d, selection, secondary_source, t=ts) """ if c is None: c = _default.c x0 = _util.asarray_of_rows(x0) n0 = _util.asarray_of_rows(n0) xs = _util.asarray_1d(xs) xref = _util.asarray_of_rows(xref) x0xs = x0 - xs x0xref = x0 - xref x0xs_n = _np.linalg.norm(x0xs, axis=1) x0xref_n = _np.linalg.norm(x0xref, axis=1) g0 = 1 / (_np.sqrt(2 * _np.pi) * x0xs_n**2) g0 *= _np.sqrt((x0xs_n * x0xref_n) / (x0xs_n + x0xref_n)) delays = x0xs_n / c weights = g0 * _inner1d(x0xs, n0) selection = _util.source_selection_point(n0, x0, xs) return delays, weights, selection, _secondary_source_point(c)