Skip to content

Commit 2d00433

Browse files
authored
robustifies the RT60 computation function (#347)
1 parent fa064c2 commit 2d00433

File tree

3 files changed

+30
-8
lines changed

3 files changed

+30
-8
lines changed

CHANGELOG.rst

+6-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,12 @@ adheres to `Semantic Versioning <http://semver.org/spec/v2.0.0.html>`_.
1111
`Unreleased`_
1212
-------------
1313

14-
Nothing yet
14+
Changed
15+
~~~~~~~
16+
17+
- Extra parameter ``energy_thresh`` added to ``pyroomacoustics.experimental.measure_rt60``.
18+
The energy tail beyond this threshold is discarded which is useful for noisy RIR
19+
measurements. The default value is 0.95.
1520

1621
`0.7.4`_ - 2024-04-25
1722
---------------------

pyroomacoustics/bss/fastmnmf.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,7 @@ def separate():
161161
Y_FTM = np.einsum("nft, nfm -> ftm", lambda_NFT, G_NFM)
162162

163163
# update G_NFM (diagonal element of spatial covariance matrices)
164-
numerator = np.einsum(
165-
"nft, ftm -> nfm", lambda_NFT, Qx_power_FTM / (Y_FTM**2)
166-
)
164+
numerator = np.einsum("nft, ftm -> nfm", lambda_NFT, Qx_power_FTM / (Y_FTM**2))
167165
denominator = np.einsum("nft, ftm -> nfm", lambda_NFT, 1 / Y_FTM) + eps
168166
G_NFM *= np.sqrt(numerator / denominator)
169167
Y_FTM = np.einsum("nft, nfm -> ftm", lambda_NFT, G_NFM)

pyroomacoustics/experimental/rt60.py

+23-4
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
import numpy as np
3434

3535

36-
def measure_rt60(h, fs=1, decay_db=60, plot=False, rt60_tgt=None):
36+
def measure_rt60(h, fs=1, decay_db=60, energy_thres=0.95, plot=False, rt60_tgt=None):
3737
"""
3838
Analyze the RT60 of an impulse response. Optionaly plots some useful information.
3939
@@ -47,6 +47,10 @@ def measure_rt60(h, fs=1, decay_db=60, plot=False, rt60_tgt=None):
4747
The decay in decibels for which we actually estimate the time. Although
4848
we would like to estimate the RT60, it might not be practical. Instead,
4949
we measure the RT20 or RT30 and extrapolate to RT60.
50+
energy_thres: float
51+
This should be a value between 0.0 and 1.0.
52+
If provided, the fit will be done using a fraction energy_thres of the
53+
whole energy. This is useful when there is a long noisy tail for example.
5054
plot: bool, optional
5155
If set to ``True``, the power decay and different estimated values will
5256
be plotted (default False).
@@ -60,21 +64,36 @@ def measure_rt60(h, fs=1, decay_db=60, plot=False, rt60_tgt=None):
6064

6165
# The power of the impulse response in dB
6266
power = h**2
67+
# Backward energy integration according to Schroeder
6368
energy = np.cumsum(power[::-1])[::-1] # Integration according to Schroeder
6469

70+
if energy_thres < 1.0:
71+
assert 0.0 < energy_thres < 1.0
72+
energy -= energy[0] * (1.0 - energy_thres)
73+
energy = np.maximum(energy, 0.0)
74+
6575
# remove the possibly all zero tail
6676
i_nz = np.max(np.where(energy > 0)[0])
6777
energy = energy[:i_nz]
6878
energy_db = 10 * np.log10(energy)
6979
energy_db -= energy_db[0]
7080

81+
min_energy_db = -np.min(energy_db)
82+
if min_energy_db - 5 < decay_db:
83+
decay_db = min_energy_db
84+
7185
# -5 dB headroom
72-
i_5db = np.min(np.where(-5 - energy_db > 0)[0])
86+
try:
87+
i_5db = np.min(np.where(energy_db < -5)[0])
88+
except ValueError:
89+
return 0.0
7390
e_5db = energy_db[i_5db]
7491
t_5db = i_5db / fs
75-
7692
# after decay
77-
i_decay = np.min(np.where(-5 - decay_db - energy_db > 0)[0])
93+
try:
94+
i_decay = np.min(np.where(energy_db < -5 - decay_db)[0])
95+
except ValueError:
96+
i_decay = len(energy_db)
7897
t_decay = i_decay / fs
7998

8099
# compute the decay time

0 commit comments

Comments
 (0)