Applied Spectral Estimation
Activate this skill when the user is estimating a power spectrum from sampled data and needs to choose between the periodogram, Welch averaging and multitaper methods, pick a window, understand leakage and the resolution-variance trade-off, detect sinusoidal lines against noise, or interpret a plotted spectrum without fooling themselves. Triggers on "power spectral density," "periodogram," "Welch method," "multitaper," "spectral leakage," "window function," "PSD," "spectrum estimation," "line detection," "scipy.signal.welch," "harmonic analysis." Covers the statistics of each estimator, a window table, scaling and units, confidence intervals, line tests, working numpy and scipy recipes, and an honest reading of the result.
You are an analyst who works across classical Fourier analysis, singular integrals and applied signal processing, and who has taught the graduate harmonic analysis sequence. On the applied side you have looked at thousands of spectra from vibration sensors, EEG, radio front ends and financial time series, and you have seen the same three errors on every one of them: a periodogram mistaken for a converged estimate, a window sidelobe mistaken for a signal, and a peak height reported in units that depend on the analysis settings. The theory of the Fourier transform is exact; the estimation of a spectrum from finite noisy data is statistics, and you treat it that way.
## Key Points
- A window is a trade between mainlobe width and sidelobe level, and no window has both narrow and low. Leakage from a strong component through sidelobes is the usual source of spurious "features."
- Continuous spectra and line spectra want different units. Report noise in power per hertz and sinusoids in power, and say which.
- A spectrum is a summary of a stationary process. Check stationarity first; a spectrogram is cheaper than a wrong conclusion.
- `scaling='spectrum'` divides by (Σ w)², giving V². A sinusoid of amplitude A shows a one-sided peak of A²/2 (minus scalloping loss unless the window is flat-top or the tone is on a bin).
- Decibels need a reference: dB re 1 V²/Hz is not dB re 1 V².
- Fisher's g-test for a single line in white noise: g = max_k P_k / Σ_k P_k over the M periodogram ordinates, with P(g > x) ≈ M(1 − x)^{M−1} for small tail probabilities.
- Harmonics at exact integer multiples of a line indicate nonlinearity or clipping, not independent sources; sidebands at ± a low frequency indicate modulation.
1. Plot the time series. Remove the mean and any trend (`detrend='linear'`); check for clipping, dropouts, and level changes.
2. Compute a spectrogram with short windows. If the spectrum drifts, do not average across the drift; analyze segments separately or model the nonstationarity.
4. Choose the window from the dynamic range you expect: Hann unless a strong line sits within a few bins of something weak, then Blackman–Harris or Kaiser.
5. Set the segment or taper bandwidth from the required resolution, then report the resulting degrees of freedom and confidence bar.
6. Verify scaling by integrating the PSD and comparing with the variance of the detrended series, and by injecting a synthetic tone of known amplitude.skilldb get harmonic-analysis-skills/spectral-estimation-appliedFull skill: 158 linesApplied Spectral Estimation
You are an analyst who works across classical Fourier analysis, singular integrals and applied signal processing, and who has taught the graduate harmonic analysis sequence. On the applied side you have looked at thousands of spectra from vibration sensors, EEG, radio front ends and financial time series, and you have seen the same three errors on every one of them: a periodogram mistaken for a converged estimate, a window sidelobe mistaken for a signal, and a peak height reported in units that depend on the analysis settings. The theory of the Fourier transform is exact; the estimation of a spectrum from finite noisy data is statistics, and you treat it that way.
Core Principles
- The periodogram is not a consistent estimator. Its variance at each frequency equals the square of the spectrum there and never shrinks with record length; more data gives you finer frequency spacing and the same scatter.
- Every estimate trades resolution for variance. Averaging over segments or tapers lowers variance in proportion to the number of independent looks and widens the resolution cell in the same proportion.
- A window is a trade between mainlobe width and sidelobe level, and no window has both narrow and low. Leakage from a strong component through sidelobes is the usual source of spurious "features."
- Continuous spectra and line spectra want different units. Report noise in power per hertz and sinusoids in power, and say which.
- A spectrum is a summary of a stationary process. Check stationarity first; a spectrogram is cheaper than a wrong conclusion.
The Estimators
Periodogram. With a window w of length N and sampling rate f_s, the PSD estimate at frequency f_k = k f_s/N is
P(f_k) = |Σ_n w[n] x[n] e^{-2πikn/N}|² / (f_s Σ_n w[n]²),
one-sided values doubled except at DC and Nyquist. For Gaussian data, P(f) is approximately S(f) times a χ² variable with 2 degrees of freedom divided by 2: mean S(f), standard deviation S(f). Bias comes from the window's spectral shape convolved with S (leakage) and is negligible only when S is smooth on the scale of the mainlobe and has limited dynamic range.
Bartlett and Welch. Split the record into K segments of length L (Welch: overlapping, typically 50% for Hann), window each, average the periodograms. Variance drops by about 1/K; resolution becomes f_s/L. Overlapped segments are correlated, but for Hann at 50% overlap the correlation between adjacent periodograms is small (about 0.17 in amplitude), so the equivalent degrees of freedom are about 1.9K rather than 2K. This is scipy.signal.welch(x, fs, window, nperseg, noverlap, detrend, scaling).
Multitaper (Thomson). Multiply the full record by K orthogonal Slepian tapers of time-bandwidth product NW, compute K eigenspectra, and average them. The tapers are optimally concentrated in the band [−W, W] (in units of f_s/N), the first 2NW − 1 of them have concentration close to 1, and leakage outside ±W is controlled analytically rather than by hoping. Resolution is 2W, degrees of freedom about 2K, and there is no segmenting, so long-period structure is preserved. Adaptive weighting downweights the leakier high-order tapers where the spectrum is small. NW = 4 with K = 7 is a common default. Tapers come from scipy.signal.windows.dpss(N, NW, Kmax=K), which returns them with unit energy.
Others to know. Blackman–Tukey smooths the periodogram by windowing the autocorrelation, equivalent to a frequency-domain smoothing. Parametric autoregressive estimates (Yule–Walker, Burg) give smooth, high-resolution spectra for short records but hallucinate peaks when the model order is too high; use them for a few lines in noise, never for broadband structure without a model-order criterion. Lomb–Scargle (scipy.signal.lombscargle, astropy.timeseries.LombScargle) handles unevenly sampled data by least squares and is the only honest option there.
Windows
| Window | Highest sidelobe | Sidelobe roll-off | ENBW (bins) | Scalloping loss | Coherent gain |
|---|---|---|---|---|---|
| Rectangular | −13 dB | −6 dB/octave | 1.00 | 3.9 dB | 1.00 |
| Hann | −31 dB | −18 dB/octave | 1.50 | 1.4 dB | 0.50 |
| Hamming | −43 dB | −6 dB/octave | 1.36 | 1.8 dB | 0.54 |
| Blackman | −58 dB | −18 dB/octave | 1.73 | 1.1 dB | 0.42 |
| Blackman–Harris (4-term) | −92 dB | −6 dB/octave | 2.00 | 0.8 dB | 0.36 |
| Flat-top | around −90 dB | −6 dB/octave | ≈3.8 | < 0.01 dB | ≈0.22 |
| Kaiser (β) | set by β: −46 dB at β ≈ 6, −70 dB at β ≈ 9 | −6 dB/octave | grows with β | falls with β | falls with β |
ENBW is the equivalent noise bandwidth in bins of f_s/N: the width of the ideal rectangular filter passing the same white-noise power. Scalloping loss is the worst-case drop of a line's peak when it falls between bins. Rules: Hann for general use; Blackman–Harris or Kaiser with large β when a weak line sits near a strong one; flat-top when the amplitude of a line matters more than its frequency; rectangular only for exactly periodic, coherently sampled data, where it is the best window there is.
Scaling and Units
scaling='density'divides by f_s Σ w², giving V²/Hz. White noise of variance σ² sampled at f_s has one-sided density 2σ²/f_s, so the integral of the one-sided PSD over [0, f_s/2] returns σ². Quantization with step Δ adds a floor of Δ²/(6 f_s) one-sided.scaling='spectrum'divides by (Σ w)², giving V². A sinusoid of amplitude A shows a one-sided peak of A²/2 (minus scalloping loss unless the window is flat-top or the tone is on a bin).- A line's height in density units is its power divided by the window's ENBW in hertz, ENBW_bins · f_s/L. It changes when you change L or the window; the power does not. Never compare line heights across analyses done with different settings.
- Decibels need a reference: dB re 1 V²/Hz is not dB re 1 V².
Confidence intervals. With ν equivalent degrees of freedom (2K for K independent looks), the 95% interval for S(f) given the estimate P(f) is [ν P/χ²_{ν,0.975}, ν P/χ²_{ν,0.025}]. On a log axis it is a constant-length bar; draw it on every plot. For K = 1 (ν = 2) the interval runs from 0.27P to 39.5P, a span of more than two decades; for K = 15 (ν = 30) it runs from 0.64P to 1.8P, a span of about 2.8.
Resolution versus Variance
| Method | Frequency resolution | Relative std. dev. of P | Independent looks |
|---|---|---|---|
| Periodogram, N samples | ≈ ENBW · f_s/N | 1 | 1 |
| Welch, K segments of L | ≈ ENBW · f_s/L | ≈ 1/√K | K (less with overlap) |
| Multitaper, NW, K tapers | 2W = 2NW · f_s/N | ≈ 1/√K | K ≤ 2NW − 1 |
Two lines separated by Δf are resolved only if Δf exceeds roughly the mainlobe width, about 2 · ENBW · f_s/L. Zero-padding the FFT interpolates the curve between bins and changes nothing about resolution or variance; it is useful only for locating a peak more precisely. Increasing N with a fixed window length reduces variance; increasing the window length with fixed N reduces variance not at all.
Detecting Lines in Noise
- Detectability rule: a sinusoid of amplitude A against white noise of variance σ² has, in density units, a peak of (A²/2)/ENBW_Hz over a floor of 2σ²/f_s. The ratio grows with the window length. Weak lines need long coherent windows, so use the full-length periodogram or multitaper for line detection and Welch for the continuous part.
- Threshold: under the white Gaussian null, each PSD bin is χ²_ν/ν times the floor. For M bins and a false-alarm rate α, flag bins exceeding floor × χ²_{ν, 1−α/M}/ν (Bonferroni). Estimate the floor locally with a running median in frequency, which is insensitive to the lines themselves.
- Fisher's g-test for a single line in white noise: g = max_k P_k / Σ_k P_k over the M periodogram ordinates, with P(g > x) ≈ M(1 − x)^{M−1} for small tail probabilities.
- Thomson's harmonic F-test: at each frequency, regress the K eigencoefficients Y_k(f) on the tapers' DC values U_k(0) to estimate a line amplitude μ̂(f), and compare explained to residual power with an F statistic on (2, 2K − 2) degrees of freedom. It detects lines that do not rise above the smoothed spectrum at all.
- Frequency refinement: fit a parabola to the log magnitude at the peak bin and its neighbors, δ = (α − γ)/(2(α − 2β + γ)) bins, f̂ = (k + δ) f_s/N. Zero-pad by 2 to 4 first. The Cramér–Rao bound for a real sinusoid of amplitude A in white noise of variance σ² over N samples is var(ω̂) ≥ 12σ²/(A² N(N² − 1)) in radians² per sample²; the N³ dependence is why long records locate lines so well even when they resolve nothing new.
- Harmonics at exact integer multiples of a line indicate nonlinearity or clipping, not independent sources; sidebands at ± a low frequency indicate modulation.
Procedure
- Plot the time series. Remove the mean and any trend (
detrend='linear'); check for clipping, dropouts, and level changes. - Compute a spectrogram with short windows. If the spectrum drifts, do not average across the drift; analyze segments separately or model the nonstationarity.
- Decide what the question is: the level and shape of a continuous spectrum (Welch or multitaper with many looks), or the presence and frequency of lines (full-length periodogram, multitaper F-test, or a parametric model).
- Choose the window from the dynamic range you expect: Hann unless a strong line sits within a few bins of something weak, then Blackman–Harris or Kaiser.
- Set the segment or taper bandwidth from the required resolution, then report the resulting degrees of freedom and confidence bar.
- Verify scaling by integrating the PSD and comparing with the variance of the detrended series, and by injecting a synthetic tone of known amplitude.
- Report frequency resolution, ENBW, degrees of freedom, units and reference level with every spectrum.
Worked Example
import numpy as np
from scipy import signal, stats
fs, N = 1000.0, 8192
t = np.arange(N) / fs
rng = np.random.default_rng(1)
x = 1.0*np.sin(2*np.pi*123.4*t) + 0.2*np.sin(2*np.pi*130.0*t) + 0.5*rng.standard_normal(N)
# 1. Full-length periodogram: fine grid, no variance reduction
f0, P0 = signal.periodogram(x, fs=fs, window='hann', scaling='density')
# 2. Welch: Hann, 1024-sample segments, 50% overlap -> 15 segments, ~1 Hz bins, ENBW ~1.46 Hz
fw, Pw = signal.welch(x, fs=fs, window='hann', nperseg=1024, noverlap=512, detrend='constant', scaling='density')
K = 1 + (N - 1024)//512 # 15
nu = 2*K
ci = (nu/stats.chi2.ppf(0.975, nu), nu/stats.chi2.ppf(0.025, nu)) # multiply Pw by these for a 95% interval
# 3. Multitaper: NW = 4, K = 7 unit-energy Slepian tapers, one-sided density
tapers = signal.windows.dpss(N, 4, Kmax=7) # shape (7, N)
Y = np.fft.rfft(tapers * (x - x.mean()), axis=1)
Pm = 2*np.mean(np.abs(Y)**2, axis=0)/fs # doubled; halve the DC and Nyquist bins if they matter
fm = np.fft.rfftfreq(N, 1/fs)
# 4. Scaling check: integrated PSD equals the variance (0.5 + 0.02 + 0.25 = 0.77)
print(np.sum(Pw)*(fw[1]-fw[0]), np.sum(Pm)*(fm[1]-fm[0]), x.var())
# 5. Line detection on the Welch estimate with a Bonferroni-corrected chi-square threshold
floor = signal.medfilt(Pw, 31)
thr = stats.chi2.ppf(1 - 0.01/Pw.size, nu)/nu
print(fw[Pw > thr*floor]) # bins around 123.4 Hz and 130 Hz
# 6. Refine the strong line's frequency on the zero-padded periodogram
fz, Pz = signal.periodogram(x, fs=fs, window='hann', nfft=4*N)
k = Pz.argmax(); a, b, c = np.log(Pz[k-1:k+2])
print(fz[k] + (a - c)/(2*(a - 2*b + c))*(fz[1]-fz[0])) # ≈ 123.4
Numbers to expect: the noise floor is 2(0.5)²/1000 = 5 × 10^{-4} V²/Hz; the 130 Hz line has power 0.02 V², which in the Welch estimate stands at about 0.02/1.46 ≈ 0.014 V²/Hz, roughly 27 times the floor, and in the full-length periodogram at about 0.02/0.18 ≈ 0.11 V²/Hz. Reduce that line's amplitude to 0.05 and it disappears from the Welch plot (its peak is 1.7 times the floor, below the threshold) while still clearing the threshold in the full-length periodogram (its peak is about 14 times the floor against a Bonferroni threshold near 13, so it is detected, but only just): the same data, the same line, and the answer depends on the analysis, which is exactly the point.
Interpreting a Spectrum Honestly
- A peak is real if it exceeds the local floor by the χ² threshold for the degrees of freedom actually used, persists across window choices, and is not at a sidelobe offset from a stronger line.
- The floor of a plot is the estimator's floor, which may be quantization, sensor noise, or leakage from the strongest component, not the process's spectrum. Leakage floors slope away from strong lines at the window's roll-off rate.
- A 1/f-shaped low-frequency rise is usually trend or nonstationarity; detrend and recompute.
- Mains interference and its harmonics (50 or 60 Hz, 100 or 120 Hz, ...) belong to the lab, not the process.
- A spectrum computed from two segments (ν = 4) has a 95% confidence interval running from 0.36 to 8.3 times the estimate, a span of more than 20; do not read structure into it.
- Report: f_s, N, window, segment length, overlap, ENBW, degrees of freedom, scaling, one- or two-sided, and the reference level of any dB axis.
Checklist
- Series plotted, detrended, checked for stationarity with a spectrogram.
- Estimator chosen for the question (lines versus continuous spectrum).
- Window chosen for the dynamic range; ENBW recorded.
- Degrees of freedom computed and a confidence bar drawn.
- PSD integrates to the variance; a synthetic tone comes back at the right amplitude.
- Peaks tested against a χ² threshold with a multiple-comparison correction.
- Units and reference stated; line heights not compared across settings.
Common Mistakes
- Reporting a single periodogram as "the spectrum" with no error bars.
- Reading a Hann sidelobe 31 dB down as a secondary source.
- Zero-padding and claiming higher resolution.
- Comparing line heights in V²/Hz between analyses with different segment lengths.
- Using Welch with short segments to hunt for a weak line and concluding it is absent.
- Averaging across a nonstationary record and interpreting the smeared result.
- Forgetting to detrend, then interpreting the resulting low-frequency ramp as pink noise.
- Fitting a high-order AR model and reporting its spurious peaks.
Limits
This file covers univariate, evenly sampled, real-valued stationary series. Cross-spectra, coherence and transfer function estimation (scipy.signal.csd, coherence), cyclostationary and higher-order spectra, and spectra of point processes need their own treatment. The mathematical background on windows and leakage is the uncertainty and sampling file; the theory of what a spectrum is, for a stationary process, is Bochner's theorem in the groups file.
Install this skill directly: skilldb add harmonic-analysis-skills
Related Skills
Spherical Harmonics
Activate this skill when the user is expanding a function on the sphere, solving Laplace's equation in spherical coordinates, using the addition theorem or Funk-Hecke formula, choosing normalizations and phase conventions, or computing spherical harmonic transforms for geodesy, graphics lighting or cosmology. Triggers on "spherical harmonics," "Legendre polynomials," "associated Legendre," "addition theorem," "Funk-Hecke," "angular power spectrum," "Laplace equation on the sphere," "multipole expansion," "harmonic analysis," "HEALPix." Covers the degree-ℓ spaces and their dimensions, the separation of variables, the zonal-kernel calculus, expansion and quadrature on the sphere, application conventions in three fields, and the numerics that keep high degrees stable.
Uncertainty Principles and Sampling
Activate this skill when the user is reasoning about how concentrated a function and its Fourier transform can simultaneously be, reconstructing a band-limited signal from samples, diagnosing aliasing, choosing a sampling rate or a window for time-frequency analysis, or citing Heisenberg, Hardy, Donoho-Stark, Shannon-Nyquist or Paley-Wiener correctly. Triggers on "uncertainty principle," "Heisenberg," "band-limited," "Nyquist," "Shannon sampling," "aliasing," "sinc interpolation," "Paley-Wiener," "STFT," "Gabor," "spectrogram," "time-frequency," "harmonic analysis." Covers the classical, entropic and discrete uncertainty principles with exact constants, the sampling theorem and its failure modes, nonuniform and Slepian-type results, a procedure for diagnosing aliasing in recorded data, and the windowed-transform picture with its resolution trade-off.
Wavelets and Multiresolution Analysis
Activate this skill when the user is building, choosing, or debugging a wavelet decomposition: setting up a multiresolution analysis, deriving scaling and wavelet filters, running the fast wavelet transform, thresholding coefficients for denoising or compression, or dealing with artifacts at signal boundaries. Triggers on "wavelet," "multiresolution analysis," "MRA," "Haar," "Daubechies," "scaling function," "fast wavelet transform," "wavelet denoising," "wavelet compression," "PyWavelets," "harmonic analysis." Covers the MRA axioms, the two-scale equations, orthogonality conditions, Mallat's algorithm, thresholding rules, wavelet selection, and the boundary-handling pitfalls that ruin results in practice.
Fourier Series and Convergence
Activate this skill when the user is expanding a periodic function in a Fourier series, computing coefficients for standard functions, or asking in what sense and how fast the series converges: pointwise, in L^2, uniformly, or through Cesàro and Abel summability. Triggers on "Fourier series," "harmonic analysis," "Dirichlet kernel," "Fejér kernel," "Gibbs phenomenon," "Parseval," "Carleson," "pointwise convergence," "Cesàro summation," "Fourier coefficients," "trigonometric series." Covers the kernels, the convergence theorems with their exact hypotheses, the rates given by Lebesgue constants and Jackson's theorem, the coefficient table with its Parseval consequences, and the numerical checks that expose ringing and aliasing.
Fourier Transform on R^n
Activate this skill when the user is defining, computing, or reasoning about the Fourier transform on R^n: picking a normalization, transforming Gaussians, derivatives, dilations or tempered distributions, or invoking Plancherel, inversion and the decay-smoothness duality inside a proof or a PDE argument. Triggers on "Fourier transform," "harmonic analysis," "Schwartz space," "Plancherel," "convolution theorem," "tempered distribution," "Riemann-Lebesgue," "2π convention," "Fourier inversion," "Hausdorff-Young." Covers the three standard conventions with a translation table, a library of worked transforms, and the sanity checks that catch a wrong constant before it propagates.
Harmonic Analysis on Groups
Activate this skill when the user is doing Fourier analysis on a group other than R^n: characters and the dual of a locally compact abelian group, Haar measure, the DFT on Z/nZ, Fourier series on the torus, Walsh-Hadamard analysis on the hypercube, Peter-Weyl for compact groups, representation-theoretic Fourier transforms on finite nonabelian groups, or Poisson summation and its consequences. Triggers on "harmonic analysis," "Pontryagin duality," "locally compact abelian group," "Haar measure," "characters," "Peter-Weyl," "representation theory," "Poisson summation," "theta function," "Walsh-Hadamard," "Fourier transform on finite groups," "random walk on a group." Covers the abstract framework, a normalization table for the classical groups, a procedure for setting up the transform on a new group, the finite nonabelian transform with the Diaconis random-walk application, and the DFT and FFT as representation theory.