# Scipy fourier transform zero frequency spike (from DC offset) - de-meaning and hanning window have no effect

I am trying to plot the FFT of essentially a random signal that has a non-zero mean shown below.

The FFT of the signal is peaked over the zero frequency which usually indicates a DC offset. Although I have already demeaned and applied a hanning window to the data.

I am not sure what I am doing wrong here. I have also tried plotting from [1:] to ignore the zero frequency and applying a highpass filter which have had no effect. My code is below.

# a = signal.detrend(hhe_trim[0].data, type='constant')
a = hhe_trim[0].data.astype(np.float64)
a -= np.mean(a)

win = signal.hann(174001)
dt = 0.01
n = 174001

X = fftpack.fft(a*win, n=n)
freqs = fftpack.fftfreq(len(a), dt)
plt.plot(freqs, np.abs(X))
# plt.yscale("log")
plt.show()


My data has 174 001 samples and a sampling rate of 100Hz. Any help would be appreciated!

• 1. Don't use scipy.fftpack anymore, use scipy.fft Commented Nov 4, 2020 at 23:38

It doesn't happen with a random signal. Your signal must have low frequency content around 0 Hz that shows up even after you've nulled out 0 Hz itself?

import numpy as np
from scipy import signal
from scipy import fft
import matplotlib.pyplot as plt

a = np.random.randn(174001)
a -= np.mean(a)

win = signal.hann(174001)
dt = 0.01
n = 174001

X = fft.fft(a*win, n=n)
freqs = fft.fftfreq(len(a), dt)
plt.plot(freqs, np.abs(X))
# plt.yscale("log")
plt.show()


If you zoom in on 0 Hz, I bet you can see that the 0 Hz spike itself goes away when you null out the mean, but the content around 0 Hz stays the same.

Windowing causes spectral leakage into adjacent bins. There’s nothing special about bin 0; you can get small contributions from neighboring bins into bin 0. Remember that the mean of the input data block before windowing is not the same as the mean of the data block after windowing, so there’s no guarantee the post-windowed data will have zero mean.
Bob