diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 723d90c..4a75c98 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,6 +14,22 @@ adheres to `Semantic Versioning `_. - Validation for results from tests in every module (so far many tests are only regarding functionality) +`0.3.8 `_ - +--------------------- + +Misc +~~~~~~~ +- renamed paramater `remove_impulse_delay` to `remove_ir_latency` +- changed default values in `PhaseLinearizer` +- general documentation improvements + +Bugfix +~~~~~~ +- `find_ir_latency` now searches for the latency in comparison to the minimum + phase ir +- `harmonic_distortion_analysis` was fixed so that it can succesfully trim + the fundamental ir + `0.3.7 `_ - --------------------- diff --git a/dsptoolbox/__init__.py b/dsptoolbox/__init__.py index 0294919..7a6bc8f 100644 --- a/dsptoolbox/__init__.py +++ b/dsptoolbox/__init__.py @@ -73,4 +73,4 @@ "effects", ] -__version__ = "0.3.7" +__version__ = "0.3.8" diff --git a/dsptoolbox/_general_helpers.py b/dsptoolbox/_general_helpers.py index 52daa7b..f59cf1d 100644 --- a/dsptoolbox/_general_helpers.py +++ b/dsptoolbox/_general_helpers.py @@ -3,7 +3,12 @@ """ import numpy as np -from scipy.signal import windows, convolve as scipy_convolve, hilbert +from scipy.signal import ( + windows, + convolve as scipy_convolve, + hilbert, + correlate, +) from scipy.interpolate import interp1d from scipy.linalg import toeplitz as toeplitz_scipy from os import sep @@ -1235,7 +1240,7 @@ def _get_fractional_impulse_peak_index( return latency_samples + start_offset -def _remove_impulse_delay_from_phase( +def _remove_ir_latency_from_phase( freqs: np.ndarray, phase: np.ndarray, time_data: np.ndarray, @@ -1261,5 +1266,112 @@ def _remove_impulse_delay_from_phase( New phase response without impulse delay. """ - delays_s = _get_fractional_impulse_peak_index(time_data) / sampling_rate_hz + min_ir = _min_phase_ir_from_real_cepstrum(time_data) + delays_s = _fractional_latency(time_data, min_ir) / sampling_rate_hz return _wrap_phase(phase + 2 * np.pi * freqs[:, None] * delays_s[None, :]) + + +def _min_phase_ir_from_real_cepstrum(time_data: np.ndarray): + """Returns minimum-phase version of a time series using the real cepstrum + method. + + Parameters + ---------- + time_data : `np.ndarray` + Time series to compute the minimum phase version from. It is assumed + to have shape (time samples, channels). + + Returns + ------- + min_phase_time_data : `np.ndarray` + New time series. + + """ + return np.real( + np.fft.ifft( + _get_minimum_phase_spectrum_from_real_cepstrum(time_data), axis=0 + ) + ) + + +def _get_minimum_phase_spectrum_from_real_cepstrum(time_data: np.ndarray): + """Returns minimum-phase version of a time series using the real cepstrum + method. + + Parameters + ---------- + time_data : `np.ndarray` + Time series to compute the minimum phase version from. It is assumed + to have shape (time samples, channels). + + Returns + ------- + `np.ndarray` + New spectrum with minimum phase. + + """ + # Real cepstrum + y = np.real( + np.fft.ifft(np.log(np.abs(np.fft.fft(time_data, axis=0))), axis=0) + ) + + # Window in the cepstral domain, like obtaining hilbert transform + w = np.zeros(y.shape[0]) + w[0] = 1 + w[: len(w) // 2 - 1] = 2 + # If length is even, nyquist is exactly in the middle + if len(w) % 2 == 0: + w[len(w) // 2] = 1 + + # Windowing in cepstral domain and back to spectral domain + return np.exp(np.fft.fft(y * w[..., None], axis=0)) + + +def _fractional_latency( + td1: np.ndarray, td2: np.ndarray | None = None, polynomial_points: int = 1 +): + """This function computes the sub-sample latency between two signals using + Zero-Crossing of the analytic (hilbert transformed) correlation function. + The number of polynomial points taken around the correlation maximum can be + set, although some polynomial orders might fail to compute the root. In + that case, integer latency will be returned for the respective channel. + + Parameters + ---------- + td1 : `np.ndaray` + Delayed version of the signal. + td2 : `np.ndarray`, optional + Original version of the signal. If `None` is passed, the latencies + are computed between the first channel of td1 and every other. + Default: `None`. + polynomial_points : int, optional + This corresponds to the number of points taken around the root in order + to fit a polynomial. Accuracy might improve with higher orders but + it could also lead to ill-conditioned polynomials. In case root finding + is not successful, integer latency values are returned. Default: 1. + + Returns + ------- + lags : `np.ndarray` + Fractional delays. It has shape (channel). In case td2 was `None`, its + length is `channels - 1`. + + References + ---------- + - N. S. M. Tamim and F. Ghani, "Hilbert transform of FFT pruned cross + correlation function for optimization in time delay estimation," 2009 + IEEE 9th Malaysia International Conference on Communications (MICC), + Kuala Lumpur, Malaysia, 2009, pp. 809-814, + doi: 10.1109/MICC.2009.5431382. + + """ + if td2 is None: + td2 = td1[:, 0][..., None] + td1 = np.atleast_2d(td1[:, 1:]) + xcor = correlate(td2, td1) + else: + xcor = np.zeros((td1.shape[0] + td2.shape[0] - 1, td2.shape[1])) + for i in range(td2.shape[1]): + xcor[:, i] = correlate(td2[:, i], td1[:, i]) + inds = _get_fractional_impulse_peak_index(xcor, polynomial_points) + return td1.shape[0] - inds - 1 diff --git a/dsptoolbox/_standard.py b/dsptoolbox/_standard.py index b35dd2c..65be25c 100644 --- a/dsptoolbox/_standard.py +++ b/dsptoolbox/_standard.py @@ -8,7 +8,6 @@ from ._general_helpers import ( _pad_trim, _compute_number_frames, - _get_fractional_impulse_peak_index, _wrap_phase, ) from warnings import warn @@ -35,56 +34,6 @@ def _latency( return in1.shape[0] - peak_inds - 1 -def _fractional_latency( - td1: np.ndarray, td2: np.ndarray | None = None, polynomial_points: int = 1 -): - """This function computes the sub-sample latency between two signals using - Zero-Crossing of the analytic (hilbert transformed) correlation function. - The number of polynomial points taken around the correlation maximum can be - set, although some polynomial orders might fail to compute the root. In - that case, integer latency will be returned for the respective channel. - - Parameters - ---------- - td1 : `np.ndaray` - Delayed version of the signal. - td2 : `np.ndarray`, optional - Original version of the signal. If `None` is passed, the latencies - are computed between the first channel of td1 and every other. - Default: `None`. - polynomial_points : int, optional - This corresponds to the number of points taken around the root in order - to fit a polynomial. Accuracy might improve with higher orders but - it could also lead to ill-conditioned polynomials. In case root finding - is not successful, integer latency values are returned. Default: 1. - - Returns - ------- - lags : `np.ndarray` - Fractional delays. It has shape (channel). In case td2 was `None`, its - length is `channels - 1`. - - References - ---------- - - N. S. M. Tamim and F. Ghani, "Hilbert transform of FFT pruned cross - correlation function for optimization in time delay estimation," 2009 - IEEE 9th Malaysia International Conference on Communications (MICC), - Kuala Lumpur, Malaysia, 2009, pp. 809-814, - doi: 10.1109/MICC.2009.5431382. - - """ - if td2 is None: - td2 = td1[:, 0][..., None] - td1 = np.atleast_2d(td1[:, 1:]) - xcor = correlate(td2, td1) - else: - xcor = np.zeros((td1.shape[0] + td2.shape[0] - 1, td2.shape[1])) - for i in range(td2.shape[1]): - xcor[:, i] = correlate(td2[:, i], td1[:, i]) - inds = _get_fractional_impulse_peak_index(xcor, polynomial_points) - return td1.shape[0] - inds - 1 - - def _welch( x: np.ndarray, y: np.ndarray | None, diff --git a/dsptoolbox/classes/_phaseLinearizer.py b/dsptoolbox/classes/_phaseLinearizer.py index 777defc..2774532 100644 --- a/dsptoolbox/classes/_phaseLinearizer.py +++ b/dsptoolbox/classes/_phaseLinearizer.py @@ -82,7 +82,7 @@ def _set_target_group_delay(self, target_group_delay: np.ndarray): def set_parameters( self, delay_increase_percent: float = 100.0, - total_length_factor: float = 1.5, + total_length_factor: float = 1.0, ): """Set parameters for the FIR filter. @@ -97,7 +97,7 @@ def set_parameters( Default: 100. total_length_factor : float, optional The total length of the filter is based on the longest group delay. - This factor can augment it. Default: 1.5. + This factor can augment it. Default: 1. Notes ----- diff --git a/dsptoolbox/classes/filter_class.py b/dsptoolbox/classes/filter_class.py index cc47ea4..020d7a5 100644 --- a/dsptoolbox/classes/filter_class.py +++ b/dsptoolbox/classes/filter_class.py @@ -589,7 +589,7 @@ def get_coefficients( coefficients : array-like Array with filter coefficients with shape depending on mode: - `'ba'`: list(b, a) with b and a of type `np.ndarray`. - - `'sos'`: `np.ndarray` + - `'sos'`: `np.ndarray` with shape (n_sections, 6). - `'zpk'`: tuple(z, p, k) with z, p, k of type `np.ndarray` - Return `None` if user decides that ba->sos is too costly. The threshold is for filters with order > 500. diff --git a/dsptoolbox/classes/signal_class.py b/dsptoolbox/classes/signal_class.py index ce30432..264dbf1 100644 --- a/dsptoolbox/classes/signal_class.py +++ b/dsptoolbox/classes/signal_class.py @@ -21,7 +21,7 @@ _check_format_in_path, _scale_spectrum, _wrap_phase, - _remove_impulse_delay_from_phase, + _remove_ir_latency_from_phase, ) from .._standard import _welch, _group_delay_direct, _stft, _csm @@ -1018,14 +1018,14 @@ def plot_magnitude( ) return fig, ax - def plot_time(self) -> tuple[Figure, Axes]: + def plot_time(self) -> tuple[Figure, list[Axes]]: """Plots time signals. Returns ------- fig : `matplotlib.figure.Figure` Figure. - ax : `matplotlib.axes.Axes` + ax : list of `matplotlib.axes.Axes` Axes. """ @@ -1065,7 +1065,7 @@ def plot_spl( normalize_at_peak: bool = False, range_db: float | None = 100.0, window_length_s: float = 0.0, - ) -> tuple[Figure, Axes]: + ) -> tuple[Figure, list[Axes]]: """Plots the momentary sound pressure level (dB or dBFS) of each channel. If the signal is calibrated and not normalized at peak, the values correspond to dB, otherwise they are dBFS. @@ -1087,7 +1087,7 @@ def plot_spl( ------- fig : `matplotlib.figure.Figure` Figure. - ax : `matplotlib.axes.Axes` + ax : list of `matplotlib.axes.Axes` Axes. Notes @@ -1191,7 +1191,7 @@ def plot_spl( def plot_group_delay( self, range_hz=[20, 20000], - remove_impulse_delay: bool = False, + remove_ir_latency: bool = False, smoothing: int = 0, ) -> tuple[Figure, Axes]: """Plots group delay of each channel. @@ -1203,7 +1203,7 @@ def plot_group_delay( range_hz : array-like with length 2, optional Range of frequencies for which to show group delay. Default: [20, 20e3]. - remove_impulse_delay : bool, optional + remove_ir_latency : bool, optional When `True`, the delay of the impulse is removed prior to the computation of the group delay. Default: `False`. smoothing : int, optional @@ -1241,8 +1241,8 @@ def plot_group_delay( self._spectrum_parameters = prior_spectrum_parameters sp = np.angle(sp) - if remove_impulse_delay: - sp = _remove_impulse_delay_from_phase( + if remove_ir_latency: + sp = _remove_ir_latency_from_phase( f, sp, self.time_data, self.sampling_rate_hz ) @@ -1337,14 +1337,14 @@ def plot_spectrogram( ) return fig, ax - def plot_coherence(self) -> tuple[Figure, Axes]: + def plot_coherence(self) -> tuple[Figure, list[Axes]]: """Plots coherence measurements if there are any. Returns ------- fig : `matplotlib.figure.Figure` Figure. - ax : `matplotlib.axes.Axes` + ax : list of `matplotlib.axes.Axes` Axes. """ @@ -1372,7 +1372,7 @@ def plot_phase( range_hz=[20, 20e3], unwrap: bool = False, smoothing: int = 0, - remove_impulse_delay: bool = False, + remove_ir_latency: bool = False, ) -> tuple[Figure, Axes]: """Plots phase of the frequency response, only available if the method for the spectrum `"standard"`. @@ -1388,7 +1388,7 @@ def plot_phase( When different than 0, the phase response is smoothed across the 1/smoothing-octave band. This only applies smoothing to the plot data. Default: 0. - remove_impulse_delay : bool, optional + remove_ir_latency : bool, optional If the signal is of type `"rir"` or `"ir"`, the delay of the impulse can be removed. Default: `False`. @@ -1415,12 +1415,12 @@ def plot_phase( self._spectrum_parameters["smoothe"] = prior_smoothing - if remove_impulse_delay: + if remove_ir_latency: assert self.signal_type in ( "rir", "ir", ), f"{self.signal_type} is not valid, use rir or ir" - ph = _remove_impulse_delay_from_phase( + ph = _remove_ir_latency_from_phase( f, ph, self.time_data, self.sampling_rate_hz ) diff --git a/dsptoolbox/standard_functions.py b/dsptoolbox/standard_functions.py index bb7ce75..fc7bbb3 100644 --- a/dsptoolbox/standard_functions.py +++ b/dsptoolbox/standard_functions.py @@ -28,7 +28,6 @@ _indices_above_threshold_dbfs, _detrend, _rms, - _fractional_latency, _fractional_delay_filter, ) from ._general_helpers import ( @@ -37,6 +36,7 @@ _fade, _check_format_in_path, _get_smoothing_factor_ema, + _fractional_latency, ) diff --git a/dsptoolbox/transfer_functions/_transfer_functions.py b/dsptoolbox/transfer_functions/_transfer_functions.py index c27a301..33f34d6 100644 --- a/dsptoolbox/transfer_functions/_transfer_functions.py +++ b/dsptoolbox/transfer_functions/_transfer_functions.py @@ -160,62 +160,6 @@ def _window_this_ir_tukey( return vec * window, window, start_sample -def _min_phase_ir_from_real_cepstrum(time_data: np.ndarray): - """Returns minimum-phase version of a time series using the real cepstrum - method. - - Parameters - ---------- - time_data : `np.ndarray` - Time series to compute the minimum phase version from. It is assumed - to have shape (time samples, channels). - - Returns - ------- - min_phase_time_data : `np.ndarray` - New time series. - - """ - return np.real( - np.fft.ifft( - _get_minimum_phase_spectrum_from_real_cepstrum(time_data), axis=0 - ) - ) - - -def _get_minimum_phase_spectrum_from_real_cepstrum(time_data: np.ndarray): - """Returns minimum-phase version of a time series using the real cepstrum - method. - - Parameters - ---------- - time_data : `np.ndarray` - Time series to compute the minimum phase version from. It is assumed - to have shape (time samples, channels). - - Returns - ------- - `np.ndarray` - New spectrum with minimum phase. - - """ - # Real cepstrum - y = np.real( - np.fft.ifft(np.log(np.abs(np.fft.fft(time_data, axis=0))), axis=0) - ) - - # Window in the cepstral domain, like obtaining hilbert transform - w = np.zeros(y.shape[0]) - w[0] = 1 - w[: len(w) // 2 - 1] = 2 - # If length is even, nyquist is exactly in the middle - if len(w) % 2 == 0: - w[len(w) // 2] = 1 - - # Windowing in cepstral domain and back to spectral domain - return np.exp(np.fft.fft(y * w[..., None], axis=0)) - - def _window_this_ir( vec, total_length: int, window_type: str = "hann", window_parameter=None ) -> tuple[np.ndarray, np.ndarray, np.ndarray]: @@ -329,7 +273,7 @@ def _warp_time_series(td: np.ndarray, warping_factor: float): def _get_harmonic_times( chirp_range_hz: list, - chirp_length_seconds: float, + chirp_length_s: float, n_harmonics: int, time_offset_seconds: float = 0.0, ) -> np.ndarray: @@ -342,7 +286,7 @@ def _get_harmonic_times( ---------- chirp_range_hz : list of length 2 The frequency range of the chirp. - chirp_length_seconds : float + chirp_length_s : float Length of chirp in seconds (without zero-padding). n_harmonics : int Number of harmonics to analyze. @@ -360,7 +304,7 @@ def _get_harmonic_times( - [1]: Weinzierl, S. Handbuch der Audiotechnik. Chapter 21. """ - rate = _get_chirp_rate(chirp_range_hz, chirp_length_seconds) + rate = _get_chirp_rate(chirp_range_hz, chirp_length_s) return time_offset_seconds - np.log2(np.arange(n_harmonics) + 2) / rate diff --git a/dsptoolbox/transfer_functions/transfer_functions.py b/dsptoolbox/transfer_functions/transfer_functions.py index 42496bd..dde03a0 100644 --- a/dsptoolbox/transfer_functions/transfer_functions.py +++ b/dsptoolbox/transfer_functions/transfer_functions.py @@ -11,8 +11,6 @@ _spectral_deconvolve, _window_this_ir_tukey, _window_this_ir, - _min_phase_ir_from_real_cepstrum, - _get_minimum_phase_spectrum_from_real_cepstrum, _warp_time_series, _get_harmonic_times, _trim_ir, @@ -20,12 +18,13 @@ from ..classes import Signal, Filter from ..classes._filter import _group_delay_filter from .._general_helpers import ( - _remove_impulse_delay_from_phase, + _remove_ir_latency_from_phase, + _min_phase_ir_from_real_cepstrum, + _get_minimum_phase_spectrum_from_real_cepstrum, _find_frequencies_above_threshold, _fractional_octave_smoothing, _correct_for_real_phase_spectrum, _wrap_phase, - _get_fractional_impulse_peak_index, ) from .._standard import ( _welch, @@ -33,7 +32,12 @@ _group_delay_direct, _pad_trim, ) -from ..standard_functions import fractional_delay, merge_signals, normalize +from ..standard_functions import ( + fractional_delay, + merge_signals, + normalize, + latency, +) from ..generators import dirac from ..filterbanks import linkwitz_riley_crossovers from ..room_acoustics._room_acoustics import _find_ir_start @@ -239,6 +243,9 @@ def window_ir( "rir", "ir", ), f"{signal.signal_type} is not a valid signal type. Use rir or ir." + assert ( + constant_percentage < 1 and constant_percentage >= 0 + ), "Constant percentage can not be larger than 1 or smaller than 0" assert offset_samples >= 0, "Offset must be positive" assert offset_samples <= constant_percentage * total_length_samples, ( "Offset is too large for the constant part of the window and its " @@ -792,7 +799,7 @@ def group_delay( signal: Signal, method="matlab", smoothing: int = 0, - remove_impulse_delay: bool = False, + remove_ir_latency: bool = False, ) -> tuple[np.ndarray, np.ndarray]: """Computes and returns group delay. @@ -808,7 +815,7 @@ def group_delay( smoothing : int, optional Octave fraction by which to apply smoothing. `0` avoids any smoothing of the group delay. Default: `0`. - remove_impulse_delay : bool, optional + remove_ir_latency : bool, optional If the signal is of type `"ir"` or `"rir"`, the impulse delay can be removed. Default: `False`. @@ -833,7 +840,7 @@ def group_delay( signal._spectrum_parameters = spec_parameters group_delays = np.zeros((sp.shape[0], sp.shape[1])) - if remove_impulse_delay: + if remove_ir_latency: assert signal.signal_type in ( "rir", "ir", @@ -841,7 +848,7 @@ def group_delay( f"{signal.signal_type} is not a valid signal type. Use ir " + "or rir" ) - sp = _remove_impulse_delay_from_phase( + sp = _remove_ir_latency_from_phase( f, np.angle(sp), signal.time_data, signal.sampling_rate_hz ) for n in range(signal.number_of_channels): @@ -856,7 +863,7 @@ def group_delay( for n in range(signal.number_of_channels): b = signal.time_data[:, n] - if remove_impulse_delay: + if remove_ir_latency: b = b[max(int(np.argmax(np.abs(b))) - 1, 0) :] a = [1] _, group_delays[:, n] = _group_delay_filter( @@ -988,7 +995,7 @@ def excess_group_delay( signal: Signal, method: str = "real cepstrum", smoothing: int = 0, - remove_impulse_delay: bool = False, + remove_ir_latency: bool = False, ) -> tuple[np.ndarray, np.ndarray]: """Computes excess group delay of an IR. @@ -1002,7 +1009,7 @@ def excess_group_delay( smoothing : int, optional Octave fraction by which to apply smoothing. `0` avoids any smoothing of the group delay. Default: `0`. - remove_impulse_delay : bool, optional + remove_ir_latency : bool, optional If the signal is of type `"ir"` or `"rir"`, the impulse delay can be removed. Default: `False`. @@ -1024,7 +1031,7 @@ def excess_group_delay( signal, smoothing=0, method="direct", - remove_impulse_delay=remove_impulse_delay, + remove_ir_latency=remove_ir_latency, ) ex_gd = gd - min_gd @@ -1448,9 +1455,8 @@ def warp_ir( def find_ir_latency(ir: Signal) -> np.ndarray: - """Find the subsample maximum of each channel of the IR using the root of - the analytical function. This value can be associated with the latency - of the impulse response. + """Find the subsample maximum of each channel of the IR using the its + minimum phase equivalent. Parameters ---------- @@ -1464,13 +1470,14 @@ def find_ir_latency(ir: Signal) -> np.ndarray: """ assert ir.signal_type in ("rir", "ir"), "Only valid for rir or ir" - return _get_fractional_impulse_peak_index(ir.time_data) + min_ir = min_phase_ir(ir) + return latency(ir, min_ir, 1) def harmonics_from_chirp_ir( ir: Signal, chirp_range_hz: list, - chirp_length_seconds: float, + chirp_length_s: float, n_harmonics: int = 5, offset_percentage: float = 0.05, ) -> list[Signal]: @@ -1484,7 +1491,7 @@ def harmonics_from_chirp_ir( chirp. chirp_range_hz : list of length 2 The frequency range of the chirp. - chirp_length_seconds : float + chirp_length_s : float Length of chirp in seconds (without zero-padding). n_harmonics : int, optional Number of harmonics to analyze. Default: 5. @@ -1525,9 +1532,7 @@ def harmonics_from_chirp_ir( td = np.roll(td, offsets, axis=0) # Get times of each harmonic - ts = _get_harmonic_times( - chirp_range_hz, chirp_length_seconds, n_harmonics + 1 - ) + ts = _get_harmonic_times(chirp_range_hz, chirp_length_s, n_harmonics + 1) time_harmonics_samples = len(td) + (ts * ir.sampling_rate_hz + 0.5).astype( int ) @@ -1636,21 +1641,28 @@ def harmonic_distortion_analysis( chirp_range_hz = [0, ir2.sampling_rate_hz // 2] passed_harmonics = True - elif type(ir) is Signal: + assert ( + chirp_length_s is not None + and chirp_range_hz is not None + and n_harmonics is not None + ), "Chirp parameters and number of harmonics cannot be None" + # Get different harmonics harm = harmonics_from_chirp_ir( ir, chirp_range_hz, chirp_length_s, n_harmonics, 0.01 ) - passed_harmonics = False - # Trim and window IR ir2 = ir.copy() - start, stop, _ = _trim_ir(ir2.time_data, ir.sampling_rate_hz, 10e-3) + start, stop, _ = _trim_ir( + ir2.time_data[:, 0], ir.sampling_rate_hz, 10e-3 + ) ir2.time_data = ir2.time_data[start:stop] ir2 = window_ir(ir2, len(ir2), constant_percentage=0.9)[0] ir2._spectrum_parameters["smoothe"] = smoothing + + passed_harmonics = False else: raise TypeError("Type for ir is not supported") diff --git a/tests/test_transfer_functions.py b/tests/test_transfer_functions.py index d559235..29086fe 100644 --- a/tests/test_transfer_functions.py +++ b/tests/test_transfer_functions.py @@ -352,7 +352,7 @@ def test_group_delay(self): dsp.transfer_functions.group_delay(ir, method="matlab", smoothing=4) dsp.transfer_functions.group_delay( - ir, method="direct", smoothing=4, remove_impulse_delay=True + ir, method="direct", smoothing=4, remove_ir_latency=True ) # Single-channel plausibility check @@ -429,7 +429,7 @@ def test_excess_group_delay(self): # Only works for some signal types dsp.transfer_functions.excess_group_delay(ir) dsp.transfer_functions.excess_group_delay( - ir, smoothing=3, remove_impulse_delay=True + ir, smoothing=3, remove_ir_latency=True ) with pytest.raises(AssertionError): s1 = dsp.Signal(None, ir.time_data, ir.sampling_rate_hz) @@ -464,6 +464,9 @@ def test_find_ir_latency(self): assert np.isclose(delay_samples, output, atol=0.4) + ir = dsp.Signal(join("examples", "data", "rir.wav"), signal_type="rir") + assert dsp.transfer_functions.find_ir_latency(ir) > 0 + def test_window_frequency_dependent(self): s = dsp.Signal(join("examples", "data", "rir.wav"), signal_type="rir") f, sp = dsp.transfer_functions.window_frequency_dependent( @@ -486,7 +489,7 @@ def test_harmonics_from_chirp_ir(self): dsp.transfer_functions.harmonics_from_chirp_ir( ir, chirp_range_hz=[20, 20e3], - chirp_length_seconds=2, + chirp_length_s=2, n_harmonics=2, ) @@ -496,21 +499,21 @@ def test_harmonic_distortion_analysis(self): dsp.transfer_functions.harmonic_distortion_analysis( ir, chirp_range_hz=[20, 20e3], - chirp_length_seconds=2, + chirp_length_s=2, n_harmonics=7, ) harm = dsp.transfer_functions.harmonics_from_chirp_ir( ir, chirp_range_hz=[20, 20e3], - chirp_length_seconds=2, + chirp_length_s=2, n_harmonics=2, ) harm.insert(0, dsp.transfer_functions.trim_ir(ir)[0]) dsp.transfer_functions.harmonic_distortion_analysis( harm, chirp_range_hz=None, - chirp_length_seconds=None, + chirp_length_s=None, n_harmonics=None, )