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.