WelchSpectrum#
- class cultivars.spectral.periodogram.WelchSpectrum(data, *, segment=None, detrend='c', names=None)[source]
Bases:
objectWelch’s averaged periodogram over half-overlapped Hann segments.
The sample is cut into \(B\) segments of \(L\) observations starting every \(L/2\), each is demeaned, multiplied by the Hann taper \(h_t = \tfrac12 - \tfrac12\cos(2\pi t/L)\), and transformed on the segment’s own Fourier grid; the estimate is the plain average
\[\hat f(\omega_j) = \frac{1}{B}\sum_{b=1}^{B} I_b(\omega_j), \qquad \omega_j = \frac{2\pi j}{L},\ j = 0, \dots, \lfloor L/2 \rfloor,\]with \(\nu = 36B/19 \approx 1.9B\) equivalent degrees of freedom, the Percival-Walden count for half-overlapped Hann segments, whose overlap makes adjacent periodograms correlated. The grid is the segment’s, so the spacing is \(2\pi/L\) and the number of ordinates \(L/2 + 1\) regardless of the sample length; the default segment is an eighth of the sample rounded to even, at least 32. Variance is bought by shortening segments, resolution by lengthening them, and only the sample length lets both improve.
- Variables:
_panel – The
(nobs, k)panel after detrending._names – The series labels.
_detrend – The detrending choice.
_segment – The segment length \(L\).
- Parameters:
data (
ArrayLike) – A(nobs, k)panel or one-dimensional series, at least 32 observations.segment (
int|None) – Segment length \(L\), an integer from 8 tonobs;Nonefor the default. Even lengths put the last ordinate exactly at \(\pi\).detrend (
str) –"n","c"(demean) or"ct"(linear detrend), removed from the whole sample first; each segment is then demeaned again.names (
tuple[str,...] |None) – Series labels;Nonereads them from a frame or usesy1 .. yk(yfor a single series).
- Raises:
SpecificationError – If the segment is not an integer of at least 8 or exceeds the sample, the detrend choice is unknown, the labels do not match the columns, or the panel is too short.
DimensionError – If the panel is malformed.
NumericalError – If the panel is not finite.
Note
The reported
bandwidthis the grid spacing \(2\pi/L\), not the Hann taper’s main lobe, which is twice as wide: two sinusoids two grid bins apart merge into one peak and three bins apart separate. Read peaks with that in mind. The per-segment Hann taper also costs about 3% of the variance (the taper’s energy loss and the per-segment demeaning), so the integral of the spectrum falls slightly short of the sample variance whereDaniellSpectrumreproduces it exactly. Welch is the estimator for long samples where a coarse grid is acceptable and stationarity across segments is the question worth asking; for the sample lengths typical of macroeconomic dataMultitaperSpectrumkeeps the full grid at the same degrees of freedom.See also
SpectrumEstimate– the result.MultitaperSpectrum– full-grid resolution at the same variance, the default.DaniellSpectrum– the smoothed periodogram.
References
Welch, P. D. (1967). The use of fast Fourier transform for the estimation of power spectra: A method based on time averaging over short, modified periodograms. IEEE Transactions on Audio and Electroacoustics, 15(2), 70-73.
Percival, D. B., & Walden, A. T. (1993). Spectral Analysis for Physical Applications, section 6.17. Cambridge University Press.
Example
>>> rng = np.random.default_rng(0) >>> est = WelchSpectrum(rng.standard_normal((800, 2)), segment=128).compute() >>> est.density.shape, bool(est.coherence("y1", "y2").mean() < 0.3) ((65, 2, 2), True)
Eleven half-overlapped segments of 128 fit in 800 observations, giving \(36 \cdot 11 / 19\) degrees of freedom on a grid of 65 points spaced \(2\pi/128\):
>>> round(est.degrees_of_freedom, 2), round(est.bandwidth, 4), est.nobs (20.84, 0.0491, 800) >>> WelchSpectrum(rng.standard_normal(4096)).compute().frequencies.shape (257,)