Lesson 8 of 15

Power Spectrum

Power Spectrum

The power spectrum shows how the power of a signal is distributed across frequencies. It is computed from the DFT magnitudes:

P[k]=X[k]2NP[k] = \frac{|X[k]|^2}{N}

where NN is the number of samples. This normalization makes the power independent of signal length.

Frequency Resolution

For a signal sampled at fsf_s Hz with NN samples, each bin kk corresponds to:

fk=kfsNf_k = k \cdot \frac{f_s}{N}

Bin 0 (k=0k=0) is the DC component (zero frequency). The highest meaningful frequency is at k=N/2k = N/2 (the Nyquist frequency).

Dominant Frequency

The dominant frequency is the bin with the highest power, excluding DC (bin 0). For a signal with a strong sinusoidal component, this reveals the fundamental frequency.

Example

A 4-sample signal [1,0,0,0][1, 0, 0, 0] (impulse) has flat power spectrum:

P[k]=14for all kP[k] = \frac{1}{4} \quad \text{for all } k

A DC signal [1,1,1,1][1, 1, 1, 1] has all power at k=0k=0:

P[0]=164=4,P[k]=0 for k>0P[0] = \frac{16}{4} = 4, \quad P[k] = 0 \text{ for } k > 0

Your Task

Implement:

  • power_spectrum(x) — returns [X[0]2/N,,X[N1]2/N][|X[0]|^2/N, \ldots, |X[N-1]|^2/N]
  • dominant_frequency(x, fs) — returns kfs/Nk^* \cdot f_s / N where kk^* maximizes P[k]P[k] for k>0k > 0
import math

def dft(x):
    N = len(x)
    X = []
    for k in range(N):
        val = 0 + 0j
        for n in range(N):
            val += x[n] * math.e ** (-2j * math.pi * k * n / N)
        X.append(val)
    return X

def power_spectrum(x):
    N = len(x)
    X = dft(x)
    return [abs(v)**2 / N for v in X]

def dominant_frequency(x, fs):
    N = len(x)
    ps = power_spectrum(x)
    start = 1 if N > 1 else 0
    best_k = start + ps[start:].index(max(ps[start:]))
    return best_k * fs / N
Python runtime loading...
Loading...
Click "Run" to execute your code.