@@ -155,8 +155,102 @@ def _point(omega, x0, n0, xs, c=None):
155155
156156
157157def point_25d (omega , x0 , n0 , xs , xref = [0 , 0 , 0 ], c = None , omalias = None ):
158+ r"""Driving function for 2.5-dimensional WFS of a virtual point source.
159+
160+ .. versionchanged:: 0.5
161+ see notes, old handling of `point_25d()` is now `point_25d_legacy()`
162+
163+ Parameters
164+ ----------
165+ omega : float
166+ Angular frequency of point source.
167+ x0 : (N, 3) array_like
168+ Sequence of secondary source positions.
169+ n0 : (N, 3) array_like
170+ Sequence of normal vectors of secondary sources.
171+ xs : (3,) array_like
172+ Position of virtual point source.
173+ xref : (3,) array_like, optional
174+ Reference point xref or contour xref(x0) for amplitude correct
175+ synthesis.
176+ c : float, optional
177+ Speed of sound in m/s.
178+ omalias: float, optional
179+ Angular frequency where spatial aliasing becomes prominent.
180+
181+ Returns
182+ -------
183+ d : (N,) numpy.ndarray
184+ Complex weights of secondary sources.
185+ selection : (N,) numpy.ndarray
186+ Boolean array containing ``True`` or ``False`` depending on
187+ whether the corresponding secondary source is "active" or not.
188+ secondary_source_function : callable
189+ A function that can be used to create the sound field of a
190+ single secondary source. See `sfs.mono.synthesize()`.
191+
192+ Notes
193+ -----
194+ `point_25d()` derives 2.5D WFS from the 3D
195+ Neumann-Rayleigh integral (i.e. the TU Delft approach).
196+ The eq. (3.10), (3.11) in :cite:`Start1997`, equivalent to
197+ Eq. (2.137) in :cite:`Schultz2016`
198+
199+ .. math::
200+
201+ D(\x_0,\w) = \sqrt{8 \pi \, \i\wc}
202+ \sqrt{\frac{|\x_\text{ref}-\x_0| \cdot
203+ |\x_0-\x_\text{s}|}{|\x_\text{ref}-\x_0| + |\x_0-\x_\text{s}|}}
204+ \scalarprod{\frac{\x_0-\x_\text{s}}{|\x_0-\x_\text{s}|}}{\n_0}
205+ \frac{\e{-\i\wc |\x_0-\x_\text{s}|}}{4\pi\,|\x_0-\x_\text{s}|}
206+
207+ is implemented.
208+ The theoretical link of `point_25d()` and `point_25d_legacy()` was
209+ introduced as *unified WFS framework* in :cite:`Firtha2017`.
210+
211+ Examples
212+ --------
213+ .. plot::
214+ :context: close-figs
215+
216+ d, selection, secondary_source = sfs.mono.wfs.point_25d(
217+ omega, array.x, array.n, xs)
218+ normalize_gain = 4 * np.pi * np.linalg.norm(xs)
219+ plot(normalize_gain * d, selection, secondary_source)
220+
221+ """
222+ x0 = util .asarray_of_rows (x0 )
223+ n0 = util .asarray_of_rows (n0 )
224+ xs = util .asarray_1d (xs )
225+ xref = util .asarray_1d (xref )
226+ k = util .wavenumber (omega , c )
227+
228+ ds = x0 - xs
229+ dr = xref - x0
230+ s = np .linalg .norm (ds , axis = 1 )
231+ r = np .linalg .norm (dr , axis = 1 )
232+
233+ d = (
234+ preeq_25d (omega , omalias , c ) *
235+ np .sqrt (8 * np .pi ) *
236+ np .sqrt ((r * s ) / (r + s )) *
237+ inner1d (n0 , ds ) / s *
238+ np .exp (- 1j * k * s ) / (4 * np .pi * s ))
239+ selection = util .source_selection_point (n0 , x0 , xs )
240+ return d , selection , secondary_source_point (omega , c )
241+
242+
243+ point_3d = _point
244+
245+
246+ def point_25d_legacy (omega , x0 , n0 , xs , xref = [0 , 0 , 0 ], c = None , omalias = None ):
158247 r"""Driving function for 2.5-dimensional WFS for a virtual point source.
159248
249+ .. versionadded:: 0.5
250+ `point_25d()` was renamed to `point_25d_legacy()` (and a new
251+ function with the name `point_25d()` was introduced). See notes for
252+ further details.
253+
160254 Parameters
161255 ----------
162256 omega : float
@@ -171,6 +265,8 @@ def point_25d(omega, x0, n0, xs, xref=[0, 0, 0], c=None, omalias=None):
171265 Reference point for synthesized sound field.
172266 c : float, optional
173267 Speed of sound.
268+ omalias: float, optional
269+ Angular frequency where spatial aliasing becomes prominent.
174270
175271 Returns
176272 -------
@@ -185,21 +281,30 @@ def point_25d(omega, x0, n0, xs, xref=[0, 0, 0], c=None, omalias=None):
185281
186282 Notes
187283 -----
284+ `point_25d_legacy()` derives 2.5D WFS from the 2D
285+ Neumann-Rayleigh integral (i.e. the approach by Rabenstein & Spors), cf.
286+ :cite:`Spors2008`.
287+
188288 .. math::
189289
190290 D(\x_0,\w) = \sqrt{\i\wc |\x_\text{ref}-\x_0|}
191291 \frac{\scalarprod{\x_0-\x_\text{s}}{\n_0}}
192292 {|\x_0-\x_\text{s}|^\frac{3}{2}}
193293 \e{-\i\wc |\x_0-\x_\text{s}|}
194294
295+ The theoretical link of `point_25d()` and `point_25d_legacy()` was
296+ introduced as *unified WFS framework* in :cite:`Firtha2017`.
297+ Also cf. Eq. (2.145)-(2.147) :cite:`Schultz2016`.
298+
195299 Examples
196300 --------
197301 .. plot::
198302 :context: close-figs
199303
200- d, selection, secondary_source = sfs.mono.wfs.point_25d (
304+ d, selection, secondary_source = sfs.mono.wfs.point_25d_legacy (
201305 omega, array.x, array.n, xs)
202- plot(d, selection, secondary_source)
306+ normalize_gain = np.linalg.norm(xs)
307+ plot(normalize_gain * d, selection, secondary_source)
203308
204309 """
205310 x0 = util .asarray_of_rows (x0 )
@@ -217,9 +322,6 @@ def point_25d(omega, x0, n0, xs, xref=[0, 0, 0], c=None, omalias=None):
217322 return d , selection , secondary_source_point (omega , c )
218323
219324
220- point_3d = _point
221-
222-
223325def _plane (omega , x0 , n0 , n = [0 , 1 , 0 ], c = None ):
224326 r"""Driving function for 2/3-dimensional WFS for a virtual plane wave.
225327
@@ -499,7 +601,8 @@ def preeq_25d(omega, omalias, c):
499601
500602 H(\w) = \begin{cases}
501603 \sqrt{\i \wc} & \text{for } \w \leq \w_\text{alias} \\
502- \sqrt{\i \frac{\w_\text{alias}}{c}} & \text{for } \w > \w_\text{alias}
604+ \sqrt{\i \frac{\w_\text{alias}}{c}} &
605+ \text{for } \w > \w_\text{alias}
503606 \end{cases}
504607
505608 """
0 commit comments