How to restore the full signal from non-centered stft?

Trajektorie: <p>Posting for the first time, please tell me if I made a mistake.</p>
<p>Hi, I am working on a speech enhancement problem, with a STFT → modification in the frequency domain → iSTFT workflow.</p>
<p>My problem is, I have only managed to reconstruct the full signal that I passed into torch.stft when using the <code>center=True</code> option. Using the librosa implementation it seems like it could work. Maybe I am missing something, how I can achieve the same behavior in pytorch.<br>
The following is a dummy setup to transform a sine wave and transform it back.</p>
<pre><code class="lang-auto">import torch
import matplotlib.pyplot as plt
import numpy as np
import librosa

n_fft = 32
# Example singal:
signal = (torch.linspace(0, 2*n_fft, 2*n_fft) * 2 * np.pi).sin()

# Parameters

# stft parameters with and without center
centered = {
    'n_fft': n_fft,
    'hop_length': n_fft // 2,
    'win_length': n_fft,
    'window': torch.hann_window(n_fft),
    'center': True,
    'return_complex': True,
}
uncentered = centered.copy()
uncentered['center'] = False

# parameters for librosa stft for comparison
lr_centered =  {
    'n_fft': n_fft,
    'hop_length': n_fft // 2,
    'win_length': n_fft,
    'window': 'hann',
    'center': True,
}

lr_uncentered = lr_centered.copy()
lr_uncentered['center'] = False

# parameters for the istft
i_centered = {
    'n_fft': n_fft,
    'hop_length': n_fft // 2,
    'win_length': n_fft,
    'window': torch.hann_window(n_fft),
    'center': True,
    'return_complex': False,
    # 'length': len(signal),
}
i_uncentered = i_centered.copy()
i_uncentered['center'] = False

i_lr_centered = {
    'hop_length': n_fft // 2,
    'win_length': n_fft,
    'window': 'hann',
    'center': True,  
}
i_lr_uncentered = i_lr_centered.copy()
i_lr_uncentered['center'] = False

# stfts
stft_centered = signal.stft(**centered)
stft_uncentered = signal.stft(**uncentered)
stft_lr_centered = librosa.stft(signal.numpy(), **lr_centered)
stft_lr_uncentered = librosa.stft(signal.numpy(), **lr_uncentered)

# istfts
i_stft_centered = stft_centered.istft(**i_centered)
# i_stft_uncentered = stft_uncentered.istft(**i_uncentered) # ! this causes an error!
# RuntimeError: istft(CPUComplexFloatType[17, 3], n_fft=32, hop_length=16, win_length=32, 
# window=torch.FloatTensor{[32]}, center=0, normalized=0, onesided=None, length=None, 
# return_complex=0) window overlap add min: 0
i_stft_lr_centered = librosa.istft(stft_lr_centered, **i_lr_centered)
i_stft_lr_uncentered = librosa.istft(stft_lr_uncentered, **i_lr_uncentered)

# I used the centered parameters to see what happens:
i_stft_uncentered = stft_uncentered.istft(**i_centered)
</code></pre>
<p>With the code above, I get the following results:<br>
<strong>The input Signal:</strong></p>
<p><em>[Had to delete this picture, because new users can post only one]</em><br>
<strong>The stfts:</strong></p>
<p><em>[Had to delete this picture, because new users can post only one]</em></p>
<p><strong>And the reconstructed signals:</strong><br>
<img src="https://discuss.pytorch.org/uploads/default/original/3X/a/c/ac680d3f0e42d855c8e5903b9d7422b3579031c5.png" alt="reconstructed" data-base62-sha1="oBb3osiCiMA2opJSQpfVDyX85lH" width="432" height="288"></p>
<p>As we can see, the librosa implementation can handle both centered and uncentered stfts with complete reconstruction, but the pytorch implementation fails at <code>i_stft_uncentered = stft_uncentered.istft(**i_uncentered)</code> (see above).</p>
<p>Is this a limitation of the pytorch implementation, or am I missing a way to get the same behavior in pytorch?</p>

Trajektorie: <p>The STFTs:<br>
<img src="https://discuss.pytorch.org/uploads/default/original/3X/0/3/039192d284605f830d57e07d7663343dc49f79f7.png" alt="stfts" data-base62-sha1="vzjYJ7rWv8963q1BxcuuM7hmOr" width="432" height="288"></p>
<p>I hope I am not breaking any rules by circumventing the 1 media element restriction like this</p>

turian: <p>I am also curious about this:</p>
<pre><code class="lang-auto">Z = torch.stft(X, n_fft=512, center=False, window=torch.hann_window(512))
X2 = torch.istft(Z, n_fft=512, center=False, window=torch.hann_window(512))
</code></pre>
<p>gives:</p>
<pre><code class="lang-auto">~/opt/miniconda3/lib/python3.8/site-packages/torch/functional.py in istft(input, n_fft, hop_length, win_length, window, center, normalized, onesided, length, return_complex)
    652             length=length, return_complex=return_complex)
    653 
--&gt; 654     return _VF.istft(input, n_fft, hop_length, win_length, window, center,  # type: ignore
    655                      normalized, onesided, length, return_complex)
    656 

RuntimeError: istft(torch.DoubleTensor[257, 686, 2], n_fft=512, hop_length=128, win_length=512, window=torch.FloatTensor{[512]}, center=0, normalized=0, onesided=None, length=None, return_complex=0) window overlap add min: 0
</code></pre>

eagomez: <p>Same thing here. Did you figure out what may be the issue?</p>

miccio-dk: <p>I’m experiencing the same behavior.<br>
I’m providing a workaround at <a href="https://github.com/pytorch/pytorch/issues/62323#issuecomment-1006594200" rel="noopener nofollow ugc">pytorch/pytorch#62323</a>; it consists in only using the non-zero portion of the window.</p>
<p>Surprisingly enough, torch and scipy windows are constructed differently, which makes any comparison between <code>torch.stft</code> and <code>librosa.stft</code> even more difficult.</p>