Spectral Conventions

This page explains the design choices behind cogpy’s spectral analysis stack.

PSD-first convention

Spectral scalar features (band power, entropy, line noise ratio, etc.) accept pre-computed PSD arrays, not raw signals:

# Step 1: Compute PSD once
psd, freqs = psd_multitaper(signal, fs=1000.0)

# Step 2: Derive multiple features from the same PSD
gamma = band_power(psd, freqs, band=(30, 100))
entropy = spectral_entropy(psd, freqs)
lnr = line_noise_ratio(psd, freqs, line_freq=60.0)

Why? PSD estimation is the expensive step. Computing it once and reusing it across features avoids redundant work. This also makes features composable — any PSD source (Welch, multitaper, averaged spectrogram) works.

Exception: ftest_line_scan operates on raw signal because it needs access to individual tapered FFTs for the F-test statistic.

Multitaper methods

cogpy prefers multitaper spectral estimation over Welch’s method for short windows. Multitaper provides:

  • Better frequency resolution at a given window length

  • Controlled spectral leakage via DPSS (Slepian) tapers

  • Natural framework for F-test line detection

The key parameter is NW (time-bandwidth product). Higher NW = more tapers = smoother spectrum but lower frequency resolution.

NW

Tapers (K=2NW-1)

Use case

2.0

3

High frequency resolution

4.0

7

General purpose (default)

8.0

15

Heavy smoothing

Frequency axis convention

  • Frequency arrays are strictly increasing, in Hz

  • The last axis of PSD/spectrogram arrays is always freq

  • DC (0 Hz) is included; Nyquist may or may not be included depending on signal length

Two API levels

numpy level (cogpy.spectral)

Pure functions on numpy arrays. No xarray dependency.

from cogpy.spectral.psd import psd_multitaper
from cogpy.spectral.multitaper import multitaper_fft

xarray level (cogpy.spectral.specx)

Dimension-aware wrappers that preserve coordinates:

from cogpy.spectral.specx import psdx, spectrogramx, coherencex

These call the numpy-level functions internally and attach appropriate xarray coordinates to the output.

Feature categories

Category

Input

Output

Examples

Scalar

(..., freq)

(...)

band_power, spectral_entropy, line_noise_ratio

Vector

(..., freq)

(..., freq)

narrowband_ratio, fooof_periodic

Raw-signal

(time,)

(freq,) + metadata

ftest_line_scan

All features broadcast over arbitrary leading batch dimensions.

Spectrogram normalization

normalize_spectrogram provides standard normalization of spectrogram tensors:

from cogpy.spectral.specx import normalize_spectrogram

wspec = normalize_spectrogram(spec, method="robust_zscore", dim="freq")
spec_db = normalize_spectrogram(spec, method="db")

Method

Formula

Use case

robust_zscore

(x - median) / (MAD * 1.4826) along dim

Frequency-whitened spectrogram for QC

db

10 * log10(x)

Display / visualization

Frequency band reduction

reduce_tf_bands collapses a frequency axis into named bands:

from cogpy.spectral.features import reduce_tf_bands

bands = {"theta": (4, 8), "alpha": (8, 13), "beta": (13, 30), "gamma": (30, 100)}
ds = reduce_tf_bands(score, bands, method="mean")
# ds["alpha"]  →  (time_win,) or (...,) with freq removed

Supported reductions: mean, median, max, sum.

Spectral whitening

For analyses where the 1/f spectral shape obscures narrowband features, cogpy provides spectral whitening:

from cogpy.spectral.whitening import whiten_ar

This fits an autoregressive model and divides out the predicted spectrum, flattening the broadband background while preserving narrowband peaks.

Possible future additions

The following methods are not currently implemented but may be added:

  • Singular Spectrum Analysis (SSA) — a non-parametric decomposition that embeds a 1-D signal into a Hankel (trajectory) matrix and applies SVD to separate oscillatory components from noise. Useful for extracting narrowband oscillations without specifying frequency bands a priori. Reference: Golyandina & Zhigljavsky, Singular Spectrum Analysis for Time Series (Springer, 2013). An incomplete prototype existed in cogpy.spectral.ssa (removed in v0.1.0) based on the pyts implementation; a future version would use pure numpy/scipy and conform to the xarray conventions above.