DaniellSpectrum#

class cultivars.spectral.periodogram.DaniellSpectrum(data, *, span=None, detrend='c', names=None)[source]#

The periodogram smoothed with a modified Daniell kernel.

The raw periodogram \(I(\omega_j)\) at the Fourier frequencies is inconsistent – each ordinate is \(f(\omega_j)\chi^2_2/2\) however long the sample – so adjacent ordinates are averaged with the flat kernel of half-width \(m\) whose two end weights are halved,

\[\hat f(\omega_j) = \sum_{|l| \le m} w_l\, I(\omega_{j+l}), \qquad w_l = \frac{1}{2m}\ (|l| < m),\quad w_{\pm m} = \frac{1}{4m},\]

\(2m + 1\) ordinates per estimate with the smoothing wrapped around the circle so the ends of the grid borrow from their mirror images. The equivalent degrees of freedom are \(\nu = 2/\sum_l w_l^2 = 16m^2/(4m - 1)\), about \(4m\), and the resolution is \(2\pi m / N\) radians. The default span \(\lfloor \sqrt{N}/2 \rceil\) is the usual compromise between resolution and variance. No taper is applied, so the estimate’s leakage is the periodogram’s own; it is the simplest of the three estimators and the one whose integral reproduces the sample variance exactly.

Variables:
  • _panel – The (nobs, k) panel after detrending.

  • _names – The series labels.

  • _detrend – The detrending choice.

  • _span – The kernel half-width \(m\).

Parameters:
  • data (ArrayLike) – A (nobs, k) panel or one-dimensional series, at least 32 observations.

  • span (int | None) – Kernel half-width in ordinates, an integer of at least 1 with 2 span + 1 at most nobs // 2; None for the default.

  • detrend (str) – "n", "c" (demean) or "ct" (linear detrend), removed by least squares first.

  • names (tuple[str, ...] | None) – Series labels; None reads them from a frame or uses y1 .. yk (y for a single series).

Raises:
  • SpecificationError – If the span is not an integer of at least 1, averages more ordinates than the grid holds, 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 span is the whole resolution-variance dial: at \(N = 1024\) a span of 4 gives \(\nu = 17\) and resolves peaks 0.025 radians apart, a span of 16 gives \(\nu = 65\) and merges anything within 0.098 radians – and flattens a sharp AR(1) peak at the origin to 97% of its height where the span-4 estimate overshoots it by sampling noise. Read the printed bandwidth before reading a peak.

See also

References

Bloomfield, P. (2000). Fourier Analysis of Time Series: An Introduction, 2nd ed., chapter 8. Wiley.

Percival, D. B., & Walden, A. T. (1993). Spectral Analysis for Physical Applications, chapter 6. Cambridge University Press.

Example

>>> rng = np.random.default_rng(0)
>>> est = DaniellSpectrum(rng.standard_normal(400)).compute()
>>> bool(abs(2.0 * np.pi * est.spectrum("y").mean() - 1.0) < 0.2)
True

The default span at \(N = 400\) is 10, giving \(16 \cdot 100 / 39 = 41.0\) degrees of freedom, and the estimate integrates to the sample variance exactly:

>>> est.degrees_of_freedom, round(est.bandwidth, 4)
(41.025641025641015, 0.1571)
>>> y = rng.standard_normal(512)
>>> est = DaniellSpectrum(y, span=4).compute()
>>> round(float(2.0 * np.trapezoid(est.spectrum("y"), est.frequencies) / y.var()), 3)
1.0

Methods#

compute()

Estimate the density matrix.