welch
Builtin index · Signal processing
result = welch(x, fs, [nperseg=min(256,len(x))], [noverlap=nperseg/2], [window="hann"])
Input: x, fs, nperseg, noverlap, window · Output: result
What it is
x: a length-N real vector; fs (number, Hz): sample rate. nperseg (optional number): samples per segment; noverlap (optional number): overlap between segments; window (optional string, e.g. "hann"/"hamming"/"blackman"): window applied to each segment.
Overloads
One call shape — this function is not overloaded.
| Code | Input | Output | Description |
result = welch(x, fs, [nperseg=min(256,len(x))], [noverlap=nperseg/2], [window="hann"]) | x vectorx: a length-N real vector.fs numberfs (number, Hz): sample rate.nperseg number, optional (default min(256,len(x)))nperseg (optional number): samples per segment.noverlap number, optional (default nperseg/2)noverlap (optional number): overlap between segments.window string, optional (default "hann")window (optional string, e.g. | result vector | Returns a spectrum of nperseg/2 + 1 one-sided bins (DC to Nyquist), stamped norm = "density" — SciPy's "density" scaling, units²/Hz. Welch's method segments x into overlapping windowed frames and averages their squared-magnitude spectra. Changed in v0.2.4: this used to return a bare vector whose frequency axis you had to rebuild by hand, which is exactly the mislabelling toolkit-signal.md §2 exists to prevent; it now carries its own axis, so P.freq is the axis, P.df the bin spacing (Fs/nperseg — the *segment* length, not length(x)) and P.N the segment length. The change is back-compatible: a density reads as a plain real vector everywhere one was accepted before, so length(P), max(P), arithmetic and plotting are unaffected, and linspace(0, fs/2, length(P)) still gives the same axis. band_power(P, f0, f1) integrates it over a band, returning mean-square power whose square root is the band RMS. It cannot be inverted (ifft) or unnormalised — a PSD discarded its phase. |
Examples
From the documentation, and run by the build -- the output and the figure below are what the engine actually produced. Simplest first.
fs = 1000
n = 0:1:1023
t = n / fs
x = sin(2*pi*100*t) + 0.05 * randn(1024, seed=1)
psd_w = welch(x, fs, nperseg=256)
f_w = linspace(0, fs/2, length(psd_w))
peak_w = find_peaks(psd_w, min_height=max(psd_w)*0.5)
print("welch peak near {f_w[peak_w[0]]} Hz")
psd_p = periodogram(x, fs) # single-segment special case of welch
f_p = linspace(0, fs/2, length(psd_p))
peak_p = find_peaks(psd_p, min_height=max(psd_p)*0.5)
print("periodogram peak near {f_p[peak_p[0]]} Hz")
welch peak near 101.5625 Hz periodogram peak near 99.609375 Hz
from signal-processing
How it works
welch(x, fs, [nperseg=], [noverlap=], [window="hann"]) — Welch's method PSD estimate: segments x into overlapping, windowed frames and averages their squared-magnitude spectra (qu_core::transforms::welch, itself stft's own framing scheme generalized to a caller-chosen window). nperseg defaults to min(256, length(x)) (SciPy's own default); noverlap defaults to nperseg/2 (50% overlap, also SciPy's default); window defaults to "hann", matching scipy.signal.welch's own default. Returns the one-sided PSD as a plain Value::Vec (nperseg/2 + 1 bins, DC to Nyquist) in SciPy's "density" scaling (units²/Hz) — reconstruct the matching frequency axis with linspace(0, fs/2, length(psd)), the same convention freqz/group_delay already use. periodogram below is the same code path's one-segment, no-averaging special case.
From the note above this builtin in the interpreter, where the reasoning was written down as it was built.