def test_inverse_stft_window_fn(self): """Test that inverse_stft_window_fn has unit gain at each window phase.""" # Tuples of (frame_length, frame_step). test_configs = [ (256, 32), (256, 64), (128, 25), (127, 32), (128, 64), ] for (frame_length, frame_step) in test_configs: hann_window = window_ops.hann_window(frame_length, dtype=dtypes.float32) inverse_window_fn = spectral_ops.inverse_stft_window_fn(frame_step) inverse_window = inverse_window_fn(frame_length, dtype=dtypes.float32) with self.cached_session(use_gpu=True) as sess: hann_window, inverse_window = self.evaluate( [hann_window, inverse_window]) # Expect unit gain at each phase of the window. product_window = hann_window * inverse_window for i in range(frame_step): self.assertAllClose(1.0, np.sum(product_window[i::frame_step]))
def test_inverse_stft_window_fn_special_case(self): """Test inverse_stft_window_fn in special overlap = 3/4 case.""" # Cases in which frame_length is an integer multiple of 4 * frame_step are # special because they allow exact reproduction of the waveform with a # squared Hann window (Hann window in both forward and reverse transforms). # In the case where frame_length = 4 * frame_step, that combination # produces a constant gain of 1.5, and so the corrected window will be the # Hann window / 1.5. # Tuples of (frame_length, frame_step). test_configs = [ (256, 64), (128, 32), ] for (frame_length, frame_step) in test_configs: hann_window = window_ops.hann_window(frame_length, dtype=dtypes.float32) inverse_window_fn = spectral_ops.inverse_stft_window_fn(frame_step) inverse_window = inverse_window_fn(frame_length, dtype=dtypes.float32) with self.cached_session(use_gpu=True) as sess: hann_window, inverse_window = self.evaluate( [hann_window, inverse_window]) self.assertAllClose(hann_window, inverse_window * 1.5)
def test_stft_round_trip(self, signal_length, frame_length, frame_step, fft_length, np_rtype, threshold, corrected_threshold): # Generate a random white Gaussian signal. signal = np.random.normal(size=signal_length).astype(np_rtype) stft = spectral_ops.stft(signal, frame_length, frame_step, fft_length, pad_end=False) inverse_stft = spectral_ops.inverse_stft(stft, frame_length, frame_step, fft_length) inverse_stft_corrected = spectral_ops.inverse_stft( stft, frame_length, frame_step, fft_length, window_fn=spectral_ops.inverse_stft_window_fn(frame_step)) inverse_stft, inverse_stft_corrected = self.evaluate( [inverse_stft, inverse_stft_corrected]) # Truncate signal to the size of inverse stft. signal = signal[:inverse_stft.shape[0]] # Ignore the frame_length samples at either edge. signal = signal[frame_length:-frame_length] inverse_stft = inverse_stft[frame_length:-frame_length] inverse_stft_corrected = inverse_stft_corrected[ frame_length:-frame_length] # Check that the inverse and original signal are close up to a scale # factor. inverse_stft_scaled = inverse_stft / np.mean(np.abs(inverse_stft)) signal_scaled = signal / np.mean(np.abs(signal)) self.assertLess(np.std(inverse_stft_scaled - signal_scaled), threshold) # Check that the inverse with correction and original signal are close. self.assertLess(np.std(inverse_stft_corrected - signal), corrected_threshold)
def test_inverse_stft_window_fn_special_case(self): """Test inverse_stft_window_fn in special overlap = 3/4 case.""" # Cases in which frame_length is an integer multiple of 4 * frame_step are # special because they allow exact reproduction of the waveform with a # squared Hann window (Hann window in both forward and reverse transforms). # In the case where frame_length = 4 * frame_step, that combination # produces a constant gain of 1.5, and so the corrected window will be the # Hann window / 1.5. # Tuples of (frame_length, frame_step). test_configs = [ (256, 64), (128, 32), ] for (frame_length, frame_step) in test_configs: hann_window = window_ops.hann_window(frame_length, dtype=dtypes.float32) inverse_window_fn = spectral_ops.inverse_stft_window_fn(frame_step) inverse_window = inverse_window_fn(frame_length, dtype=dtypes.float32) with self.cached_session(use_gpu=True) as sess: hann_window, inverse_window = self.evaluate( [hann_window, inverse_window]) self.assertAllClose(hann_window, inverse_window * 1.5)
def test_stft_round_trip(self): # Tuples of (signal_length, frame_length, frame_step, fft_length, # threshold, corrected_threshold). test_configs = [ # 87.5% overlap. (4096, 256, 32, 256, 1e-5, 1e-6), # 75% overlap. (4096, 256, 64, 256, 1e-5, 1e-6), # Odd frame hop. (4096, 128, 25, 128, 1e-3, 1e-6), # Odd frame length. (4096, 127, 32, 128, 1e-3, 1e-6), # 50% overlap. (4096, 128, 64, 128, 0.40, 1e-6), ] for (signal_length, frame_length, frame_step, fft_length, threshold, corrected_threshold) in test_configs: # Generate a random white Gaussian signal. signal = random_ops.random_normal([signal_length]) with spectral_ops_test_util.fft_kernel_label_map(), ( self.cached_session(use_gpu=True)) as sess: stft = spectral_ops.stft(signal, frame_length, frame_step, fft_length, pad_end=False) inverse_stft = spectral_ops.inverse_stft( stft, frame_length, frame_step, fft_length) inverse_stft_corrected = spectral_ops.inverse_stft( stft, frame_length, frame_step, fft_length, window_fn=spectral_ops.inverse_stft_window_fn(frame_step)) signal, inverse_stft, inverse_stft_corrected = sess.run( [signal, inverse_stft, inverse_stft_corrected]) # Truncate signal to the size of inverse stft. signal = signal[:inverse_stft.shape[0]] # Ignore the frame_length samples at either edge. signal = signal[frame_length:-frame_length] inverse_stft = inverse_stft[frame_length:-frame_length] inverse_stft_corrected = inverse_stft_corrected[ frame_length:-frame_length] # Check that the inverse and original signal are close up to a scale # factor. inverse_stft_scaled = inverse_stft / np.mean( np.abs(inverse_stft)) signal_scaled = signal / np.mean(np.abs(signal)) self.assertLess(np.std(inverse_stft_scaled - signal_scaled), threshold) # Check that the inverse with correction and original signal are close. self.assertLess(np.std(inverse_stft_corrected - signal), corrected_threshold)
def test_inverse_stft_window_fn(self, frame_length, frame_step): """Test that inverse_stft_window_fn has unit gain at each window phase.""" hann_window = window_ops.hann_window(frame_length, dtype=dtypes.float32) inverse_window_fn = spectral_ops.inverse_stft_window_fn(frame_step) inverse_window = inverse_window_fn(frame_length, dtype=dtypes.float32) hann_window, inverse_window = self.evaluate([hann_window, inverse_window]) # Expect unit gain at each phase of the window. product_window = hann_window * inverse_window for i in range(frame_step): self.assertAllClose(1.0, np.sum(product_window[i::frame_step]))
def test_inverse_stft_window_fn_special_case(self, frame_length, frame_step): """Test inverse_stft_window_fn in special overlap = 3/4 case.""" # Cases in which frame_length is an integer multiple of 4 * frame_step are # special because they allow exact reproduction of the waveform with a # squared Hann window (Hann window in both forward and reverse transforms). # In the case where frame_length = 4 * frame_step, that combination # produces a constant gain of 1.5, and so the corrected window will be the # Hann window / 1.5. hann_window = window_ops.hann_window(frame_length, dtype=dtypes.float32) inverse_window_fn = spectral_ops.inverse_stft_window_fn(frame_step) inverse_window = inverse_window_fn(frame_length, dtype=dtypes.float32) self.assertAllClose(hann_window, inverse_window * 1.5)
def test_stft_round_trip(self): # Tuples of (signal_length, frame_length, frame_step, fft_length, # threshold, corrected_threshold). test_configs = [ # 87.5% overlap. (4096, 256, 32, 256, 1e-5, 1e-6), # 75% overlap. (4096, 256, 64, 256, 1e-5, 1e-6), # Odd frame hop. (4096, 128, 25, 128, 1e-3, 1e-6), # Odd frame length. (4096, 127, 32, 128, 1e-3, 1e-6), # 50% overlap. (4096, 128, 64, 128, 0.40, 1e-6), ] for (signal_length, frame_length, frame_step, fft_length, threshold, corrected_threshold) in test_configs: # Generate a random white Gaussian signal. signal = random_ops.random_normal([signal_length]) with spectral_ops_test_util.fft_kernel_label_map(), ( self.cached_session(use_gpu=True)) as sess: stft = spectral_ops.stft(signal, frame_length, frame_step, fft_length, pad_end=False) inverse_stft = spectral_ops.inverse_stft(stft, frame_length, frame_step, fft_length) inverse_stft_corrected = spectral_ops.inverse_stft( stft, frame_length, frame_step, fft_length, window_fn=spectral_ops.inverse_stft_window_fn(frame_step)) signal, inverse_stft, inverse_stft_corrected = sess.run( [signal, inverse_stft, inverse_stft_corrected]) # Truncate signal to the size of inverse stft. signal = signal[:inverse_stft.shape[0]] # Ignore the frame_length samples at either edge. signal = signal[frame_length:-frame_length] inverse_stft = inverse_stft[frame_length:-frame_length] inverse_stft_corrected = inverse_stft_corrected[ frame_length:-frame_length] # Check that the inverse and original signal are close up to a scale # factor. inverse_stft_scaled = inverse_stft / np.mean(np.abs(inverse_stft)) signal_scaled = signal / np.mean(np.abs(signal)) self.assertLess(np.std(inverse_stft_scaled - signal_scaled), threshold) # Check that the inverse with correction and original signal are close. self.assertLess(np.std(inverse_stft_corrected - signal), corrected_threshold)
def test_inverse_stft_window_fn(self): """Test that inverse_stft_window_fn has unit gain at each window phase.""" # Tuples of (frame_length, frame_step). test_configs = [ (256, 32), (256, 64), (128, 25), (127, 32), (128, 64), ] for (frame_length, frame_step) in test_configs: hann_window = window_ops.hann_window(frame_length, dtype=dtypes.float32) inverse_window_fn = spectral_ops.inverse_stft_window_fn(frame_step) inverse_window = inverse_window_fn(frame_length, dtype=dtypes.float32) with self.cached_session(use_gpu=True) as sess: hann_window, inverse_window = self.evaluate( [hann_window, inverse_window]) # Expect unit gain at each phase of the window. product_window = hann_window * inverse_window for i in range(frame_step): self.assertAllClose(1.0, np.sum(product_window[i::frame_step]))