def test_normalization_exceptions(): # Call without numpy array with raises(ValueError): fft.normalization(1, 1, 44100, 'rms') # Invalid normalization with raises(ValueError): fft.normalization(np.array([1]), 1, 44100, 'goofy')
def test_normalization_with_window(): """ Test if the window cancels out if applying the normalization and inverse normalization. """ # test with window as list and numpy array windows = [[1, 1, 1, 1], np.array([1, 1, 1, 1])] fft_norms = ['unitary', 'amplitude', 'rms', 'power', 'psd'] for window in windows: for fft_norm in fft_norms: print(f"testing: {window}, {fft_norm}") spec = fft.normalization(np.array([.5, 1, .5]), 4, 44100, fft_norm, window=window) spec = fft.normalization(spec, 4, 44100, fft_norm, inverse=True, window=window) npt.assert_allclose(spec, np.array([.5, 1, .5]), atol=1e-15)
def test_normalization_with_window_value_error(): """ Test if normalization throws a ValueError if the window has the wrong length. """ with raises(ValueError): # n_samples=5, and len(window)=5 fft.normalization(np.array([.5, 1, .5]), 4, 44100, 'amplitude', window=[1, 1, 1, 1, 1])
def _arithmetic(data: tuple, domain: str, operation: Callable): """Apply arithmetic operations.""" # check input and obtain meta data of new signal sampling_rate, n_samples, fft_norm, times, frequencies, audio_type = \ _assert_match_for_arithmetic(data, domain) # apply arithmetic operation result = _get_arithmetic_data(data[0], n_samples, domain) for d in range(1, len(data)): result = operation( result, _get_arithmetic_data(data[d], n_samples, domain)) # check if to return an audio object if audio_type == Signal: # apply desired fft normalization if domain == 'freq': result = fft.normalization(result, n_samples, sampling_rate, fft_norm) result = Signal( result, sampling_rate, n_samples, domain, fft_norm=fft_norm) elif audio_type == TimeData: result = TimeData(result, times) elif audio_type == FrequencyData: result = FrequencyData(result, frequencies, fft_norm) return result
def test_normalization_none(impulse_stub): spec_out = fft.normalization(impulse_stub.freq.copy(), impulse_stub.n_samples, impulse_stub.sampling_rate, impulse_stub.fft_norm, inverse=False) npt.assert_allclose(spec_out, impulse_stub.freq, atol=10 * np.finfo(float).eps) spec_out = fft.normalization(impulse_stub.freq.copy(), impulse_stub.n_samples, impulse_stub.sampling_rate, impulse_stub.fft_norm, inverse=True) npt.assert_allclose(spec_out, impulse_stub.freq, atol=10 * np.finfo(float).eps)
def test_normalization_single_sided_multi_channel_even_samples(): # single sided test spectrum v = 1 / 3 + 1 / 3j vsq = v * np.abs(v) tile = (4, 2, 1) spec_single = np.tile(np.array([v, v, v]), tile) # valid number of samples of time signal corresponding to spec_single N = 4 # time signal with even number of samples Nsq = N**2 # factor for power and psd normalization fs = 40 # arbitrary sampling frequency for psd normalization # expected results for even number of samples sqrt2 = np.sqrt(2) truth = { 'unitary': np.array([v, v * 2, v]), 'amplitude': np.array([v / N, v / N * 2, v / N]), 'rms': np.array([v / N, v / N / sqrt2 * 2, v / N]), 'power': np.array([vsq / Nsq, vsq / Nsq * 2, vsq / Nsq]), 'psd': np.array([vsq / N / fs, vsq / N / fs * 2, vsq / N / fs]) } for normalization in truth: print(f"Assesing normalization: '{normalization}'") spec_out = fft.normalization(spec_single.copy(), N, fs, normalization, inverse=False) npt.assert_allclose(spec_out, np.tile(truth[normalization], tile), atol=1e-15) print(f"Assesing normalization: '{normalization}' (inverse)") spec_out_inv = fft.normalization(spec_out, N, fs, normalization, inverse=True) npt.assert_allclose(spec_out_inv, spec_single, atol=1e-15)
def fft_norm(self, value): """ The normalization for the Discrete Fourier Transform (DFT). See :py:func:`~pyfar.dsp.fft.normalization` for more information. """ # check input if value not in self._VALID_FFT_NORMS: raise ValueError(("Invalid FFT normalization. Has to be " f"{', '.join(self._VALID_FFT_NORMS)}, but found " f"'{value}'")) # apply new normalization if Signal is in frequency domain if self._fft_norm != value and self._domain == 'freq': # de-normalize self._data = fft.normalization( self._data, self._n_samples, self._sampling_rate, self._fft_norm, inverse=True) # normalize self._data = fft.normalization( self._data, self._n_samples, self._sampling_rate, value, inverse=False) self._fft_norm = value
def test_normalization_both_sided_single_channel(): # single sided test spectrum v = 1 / 3 + 1 / 3j vsq = v * np.abs(v) spec_single = np.array([v, v, v]) # valid number of samples of time signal corresponding to spec_single N = 3 # time signal with even number of samples Nsq = N**2 # factor for power and psd normalization fs = 30 # arbitrary sampling frequency for psd normalization # expected results for even number of samples truth = { 'unitary': np.array([v, v, v]), 'amplitude': np.array([v / N, v / N, v / N]), 'power': np.array([vsq / Nsq, vsq / Nsq, vsq / Nsq]), 'psd': np.array([vsq / N / fs, vsq / N / fs, vsq / N / fs]) } for normalization in truth: print(f"Assesing normalization: '{normalization}'") spec_out = fft.normalization(spec_single.copy(), N, fs, normalization, inverse=False, single_sided=False) npt.assert_allclose(spec_out, truth[normalization], atol=1e-15) print(f"Assesing normalization: '{normalization}' (inverse)") spec_out_inv = fft.normalization(spec_out, N, fs, normalization, inverse=True, single_sided=False) npt.assert_allclose(spec_out_inv, spec_single, atol=1e-15)
def _get_arithmetic_data(data, n_samples, domain): """ Return data in desired domain without any fft normalization. Parameters ---------- data : Signal, array like, number Input data n_samples : Number of samples of data if data is a Signal (required for fft normalization). domain : 'time', 'freq' Domain in which the data is returned Returns ------- data_out : numpy array Data in desired domain without any fft normalization if data is a Signal. `np.asarray(data)` otherwise. """ if isinstance(data, (Signal, TimeData, FrequencyData)): # get signal in correct domain if domain == "time": data_out = data.time.copy() elif domain == "freq": data_out = data.freq.copy() if isinstance(data, Signal): if data.fft_norm != 'none': # remove current fft normalization data_out = fft.normalization( data_out, n_samples, data.sampling_rate, data.fft_norm, inverse=True) else: raise ValueError( f"domain must be 'time' or 'freq' but found {domain}") else: data_out = np.asarray(data) return data_out