Source code for pyrato.rap

"""Room acoustic parameters
"""
import re
import numpy as np


[docs] def reverberation_time_linear_regression( energy_decay_curve, T='T20', return_intercept=False): """Estimate the reverberation time from a given energy decay curve. The linear regression is performed using least squares error minimization according to the ISO standard 3382 [#]_. Parameters ---------- energy_decay_curve : ndarray, double Energy decay curve. The time needs to be the arrays last dimension. times : ndarray, double Time vector corresponding to each sample of the EDC. T : 'T20', 'T30', 'T40', 'T50', 'T60', 'EDT', 'LDT' Decay interval to be used for the reverberation time extrapolation. EDT corresponds to the early decay time extrapolated from the interval [0, -10] dB, LDT corresponds to the late decay time extrapolated from the interval [-25, -35] dB. normalize : bool, True Normalize the EDC to the steady state energy level Returns ------- reverberation_time : double The reverberation time References ---------- .. [#] ISO 3382, Acoustics - Measurement of the reverberation time of rooms with reference to other acoustical parameters. Examples -------- Estimate the reverberation time from an energy decay curve. >>> import numpy as np >>> import pyfar as pf >>> import pyrato as ra >>> from pyrato.analytic import rectangular_room_rigid_walls ... >>> L = np.array([8, 5, 3])/10 >>> source_pos = np.array([5, 3, 1.2])/10 >>> receiver_pos = np.array([1, 1, 1.2])/10 >>> rir, _ = rectangular_room_rigid_walls( ... L, source_pos, receiver_pos, ... reverberation_time=1, max_freq=1.5e3, n_samples=2**12, ... speed_of_sound=343.9, samplingrate=3e3) >>> rir = rir/rir.time.max() ... >>> awgn = pf.signals.noise( ... rir.n_samples, rms=10**(-50/20), ... sampling_rate=rir.sampling_rate) >>> rir = rir + awgn ... >>> edc = ra.energy_decay_curve_chu_lundeby(rir) >>> t_20 = ra.reverberation_time_linear_regression(edc, 'T20') >>> t_20 ... array([0.99526253]) """ intervals = [20, 30, 40, 50, 60] if T == 'EDT': upper = -0.1 lower = -10.1 elif T == 'LDT': upper = -25. lower = -35. else: try: (int(re.findall(r'\d+', T)[0]) in intervals) except IndexError: raise ValueError( "{} is not a valid interval for the regression.".format(T)) upper = -5 lower = -np.double(re.findall(r'\d+', T)) + upper edcs_db = 10*np.log10(np.abs(energy_decay_curve.time)) times = energy_decay_curve.times reverberation_times = np.zeros(energy_decay_curve.cshape, dtype=float) intercepts = np.zeros(energy_decay_curve.cshape, dtype=float) for ch in np.ndindex(energy_decay_curve.cshape): edc_db = edcs_db[ch] idx_upper = np.nanargmin(np.abs(upper - edc_db)) idx_lower = np.nanargmin(np.abs(lower - edc_db)) A = np.vstack( [times[idx_upper:idx_lower], np.ones(idx_lower - idx_upper)]).T gradient, const = np.linalg.lstsq( A, edc_db[..., idx_upper:idx_lower], rcond=None)[0] reverberation_times[ch] = -60 / gradient intercepts[ch] = 10**(const/10) if return_intercept is True: return reverberation_times, intercepts else: return reverberation_times