# python scipy fft on numpy hanning window smears peaks

I have a signal that I have acquired from an experimental instrument, that I wish to examine in the frequency domain. I don't care about phase for this exercise, I only care about magnitude. I deliberately planned my experiment so that the dominant frequency would fall completely within a single fft bin. when I use the scipy fft function on an unfiltered window, the fft shows a clean spike as expected. However, when I first apply a numpy.hanning window, the spikes become smeared. Note the mean of the signal (the zero bin) also shows the same smearing effect. My code is as follows:

eta=[instrument data series of length 2048]
etaHann=np.hanning(nfft)*eta
EtaSpectrum=abs(sp.fft(eta))
EtaSpectrum=EtaSpectrum*2/nfft # convert to amplitude
EtaSpectrumHann=abs(sp.fft(etaHann))
EtaSpectrumHann=EtaSpectrumHann*2*2/nfft # also correct for Hann filter
frequencies=np.linspace(0,samplingFrequency,nfft)
plt.plot(frequencies[0:200],EtaSpectrumHann[0:200],'b.-',label='Hann filtered')
plt.plot(frequencies[0:200],EtaSpectrum[0:200],'c.-',label='rectangular')
plt.xlim(-0.01,2)
plt.xlabel('frequency')
plt.ylabel('amplitude')
plt.grid()
plt.legend(loc=0)
plt.show()


Is this meant to happen? Does anyone else get this problem? For my data, it seems a rectangular window is fine, but to me it seems that the Hanning window must be wrong here, as the integral of the entire spectrum should be the same (after I multiplied by 2 to correct amplitude), but in this case it seems to be different.

Is this meant to happen?

Yes, that is absolutely a well known effect of using any window function. Taking a look through the Wikipedia article on window functions, we find that the rectangular window has the sharpest peak. This is quite simply due to the fact that the rectangular window acquires the most data, meaning that it can distinguish between slightly different frequencies the best.

The problem with the rectangular window is that it has large side lobes. In other words, if you measure a signal which doesn't exactly match one of the discrete Fourier transform (DFT) frequencies (a.k.a. bins), then with the rectangular window you get a lot of leakage into neighboring bins. The formula for this is actually rather simple. Suppose your sampling interval is $\delta t$ and you measure $N$ points. Then the DFT frequencies are $$f_n = n / N \delta t, \quad n\in[0,1,\ldots,N-1] \, .$$

Now suppose you measure a sinusoid with frequency $\xi$ so that the sampled values are $x_n = \cos(2 \pi \xi n \delta t)$. The mod squared of the DFT values are then $$|X_k|^2 = \left( \frac{\sin(\pi(\xi - k))}{\sin(\pi(\xi-k)/N} \right)^2 \, . \tag{*}$$

We plot this function in Figure 1 for $\xi=24.4$. Note that when $\xi$ is not an integer the DFT values are nonzero for all bins, and you can see from equation $(*)$ that the values of $|X_k|^2$ only fall off as one over the square of frequency. Figure 1: DFT values for a cosine of frequency 24.4. The blue line indicates the underlying function given in equation $(*)$ and the black dots are the values of that function evaluated at the integers. In other words, the black dots are the DFT bin values.

The point of a window function is to make the leakage of power into bins near the real frequency (in this case 24.4) fall off faster, but this comes at the cost that the main peak is broadened.$^{[a]}$

Does anyone else get this problem?

It's not a problem. It's how windows are supposed to work.

For my data, it seems a rectangular window is fine, but to me it seems that the Hanning window must be wrong here, as the integral of the entire spectrum should be the same (after I multiplied by 2 to correct amplitude), but in this case it seems to be different.

Applying a window changes the total power in your signal, as you have observed. This is not a mistake at all. It's pretty obvious that this has to happen because the integral (sum) of the power in the frequency domain has to equal the power you would have computed in the time doman (Parseval's theorem). It's clear that multiplying e.g. a cosine by a window function changes the integral of the time domain signal. This is called "loss" and must be taken into account when using windows!

$[a]$: I'm not actually showing this because I didn't bother to compute the points with the window, but the Wikipedia article shows many examples.

• Thanks Daniel. That makes it clearer. The one thing I still don't understand tho is that I multiplied by 2 to account for the fact that the integral (sum) is different between rectangle and Hanning, and by my reasoning, the total integral should have been the same after I multiplied by 2. That seems to be the common practice. But at least after reading your answer I know that rectangular window is best for my purposes in this dataset. – peterW Nov 3 '15 at 22:53
• @peterW So, what's still puzzling you? Are you saying that you thought 2 is the correct power scaling factor, but when you try it there's a discrepancy? – DanielSank Nov 4 '15 at 0:06
• Yes I did think 2 was the correct power scaling factor based on what I'd read, and when I multiplied hann filtered spectrum by 2 the total integral was greater than the rectangular window spectrum. The Wikipedia article looks good, I'll dig a bit deeper in that. – peterW Nov 5 '15 at 22:32
• @peterW Advice: you can compute the power correction factors yourself! It's super easy, as I'm sure you can figure out. – DanielSank Nov 6 '15 at 0:22

There are several mistakes:

1. What you mean 'rectangle' in the plot is not the rectangle window at all. You just plotted the frequency spectrum of the original data without any rectangle window, according to your code.

2. It's ridiculous to use multiplication on the time (or other) domain and then do the fft and expect the obtained frequency spectrum is windowed. You need to apply the window function to the frequency domain directly. You can check entry 109 in below page: https://en.wikipedia.org/wiki/Fourier_transform

• Please notify me if anyone think I'm wrong. The code @peterW posted there really puzzles me. – Shiang Hoo May 4 at 15:56