@@ -39,7 +39,8 @@ def plot(d, selection, secondary_source, t=0):
3939 p = sfs.td.synthesize(d, selection, array, secondary_source, grid=grid,
4040 observation_time=t)
4141 sfs.plot2d.level(p, grid)
42- sfs.plot2d.loudspeakers(array.x, array.n, selection * array.a, size=0.15)
42+ sfs.plot2d.loudspeakers(array.x, array.n,
43+ selection * array.a, size=0.15)
4344
4445"""
4546import numpy as _np
@@ -92,9 +93,9 @@ def plane_25d(x0, n0, n=[0, 1, 0], xref=[0, 0, 0], c=None):
9293
9394 .. math::
9495
95- d_{2.5D}(x_0,t) = h(t)
96+ d_{2.5D}(x_0,t) =
9697 2 g_0 \scalarprod{n}{n_0}
97- \dirac{t - \frac{1}{c} \scalarprod{n}{x_0}}
98+ \dirac{t - \frac{1}{c} \scalarprod{n}{x_0}} \ast_t h(t)
9899
99100 with wfs(2.5D) prefilter h(t), which is not implemented yet.
100101
@@ -125,7 +126,101 @@ def plane_25d(x0, n0, n=[0, 1, 0], xref=[0, 0, 0], c=None):
125126
126127
127128def point_25d (x0 , n0 , xs , xref = [0 , 0 , 0 ], c = None ):
128- r"""Point source by 2.5-dimensional WFS.
129+ r"""Driving function for 2.5-dimensional WFS of a virtual point source.
130+
131+ .. versionchanged:: 0.61
132+ see notes, old handling of `point_25d()` is now `point_25d_legacy()`
133+
134+ Parameters
135+ ----------
136+ x0 : (N, 3) array_like
137+ Sequence of secondary source positions.
138+ n0 : (N, 3) array_like
139+ Sequence of secondary source orientations.
140+ xs : (3,) array_like
141+ Virtual source position.
142+ xref : (N, 3) array_like or (3,) array_like
143+ Reference curve of correct amplitude xref(x0)
144+ c : float, optional
145+ Speed of sound
146+
147+ Returns
148+ -------
149+ delays : (N,) numpy.ndarray
150+ Delays of secondary sources in seconds.
151+ weights: (N,) numpy.ndarray
152+ Weights of secondary sources.
153+ selection : (N,) numpy.ndarray
154+ Boolean array containing ``True`` or ``False`` depending on
155+ whether the corresponding secondary source is "active" or not.
156+ secondary_source_function : callable
157+ A function that can be used to create the sound field of a
158+ single secondary source. See `sfs.td.synthesize()`.
159+
160+ Notes
161+ -----
162+
163+ Eq. (2.138) in :cite:`Schultz2016`:
164+
165+ .. math::
166+
167+ d_{2.5D}(x_0, x_{ref}, t) =
168+ \sqrt{8\pi}
169+ \frac{\scalarprod{(x_0 - x_s)}{n_0}}{|x_0 - x_s|}
170+ \sqrt{\frac{|x_0 - x_s||x_0 - x_{ref}|}{|x_0 - x_s|+|x_0 - x_{ref}|}}
171+ \cdot
172+ \frac{\dirac{t - \frac{|x_0 - x_s|}{c}}}{4\pi |x_0 - x_s|} \ast_t h(t)
173+
174+ .. math::
175+
176+ h(t) = F^{-1}(\sqrt{\frac{j \omega}{c}})
177+
178+ with wfs(2.5D) prefilter h(t), which is not implemented yet.
179+
180+ `point_25d()` derives WFS from 3D to 2.5D via the stationary phase
181+ approximation approach (i.e. the Delft approach).
182+ The theoretical link of `point_25d()` and `point_25d_legacy()` was
183+ introduced as *unified WFS framework* in :cite:`Firtha2017`.
184+
185+ Examples
186+ --------
187+ .. plot::
188+ :context: close-figs
189+
190+ delays, weights, selection, secondary_source = \
191+ sfs.td.wfs.point_25d(array.x, array.n, xs)
192+ d = sfs.td.wfs.driving_signals(delays, weights, signal)
193+ plot(d, selection, secondary_source, t=ts)
194+
195+ """
196+ if c is None :
197+ c = _default .c
198+ x0 = _util .asarray_of_rows (x0 )
199+ n0 = _util .asarray_of_rows (n0 )
200+ xs = _util .asarray_1d (xs )
201+ xref = _util .asarray_of_rows (xref )
202+
203+ x0xs = x0 - xs
204+ x0xref = x0 - xref
205+ x0xs_n = _np .linalg .norm (x0xs , axis = 1 )
206+ x0xref_n = _np .linalg .norm (x0xref , axis = 1 )
207+
208+ g0 = 1 / (_np .sqrt (2 * _np .pi )* x0xs_n ** 2 )
209+ g0 *= _np .sqrt ((x0xs_n * x0xref_n )/ (x0xs_n + x0xref_n ))
210+
211+ delays = x0xs_n / c
212+ weights = g0 * _inner1d (x0xs , n0 )
213+ selection = _util .source_selection_point (n0 , x0 , xs )
214+ return delays , weights , selection , _secondary_source_point (c )
215+
216+
217+ def point_25d_legacy (x0 , n0 , xs , xref = [0 , 0 , 0 ], c = None ):
218+ r"""Driving function for 2.5-dimensional WFS of a virtual point source.
219+
220+ .. versionadded:: 0.61
221+ `point_25d()` was renamed to `point_25d_legacy()` (and a new
222+ function with the name `point_25d()` was introduced). See notes below
223+ for further details.
129224
130225 Parameters
131226 ----------
@@ -166,15 +261,21 @@ def point_25d(x0, n0, xs, xref=[0, 0, 0], c=None):
166261
167262 .. math::
168263
169- d_{2.5D}(x_0,t) = h(t)
264+ d_{2.5D}(x_0,t) =
170265 \frac{g_0 \scalarprod{(x_0 - x_s)}{n_0}}
171266 {2\pi |x_0 - x_s|^{3/2}}
172- \dirac{t - \frac{|x_0 - x_s|}{c}}
267+ \dirac{t - \frac{|x_0 - x_s|}{c}} \ast_t h(t)
173268
174269 with wfs(2.5D) prefilter h(t), which is not implemented yet.
175270
176271 See :sfs:`d_wfs/#equation-td-wfs-point-25d`
177272
273+ `point_25d_legacy()` derives 2.5D WFS from the 2D
274+ Neumann-Rayleigh integral (i.e. the approach by Rabenstein & Spors), cf.
275+ :cite:`Spors2008`.
276+ The theoretical link of `point_25d()` and `point_25d_legacy()` was
277+ introduced as *unified WFS framework* in :cite:`Firtha2017`.
278+
178279 Examples
179280 --------
180281 .. plot::
@@ -248,10 +349,10 @@ def focused_25d(x0, n0, xs, ns, xref=[0, 0, 0], c=None):
248349
249350 .. math::
250351
251- d_{2.5D}(x_0,t) = h(t)
352+ d_{2.5D}(x_0,t) =
252353 \frac{g_0 \scalarprod{(x_0 - x_s)}{n_0}}
253354 {|x_0 - x_s|^{3/2}}
254- \dirac{t + \frac{|x_0 - x_s|}{c}}
355+ \dirac{t + \frac{|x_0 - x_s|}{c}} \ast_t h(t)
255356
256357 with wfs(2.5D) prefilter h(t), which is not implemented yet.
257358
0 commit comments