STFT
The Short-Time Fourier Transform (STFT) is used to quantify the change of a nonstationary signal’s frequency and phase content over time.
It is computed by dividing a longer time signal into shorter segments of equal length and then computing the Fourier transform separately on each shorter segment.
Excel Usage
=STFT(x, fs, window, nperseg, noverlap, nfft, spectral_detrend, return_onesided, boundary, padded)
x(list[list], required): Time series of measurement values.fs(float, optional, default: 1): Sampling frequency.window(str, optional, default: “hann”): Desired window to use.nperseg(int, optional, default: 256): Length of each segment.noverlap(int, optional, default: null): Number of points to overlap between segments.nfft(int, optional, default: null): Length of the FFT used.spectral_detrend(str, optional, default: “False”): Specifies how to detrend each segment.return_onesided(bool, optional, default: true): If True, return a one-sided spectrum.boundary(str, optional, default: “zeros”): Specifies whether the input signal is extended at both ends.padded(bool, optional, default: true): If True, zero-pad signal to fit segments.
Returns (list[list]): A 2D array representing the STFT grid (interleaved real and imaginary).
Example 1: Basic STFT
Inputs:
| x | ||||||||
|---|---|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 4 | 3 | 2 | 1 |
Excel formula:
=STFT({1,2,3,4,5,4,3,2,1})
Expected output:
| Result | |||
|---|---|---|---|
| 0 | 5 | 10 | |
| 0.0 (Re) | 1.64381 | 3.21239 | 0.143807 |
| 0.0 (Im) | 0 | 0 | 0 |
| 0.1111111111111111 (Re) | -0.694229 | -1.86154 | 0.0557706 |
| 0.1111111111111111 (Im) | 0.95196 | -0.828119 | -0.123841 |
| 0.2222222222222222 (Re) | -0.0772516 | 0.154503 | -0.0772516 |
| 0.2222222222222222 (Im) | -0.317934 | 0.400537 | -0.0826035 |
| 0.3333333333333333 (Re) | -0.0719035 | 0.143807 | -0.0719035 |
| 0.3333333333333333 (Im) | -0.018854 | -0.0156369 | 0.034491 |
| 0.4444444444444444 (Re) | 0.0214811 | -0.0429621 | 0.0214811 |
| 0.4444444444444444 (Im) | 0.0291447 | -0.0703818 | 0.0412371 |
Example 2: STFT with constant detrending
Inputs:
| x | spectral_detrend | nperseg | |||||||
|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 0 | -1 | 0 | 1 | 0 | -1 | constant | 4 |
Excel formula:
=STFT({0,1,0,-1,0,1,0,-1}, "constant", 4)
Expected output:
| Result | |||||
|---|---|---|---|---|---|
| 0 | 2 | 4 | 6 | 8 | |
| 0.0 (Re) | 0 | 0 | 0 | 0 | 0 |
| 0.0 (Im) | 0 | 0 | 0 | 0 | 0 |
| 0.25 (Re) | 0.125 | 0 | 0 | 0 | -0.125 |
| 0.25 (Im) | 0.25 | -0.5 | 0.5 | -0.5 | 0.25 |
| 0.5 (Re) | -0.25 | 0 | 0 | 0 | 0.25 |
| 0.5 (Im) | 0 | 0 | 0 | 0 | 0 |
Example 3: STFT without boundary extension and padding
Inputs:
| x | boundary | padded | nperseg | noverlap | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 2 | 1 | 2 | 1 | 2 | 1 | 2 | None | false | 4 | 2 |
Excel formula:
=STFT({1,2,1,2,1,2,1,2}, "None", FALSE, 4, 2)
Expected output:
| Result | |||
|---|---|---|---|
| 2 | 4 | 6 | |
| 0.0 (Re) | 1.5 | 1.5 | 1.5 |
| 0.0 (Im) | 0 | 0 | 0 |
| 0.25 (Re) | -0.5 | -0.5 | -0.5 |
| 0.25 (Im) | 0 | 0 | 0 |
| 0.5 (Re) | -0.5 | -0.5 | -0.5 |
| 0.5 (Im) | 0 | 0 | 0 |
Example 4: STFT with scalar-compatible input
Inputs:
| x |
|---|
| 3 |
Excel formula:
=STFT(3)
Expected output:
| Result | |
|---|---|
| 0 | |
| 0.0 (Re) | 3 |
| 0.0 (Im) | 0 |
Python Code
Show Code
import numpy as np
from scipy.signal import stft as scipy_stft
def stft(x, fs=1, window='hann', nperseg=256, noverlap=None, nfft=None, spectral_detrend='False', return_onesided=True, boundary='zeros', padded=True):
"""
Compute the Short Time Fourier Transform (STFT).
See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.stft.html
This example function is provided as-is without any representation of accuracy.
Args:
x (list[list]): Time series of measurement values.
fs (float, optional): Sampling frequency. Default is 1.
window (str, optional): Desired window to use. Default is 'hann'.
nperseg (int, optional): Length of each segment. Default is 256.
noverlap (int, optional): Number of points to overlap between segments. Default is None.
nfft (int, optional): Length of the FFT used. Default is None.
spectral_detrend (str, optional): Specifies how to detrend each segment. Valid options: Constant, Linear, None. Default is 'False'.
return_onesided (bool, optional): If True, return a one-sided spectrum. Default is True.
boundary (str, optional): Specifies whether the input signal is extended at both ends. Valid options: Zeros, Even, Odd, Constant, None. Default is 'zeros'.
padded (bool, optional): If True, zero-pad signal to fit segments. Default is True.
Returns:
list[list]: A 2D array representing the STFT grid (interleaved real and imaginary).
"""
try:
def to_1d(v):
if isinstance(v, list):
if all(isinstance(row, list) for row in v):
return np.array([float(x) for row in v for x in row], dtype=float)
return np.array([float(x) for x in v], dtype=float)
return np.array([float(v)], dtype=float)
x_arr = to_1d(x)
detrend = spectral_detrend
if detrend == "False":
detrend = False
bound = boundary
if bound == "None":
bound = None
f, t, zxx = scipy_stft(
x_arr,
fs=float(fs),
window=window,
nperseg=int(nperseg),
noverlap=int(noverlap) if noverlap is not None else None,
nfft=int(nfft) if nfft is not None else None,
detrend=detrend,
return_onesided=bool(return_onesided),
boundary=bound,
padded=bool(padded)
)
output = []
header = [""] + t.tolist()
output.append(header)
for i, freq in enumerate(f):
row_real = [f"{freq} (Re)"] + zxx[i, :].real.tolist()
row_imag = [f"{freq} (Im)"] + zxx[i, :].imag.tolist()
output.append(row_real)
output.append(row_imag)
return output
except Exception as e:
return f"Error: {str(e)}"Online Calculator
Time series of measurement values.
Sampling frequency.
Desired window to use.
Length of each segment.
Number of points to overlap between segments.
Length of the FFT used.
Specifies how to detrend each segment.
If True, return a one-sided spectrum.
Specifies whether the input signal is extended at both ends.
If True, zero-pad signal to fit segments.