def _dct2_1d(signals, name=None): """Computes the type II 1D Discrete Cosine Transform (DCT) of `signals`. Args: signals: A `[..., samples]` `float32` `Tensor` containing the signals to take the DCT of. name: An optional name for the operation. Returns: A `[..., samples]` `float32` `Tensor` containing the DCT of `signals`. """ with ops.name_scope(name, 'dct', [signals]): # We use the FFT to compute the DCT and TensorFlow only supports float32 for # FFTs at the moment. signals = ops.convert_to_tensor(signals, dtype=dtypes.float32) axis_dim = signals.shape[-1].value or array_ops.shape(signals)[-1] axis_dim_float = math_ops.to_float(axis_dim) scale = 2.0 * math_ops.exp(math_ops.complex( 0.0, -math.pi * math_ops.range(axis_dim_float) / (2.0 * axis_dim_float))) rfft = spectral_ops.rfft(signals, fft_length=[2 * axis_dim])[..., :axis_dim] dct2 = math_ops.real(rfft * scale) return dct2
def stft(signals, frame_length, frame_step, fft_length=None, window_fn=functools.partial(window_ops.hann_window, periodic=True), pad_end=False, name=None): """Computes the [Short-time Fourier Transform][stft] of `signals`. Implemented with GPU-compatible ops and supports gradients. Args: signals: A `[..., samples]` `float32` `Tensor` of real-valued signals. frame_length: An integer scalar `Tensor`. The window length in samples. frame_step: An integer scalar `Tensor`. The number of samples to step. fft_length: An integer scalar `Tensor`. The size of the FFT to apply. If not provided, uses the smallest power of 2 enclosing `frame_length`. window_fn: A callable that takes a window length and a `dtype` keyword argument and returns a `[window_length]` `Tensor` of samples in the provided datatype. If set to `None`, no windowing is used. pad_end: Whether to pad the end of `signals` with zeros when the provided frame length and step produces a frame that lies partially past its end. name: An optional name for the operation. Returns: A `[..., frames, fft_unique_bins]` `Tensor` of `complex64` STFT values where `fft_unique_bins` is `fft_length // 2 + 1` (the unique components of the FFT). Raises: ValueError: If `signals` is not at least rank 1, `frame_length` is not scalar, or `frame_step` is not scalar. [stft]: https://en.wikipedia.org/wiki/Short-time_Fourier_transform """ with ops.name_scope(name, 'stft', [signals, frame_length, frame_step]): signals = ops.convert_to_tensor(signals, name='signals') signals.shape.with_rank_at_least(1) frame_length = ops.convert_to_tensor(frame_length, name='frame_length') frame_length.shape.assert_has_rank(0) frame_step = ops.convert_to_tensor(frame_step, name='frame_step') frame_step.shape.assert_has_rank(0) if fft_length is None: fft_length = _enclosing_power_of_two(frame_length) else: fft_length = ops.convert_to_tensor(fft_length, name='fft_length') framed_signals = shape_ops.frame( signals, frame_length, frame_step, pad_end=pad_end) # Optionally window the framed signals. if window_fn is not None: window = window_fn(frame_length, dtype=framed_signals.dtype) framed_signals *= window # spectral_ops.rfft produces the (fft_length/2 + 1) unique components of the # FFT of the real windowed signals in framed_signals. return spectral_ops.rfft(framed_signals, [fft_length])
def testRFFT(self): self._VerifyFftMethod( INNER_DIMS_1D, np.real, lambda x: np.fft.rfft(x, n=x.shape[-1]), lambda x: spectral_ops.rfft(x, fft_length=[x.shape[-1].value]))
def testRFFT(self): self._VerifyFftMethod( INNER_DIMS_1D, np.real, lambda x: np.fft.rfft(x, n=x.shape[-1]), lambda x: spectral_ops.rfft(x, fft_length=[x.shape[-1].value]))
def stft(signals, frame_length, frame_step, fft_length=None, window_fn=functools.partial(window_ops.hann_window, periodic=True), pad_end=False, name=None): """Computes the [Short-time Fourier Transform][stft] of `signals`. Implemented with GPU-compatible ops and supports gradients. Args: signals: A `[..., samples]` `float32` `Tensor` of real-valued signals. frame_length: An integer scalar `Tensor`. The window length in samples. frame_step: An integer scalar `Tensor`. The number of samples to step. fft_length: An integer scalar `Tensor`. The size of the FFT to apply. If not provided, uses the smallest power of 2 enclosing `frame_length`. window_fn: A callable that takes a window length and a `dtype` keyword argument and returns a `[window_length]` `Tensor` of samples in the provided datatype. If set to `None`, no windowing is used. pad_end: Whether to pad the end of `signals` with zeros when the provided frame length and step produces a frame that lies partially past its end. name: An optional name for the operation. Returns: A `[..., frames, fft_unique_bins]` `Tensor` of `complex64` STFT values where `fft_unique_bins` is `fft_length // 2 + 1` (the unique components of the FFT). Raises: ValueError: If `signals` is not at least rank 1, `frame_length` is not scalar, or `frame_step` is not scalar. [stft]: https://en.wikipedia.org/wiki/Short-time_Fourier_transform """ with ops.name_scope(name, 'stft', [signals, frame_length, frame_step]): signals = ops.convert_to_tensor(signals, name='signals') signals.shape.with_rank_at_least(1) frame_length = ops.convert_to_tensor(frame_length, name='frame_length') frame_length.shape.assert_has_rank(0) frame_step = ops.convert_to_tensor(frame_step, name='frame_step') frame_step.shape.assert_has_rank(0) if fft_length is None: fft_length = _enclosing_power_of_two(frame_length) else: fft_length = ops.convert_to_tensor(fft_length, name='fft_length') framed_signals = shape_ops.frame(signals, frame_length, frame_step, pad_end=pad_end) # Optionally window the framed signals. if window_fn is not None: window = window_fn(frame_length, dtype=framed_signals.dtype) framed_signals *= window # spectral_ops.rfft produces the (fft_length/2 + 1) unique components of the # FFT of the real windowed signals in framed_signals. return spectral_ops.rfft(framed_signals, [fft_length])