# Band energy and Parseval theorem

In Python, I consider a dummy signal as follows:

fs = 512
sig = np.random.standard_normal((fs,))


sig corresponds to 1s of data at 512Hz.

To check Parseval theorem on the whole signal, I do:

fft = np.fft.fft(sig)
f = np.fft.fftfreqs(sig.size, d=1. / fs)
m = np.sum((np.abs(fft) ** 2) / sig.size)
e = np.sum(sig ** 2)
print('diff = %1.5f' % (m - e))


This actually returns 0.0. Now, to compute the energy of the signal in a given frequency band (say 5Hz - 15Hz), I would filter the signal using a bandpass filter and compute its energy as above:

def _butter(lowcut, highcut, fs, order=5, btype='bandpass'):
nyq = 0.5 * fs
low = lowcut / nyq
high = highcut / nyq
b, a = butter(order, [low, high], btype=btype)
return b, a

def _filter(data, lowcut, highcut, fs, order=5, btype='bandpass'):
b, a = _butter(lowcut, highcut, fs, order=order, btype=btype)
y = filtfilt(b, a, data)
return y

filtered_sig = _filter(sig, 5., 15., fs)
e_band = np.sum(filtered_sig ** 2)


My question is: can I use Parseval theorem to compute the energy of the signal (in the 5Hz-15Hz) band using fft as above? I naively tried:

mask = np.logical_and(np.abs(f) >= 5, np.abs(f) <= 15)
m_band = np.sum((np.abs(fft[mask]) ** 2) / sig.size)


But the quantities m_band and e_band are not equal. Where did I make a mistake?

The band-pass filter is not ideal. You will still have some frequency content outside the 5 Hz-15 Hz band. For a sufficiently high order filter, the difference between m_band and e_band should be small enough.
• The right choice is to use a band-pass filter. You should NOT try to just put to zero the unwanted frequency bins and then apply the inverse FFT. Now, apply no mask, and sum up the whole power spectrum density as you were doing at first: m = np.sum((np.abs(fft) ** 2) / sig.size), and you will always have m_band = e_band. The Parseval theorem still applies after applying a linear filter. May 18, 2018 at 15:32