WELCH
This function computes Welch’s spectral density estimate by splitting a signal into overlapping segments, computing a modified periodogram for each segment, and averaging the results.
Compared with a simple periodogram, Welch’s method reduces variance in spectral estimates by averaging across segments.
If segment periodograms are P_1(f), \dots, P_m(f), Welch estimates:
\hat{P}(f) = \frac{1}{m} \sum_{i=1}^{m} P_i(f)
or a median-based alternative when median averaging is selected.
Excel Usage
=WELCH(data, fs, window, nperseg, noverlap, nfft, detrend, return_onesided, scaling, average)
data(list[list], required): 2D range of time-series samples.fs(float, optional, default: 1): Sampling frequency in hertz (Hz).window(str, optional, default: “hann”): Window name applied to each segment.nperseg(int, optional, default: null): Segment length; null uses SciPy default.noverlap(int, optional, default: null): Overlap length between adjacent segments; null uses default.nfft(int, optional, default: null): FFT length; null uses segment length.detrend(str, optional, default: “constant”): Detrending method applied per segment.return_onesided(bool, optional, default: true): Return one-sided spectrum for real-valued input.scaling(str, optional, default: “density”): Spectral scaling mode.average(str, optional, default: “mean”): Averaging method across segment periodograms.
Returns (list[list]): 2D array with columns [frequency, power].
Example 1: Welch PSD with default averaging
Inputs:
| data | fs | window | nperseg | noverlap | nfft | detrend | return_onesided | scaling | average | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 0 | -1 | 0 | 1 | 0 | -1 | 0 | 1 | 0 | -1 | 0 | 1 | 0 | -1 | 8 | hann | 8 | 4 | constant | true | density | mean |
Excel formula:
=WELCH({0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1}, 8, "hann", 8, 4, , "constant", TRUE, "density", "mean")
Expected output:
| Result | |
|---|---|
| 0 | 0 |
| 1 | 0.0833333 |
| 2 | 0.333333 |
| 3 | 0.0833333 |
| 4 | 0 |
Example 2: Welch PSD with median averaging
Inputs:
| data | fs | window | nperseg | noverlap | nfft | detrend | return_onesided | scaling | average | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.8 | 0.1 | -0.9 | -0.2 | 1.1 | 0.2 | -1 | -0.1 | 0.9 | 0 | -1.1 | 0.1 | 1 | -0.2 | -0.8 | 8 | hann | 8 | 4 | 16 | constant | true | density | median |
Excel formula:
=WELCH({0,0.8,0.1,-0.9,-0.2,1.1,0.2,-1,-0.1,0.9,0,-1.1,0.1,1,-0.2,-0.8}, 8, "hann", 8, 4, 16, "constant", TRUE, "density", "median")
Expected output:
| Result | |
|---|---|
| 0 | 0.0000428932 |
| 0.5 | 0.0150076 |
| 1 | 0.0989203 |
| 1.5 | 0.284435 |
| 2 | 0.40062 |
| 2.5 | 0.288359 |
| 3 | 0.105885 |
| 3.5 | 0.0198086 |
| 4 | 0.000364277 |
Example 3: Welch with linear detrending
Inputs:
| data | fs | window | nperseg | noverlap | nfft | detrend | return_onesided | scaling | average | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.8 | 0.1 | -0.9 | -0.2 | 1.1 | 0.2 | -1 | -0.1 | 0.9 | 0 | -1.1 | 0.1 | 1 | -0.2 | -0.8 | 8 | hann | 8 | 2 | linear | true | density | mean |
Excel formula:
=WELCH({0,0.8,0.1,-0.9,-0.2,1.1,0.2,-1,-0.1,0.9,0,-1.1,0.1,1,-0.2,-0.8}, 8, "hann", 8, 2, , "linear", TRUE, "density", "mean")
Expected output:
| Result | |
|---|---|
| 0 | 0.00320211 |
| 1 | 0.141449 |
| 2 | 0.356001 |
| 3 | 0.0927694 |
| 4 | 0.00137051 |
Example 4: Two-sided Welch power spectrum
Inputs:
| data | fs | window | nperseg | noverlap | nfft | detrend | return_onesided | scaling | average | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 0 | -1 | 0 | 1 | 0 | -1 | 0 | 1 | 0 | -1 | 0 | 1 | 0 | -1 | 8 | hann | 8 | 4 | none | false | spectrum | mean |
Excel formula:
=WELCH({0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1}, 8, "hann", 8, 4, , "none", FALSE, "spectrum", "mean")
Expected output:
| Result | |
|---|---|
| 0 | 0 |
| 1 | 0.0625 |
| 2 | 0.25 |
| 3 | 0.0625 |
| -4 | 0 |
| -3 | 0.0625 |
| -2 | 0.25 |
| -1 | 0.0625 |
Python Code
import numpy as np
from scipy.signal import welch as scipy_welch
def welch(data, fs=1, window='hann', nperseg=None, noverlap=None, nfft=None, detrend='constant', return_onesided=True, scaling='density', average='mean'):
"""
Estimate the power spectral density of a time series using Welch's method.
See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.welch.html
This example function is provided as-is without any representation of accuracy.
Args:
data (list[list]): 2D range of time-series samples.
fs (float, optional): Sampling frequency in hertz (Hz). Default is 1.
window (str, optional): Window name applied to each segment. Default is 'hann'.
nperseg (int, optional): Segment length; null uses SciPy default. Default is None.
noverlap (int, optional): Overlap length between adjacent segments; null uses default. Default is None.
nfft (int, optional): FFT length; null uses segment length. Default is None.
detrend (str, optional): Detrending method applied per segment. Valid options: Constant, Linear, None. Default is 'constant'.
return_onesided (bool, optional): Return one-sided spectrum for real-valued input. Default is True.
scaling (str, optional): Spectral scaling mode. Valid options: Density, Spectrum. Default is 'density'.
average (str, optional): Averaging method across segment periodograms. Valid options: Mean, Median. Default is 'mean'.
Returns:
list[list]: 2D array with columns [frequency, power].
"""
try:
def to2d(x):
return [[x]] if not isinstance(x, list) else x
data = to2d(data)
if fs <= 0:
return "Error: fs must be greater than 0"
if detrend not in ("constant", "linear", "none"):
return "Error: detrend must be 'constant', 'linear', or 'none'"
if scaling not in ("density", "spectrum"):
return "Error: scaling must be 'density' or 'spectrum'"
if average not in ("mean", "median"):
return "Error: average must be 'mean' or 'median'"
if not isinstance(data, list) or not all(isinstance(row, list) for row in data):
return "Error: data must be a 2D list"
values = []
for row in data:
for item in row:
try:
values.append(float(item))
except (TypeError, ValueError):
continue
if len(values) < 2:
return "Error: data must contain at least two numeric values"
nperseg_arg = None if nperseg is None or nperseg <= 0 else nperseg
noverlap_arg = None if noverlap is None or noverlap < 0 else noverlap
nfft_arg = None if nfft is None or nfft <= 0 else nfft
detrend_arg = False if detrend == "none" else detrend
if nperseg_arg is not None and noverlap_arg is not None and noverlap_arg >= nperseg_arg:
return "Error: noverlap must be smaller than nperseg"
freqs, power = scipy_welch(
np.asarray(values, dtype=float),
fs=fs,
window=window,
nperseg=nperseg_arg,
noverlap=noverlap_arg,
nfft=nfft_arg,
detrend=detrend_arg,
return_onesided=return_onesided,
scaling=scaling,
average=average,
)
return [[float(freqs[i]), float(power[i])] for i in range(len(freqs))]
except Exception as e:
return f"Error: {str(e)}"Online Calculator
2D range of time-series samples.
Sampling frequency in hertz (Hz).
Window name applied to each segment.
Segment length; null uses SciPy default.
Overlap length between adjacent segments; null uses default.
FFT length; null uses segment length.
Detrending method applied per segment.
Return one-sided spectrum for real-valued input.
Spectral scaling mode.
Averaging method across segment periodograms.