@@ -39,7 +39,8 @@ def plot(d, selection, secondary_source, t=0):
39
39
p = sfs.td.synthesize(d, selection, array, secondary_source, grid=grid,
40
40
observation_time=t)
41
41
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)
43
44
44
45
"""
45
46
import numpy as _np
@@ -92,9 +93,9 @@ def plane_25d(x0, n0, n=[0, 1, 0], xref=[0, 0, 0], c=None):
92
93
93
94
.. math::
94
95
95
- d_{2.5D}(x_0,t) = h(t)
96
+ d_{2.5D}(x_0,t) =
96
97
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)
98
99
99
100
with wfs(2.5D) prefilter h(t), which is not implemented yet.
100
101
@@ -125,7 +126,101 @@ def plane_25d(x0, n0, n=[0, 1, 0], xref=[0, 0, 0], c=None):
125
126
126
127
127
128
def 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.
129
224
130
225
Parameters
131
226
----------
@@ -166,15 +261,21 @@ def point_25d(x0, n0, xs, xref=[0, 0, 0], c=None):
166
261
167
262
.. math::
168
263
169
- d_{2.5D}(x_0,t) = h(t)
264
+ d_{2.5D}(x_0,t) =
170
265
\frac{g_0 \scalarprod{(x_0 - x_s)}{n_0}}
171
266
{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)
173
268
174
269
with wfs(2.5D) prefilter h(t), which is not implemented yet.
175
270
176
271
See :sfs:`d_wfs/#equation-td-wfs-point-25d`
177
272
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
+
178
279
Examples
179
280
--------
180
281
.. plot::
@@ -248,10 +349,10 @@ def focused_25d(x0, n0, xs, ns, xref=[0, 0, 0], c=None):
248
349
249
350
.. math::
250
351
251
- d_{2.5D}(x_0,t) = h(t)
352
+ d_{2.5D}(x_0,t) =
252
353
\frac{g_0 \scalarprod{(x_0 - x_s)}{n_0}}
253
354
{|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)
255
356
256
357
with wfs(2.5D) prefilter h(t), which is not implemented yet.
257
358
0 commit comments