# reproduce Scipy's stft

I failed to reproduce Scipy's stft. When I have tried to remove all the possible modifications and go the minimal example, I converge to the following:

from scipy import signal
from scipy import fft
import numpy as np

n = 4
np.random.seed(0)
x = np.random.normal(size=n)

stftOut = signal.stft(
x, fs=1.0, window='hann', nperseg=n,
noverlap=None, nfft=n, detrend=False,
return_onesided=True, boundary=None,
)[2]
rfftOut = fft.rfft(x * signal.windows.hann(n) / (signal.windows.hann(n)).sum())


Multiple tests showed that the larger the window, the smaller the error. It seems that I am missing something about the boundary conditions. What is it?

Two things:

1. signal.stft uses get_window() to generate its windows, which by default returns periodic, non-symmetrical windows:

If True (default), create a “periodic” window, ready to use with ifftshift and be multiplied by the result of an FFT (see also fftfreq). If False, create a “symmetric” window, for use in filter design.

On the contrary, signal.windows such as signal.windows.hann() returns a symmetrical window by default, but you can specify sym=False if you want a periodic window.

Doing

win = signal.get_window('hann', n)
rfftOut = fft.rfft(x * win / win.sum())


or

win = signal.windows.hann(n, sym=False)
rfftOut = fft.rfft(x * win / win.sum())


gives:

2. From the scipy.signal.stft documentation:

noverlap: int, optional

Number of points to overlap between segments. If None, noverlap = nperseg // 2

You'll want to change the overlap to noverlap = n-1 (I don't think it will make a difference in your example, but good to know regardless).

Periodic vs symmetrical windows

Periodic windows are preferred for spectral analysis because it enables a windowed signal to have the perfect periodic extension implicit in the discrete Fourier transform. For windows such as Hamming or Hann with even length, which are usually used in OLA processing, only periodic windows can satisfy COLA constraints.
The way the periodic window of length $$L$$ is generated is by computing a symmetric window of length $$L + 1$$ and returning the first $$L$$ points.