@@ -189,7 +189,7 @@ def radial_filter(orders, freqs, array_configuration, amp_maxdB=40):
189
189
return limiting_factor / extrapolation_coeffs
190
190
191
191
192
- def spherical_head_filter (max_order , full_order , kr ):
192
+ def spherical_head_filter (max_order , full_order , kr , is_tapering = False ):
193
193
"""Generate coloration compensation filter of specified maximum SH order.
194
194
195
195
Parameters
@@ -200,6 +200,8 @@ def spherical_head_filter(max_order, full_order, kr):
200
200
Full order necessary to expand sound field in entire modal range
201
201
kr : array_like
202
202
Vector of corresponding wave numbers
203
+ is_tapering : bool, optional
204
+ If set, spherical head filter will be adapted applying a Hann window, according to [2]
203
205
204
206
Returns
205
207
-------
@@ -208,33 +210,43 @@ def spherical_head_filter(max_order, full_order, kr):
208
210
209
211
References
210
212
----------
211
- .. [1] Ben-Hur, Z., Brinkmann, F., Sheaffer, J., et al. (2017). Spectral equalization in binaural signals
212
- represented by order-truncated spherical harmonics. The Journal of the Acoustical Society of America.
213
+ .. [1] Ben-Hur, Z., Brinkmann, F., Sheaffer, J., et al. (2017). "Spectral equalization in binaural signals
214
+ represented by order-truncated spherical harmonics. The Journal of the Acoustical Society of America".
215
+
216
+ .. [2] Hold, Christoph, Hannes Gamper, Ville Pulkki, Nikunj Raghuvanshi, and Ivan J. Tashev (2019). “Improving
217
+ Binaural Ambisonics Decoding by Spherical Harmonics Domain Tapering and Coloration Compensation.”
213
218
"""
214
219
215
- def pressure_on_sphere (max_order , kr ):
220
+ # noinspection PyShadowingNames
221
+ def pressure_on_sphere (max_order , kr , taper_weights = None ):
216
222
"""
217
223
Calculate the diffuse field pressure frequency response of a spherical scatterer, up to the specified SH order.
224
+ If tapering weights are specified, pressure on the sphere function will be adapted.
218
225
"""
226
+ if taper_weights is None :
227
+ taper_weights = _np .ones (max_order + 1 ) # no weighting
228
+
219
229
p = _np .zeros_like (kr )
220
230
for order in range (max_order + 1 ):
221
231
# Calculate mode strength b_n(kr) for an incident plane wave on sphere according to [1, Eq.(9)]
222
232
b_n = 4 * _np .pi * 1j ** order * (spherical_jn (order , kr ) -
223
233
(spherical_jn (order , kr , True ) /
224
234
dsphankel2 (order , kr )) * sphankel2 (order , kr ))
225
- p += (2 * order + 1 ) * _np .abs (b_n ) ** 2
235
+ p += (2 * order + 1 ) * _np .abs (b_n ) ** 2 * taper_weights [ order ]
226
236
227
237
# according to [1, Eq.(11)]
228
238
return 1 / (4 * _np .pi ) * _np .sqrt (p )
229
239
230
240
# according to [1, Eq.(12)].
231
- G_SHF = pressure_on_sphere (full_order , kr ) / pressure_on_sphere (max_order , kr )
241
+ taper_weights = tapering_window (max_order ) if is_tapering else None
242
+ G_SHF = pressure_on_sphere (full_order , kr ) / pressure_on_sphere (max_order , kr , taper_weights )
243
+
232
244
G_SHF [G_SHF == 0 ] = 1e-12 # catch zeros
233
245
G_SHF [_np .isnan (G_SHF )] = 1 # catch NaNs
234
246
return G_SHF
235
247
236
248
237
- def spherical_head_filter_spec (max_order , NFFT , fs , radius , amp_maxdB = None ):
249
+ def spherical_head_filter_spec (max_order , NFFT , fs , radius , amp_maxdB = None , is_tapering = False ):
238
250
"""Generate NFFT/2 + 1 coloration compensation filter of specified maximum SH order for frequencies 0:fs/2, wraps
239
251
spherical_head_filter().
240
252
@@ -250,21 +262,23 @@ def spherical_head_filter_spec(max_order, NFFT, fs, radius, amp_maxdB=None):
250
262
Array radius
251
263
amp_maxdB : int, optional
252
264
Maximum modal amplification limit in dB [Default: None]
265
+ is_tapering : bool, optional
266
+ If true spherical head filter will be adapted for SH tapering. [Default: False]
253
267
254
268
Returns
255
269
-------
256
270
G_SHF : array_like
257
271
Vector of frequency domain filter of shape [NFFT / 2 + 1]
258
272
"""
259
273
# frequency support vector & corresponding wave numbers k
260
- freqs = _np .linspace (0 , fs / 2 , NFFT // 2 + 1 )
274
+ freqs = _np .linspace (0 , fs / 2 , int ( NFFT / 2 + 1 ) )
261
275
kr_SHF = kr (freqs , radius )
262
276
263
277
# calculate SH order necessary to expand sound field in entire modal range
264
278
order_full = int (_np .ceil (kr_SHF [- 1 ]))
265
279
266
280
# calculate filter
267
- G_SHF = spherical_head_filter (max_order , order_full , kr_SHF )
281
+ G_SHF = spherical_head_filter (max_order , order_full , kr_SHF , is_tapering = is_tapering )
268
282
269
283
# filter limiting
270
284
if amp_maxdB :
@@ -430,3 +444,34 @@ def spherical_noise(gridData=None, order_max=8, spherical_harmonic_bases=None):
430
444
order_max = _np .int (_np .sqrt (spherical_harmonic_bases .shape [1 ]) - 1 )
431
445
return _np .inner (spherical_harmonic_bases ,
432
446
_np .random .randn ((order_max + 1 ) ** 2 ) + 1j * _np .random .randn ((order_max + 1 ) ** 2 ))
447
+
448
+
449
+ def tapering_window (max_order ):
450
+ """Design tapering window with cosine slope for orders greater than 3.
451
+
452
+ Parameters
453
+ ----------
454
+ max_order : int
455
+ Maximum SH order
456
+
457
+ Returns
458
+ -------
459
+ hann_window_half : array_like
460
+ Tapering window with cosine slope for orders greater than 3. Ones in case of maximum SH order being smaller than
461
+ 3.
462
+
463
+ References
464
+ ----------
465
+ .. [1] Hold, Christoph, Hannes Gamper, Ville Pulkki, Nikunj Raghuvanshi, and Ivan J. Tashev (2019). “Improving
466
+ Binaural Ambisonics Decoding by Spherical Harmonics Domain Tapering and Coloration Compensation.”
467
+ """
468
+ weights = _np .ones (max_order + 1 )
469
+
470
+ if max_order >= 3 :
471
+ hann_window = _np .hanning (2 * ((max_order + 1 ) // 2 ) + 1 )
472
+ weights [- ((max_order - 1 ) // 2 ):] = hann_window [- ((max_order + 1 ) // 2 ):- 1 ]
473
+ else :
474
+ import sys
475
+ print ('[WARNING] SH maximum order is smaller than 3. No tapering will be used.' , file = sys .stderr )
476
+
477
+ return weights
0 commit comments