216. Fourier

A frequency-domain representation of a time series. Decompose the series into a sum of sines and cosines at different frequencies. Useful for finding dominant cycles that aren’t obvious in the time-domain view.

216.0.1. Discrete Fourier Transform (DFT)

For a series 𝑦0,𝑦1,,𝑦𝑁1 of length 𝑁:

𝑌𝑘=𝑡=0𝑁1𝑦𝑡𝑒2𝜋𝑖𝑘𝑡/𝑁,𝑘=0,1,,𝑁1

The output 𝑌𝑘 is a complex number. Its magnitude |𝑌𝑘| measures how much the frequency 𝑘/𝑁 (cycles per time unit) is present in the signal. The phase arg(𝑌𝑘) tells you where the cycle peaks.

The inverse DFT recovers the original series:

𝑦𝑡=1𝑁𝑘=0𝑁1𝑌𝑘𝑒2𝜋𝑖𝑘𝑡/𝑁

216.0.2. Frequencies and periods

For a series sampled at one observation per unit time, the DFT covers frequencies 𝑘/𝑁 for 𝑘=0,1,,𝑁1:

So you only look at the first 𝑁/2 frequencies for a real-valued series. The period corresponding to bin 𝑘 is 𝑁/𝑘.

216.0.3. FFT — the fast version

The Fast Fourier Transform (Cooley-Tukey 1965) computes the DFT in 𝑂(𝑁log𝑁) rather than the naive 𝑂(𝑁2). It’s the standard implementation in every numerical library (NumPy fft.fft, MATLAB fft, etc.).

Use FFT in practice; conceptually it computes exactly the DFT above.

216.0.4. What you can do with the Fourier transform

216.0.4.1. 1. Find dominant cycles

Plot |𝑌𝑘|2 (the power spectrum) vs frequency. Peaks indicate dominant cycles. Example uses:

This is the core of [periodogram.typ](periodogram.typ).

216.0.4.2. 2. Filter (frequency-domain)

Remove specific frequencies:

Procedure: FFT → zero out unwanted frequency bins → inverse FFT.

216.0.4.3. 3. Forecast with Fourier features

Add sin(2 pi k t \/ m) and cos(2 pi k t \/ m) as regressors in a linear forecasting model, where 𝑚 is the period. A handful of harmonics (𝑘=1,2,3) captures most of a smooth seasonal pattern.

This is how Prophet (Facebook) and many modern forecasting libraries handle seasonality without a fixed seasonal index.

216.0.4.4. 4. Spectral density estimation

Smoothed version of the periodogram → see [periodogram.typ](periodogram.typ).

216.0.5. Limitations

216.0.6. Connection to seasonality

If your series has a known seasonal period 𝑚, you’d expect a peak in the spectrum at 𝑘=𝑁/𝑚. Conversely, unknown periodicities are discovered via the spectrum — perhaps weekly + monthly + yearly all show up in the same series. Fourier analysis is the natural tool for this.

Example: Fourier analysis of monthly retail sales

Given: 𝑁=60 months of sales data (5 years).

Step 1 — apply FFT

import numpy as np
Y = np.fft.fft(y)
power = np.abs(Y[:N//2])**2  # only first half (positive frequencies)
freq = np.arange(N//2) / N    # cycles per month
period = 1 / np.where(freq > 0, freq, np.inf)  # months per cycle

Step 2 — find peaks

Suppose the power spectrum shows large peaks at:

  • 𝑘=5 → frequency 560=112 → period 12 (monthly cycle = annual)
  • 𝑘=10 → frequency 1060=16 → period 6 (semi-annual)
  • 𝑘=1 → frequency 160 → period 60 (long-term trend)

Step 3 — interpret

  • The annual peak at 𝑘=5 is the dominant seasonality.
  • The semi-annual peak might be a back-to-school spike on top of the holiday spike.
  • 𝑘=1 at the lowest frequency captures the multi-year trend.

Step 4 — use

Pick a few harmonics (𝑘=5,10, possibly 15) and use them as Fourier features in a regression: forecast = trend + linear combination of sin(2𝜋𝑘𝑡/12) and cos(2𝜋𝑘𝑡/12). The Fourier representation lets you smoothly interpolate seasonal effects between cycles.