Ewan
Ewan

Reputation: 415

Numpy FFT give unexpected result when signal frequency falls exactly on a fft bin

When a signal's frequency falls exactly on an FFT bin, the amplitude becomes 0! But if I offset the signal frequency a little bit off, the result is ok.

Reproducing code:

Here the signal's frequency is 30

import numpy as np
import matplotlib.pyplot as plt
N = 1024
Freq = 30
t = np.arange(N)
x = np.sin(2*np.pi*Freq/N*t)
f = np.fft.fft(x)
plt.plot(t, x)
plt.plot(t, f)

I would expect the output to have a huge spike in the 30th bin, but it's flat, as in the following figure. enter image description here

However, if just slightly change the frequency to 30.1 to not let it fall on the exact bin,

import numpy as np
import matplotlib.pyplot as plt
N = 1024
Freq = 30.1
t = np.arange(N)
x = np.sin(2*np.pi*Freq/N*t)
f = np.fft.fft(x)
plt.plot(t, x)
plt.plot(t, f)

The result is correct as in the following figure: enter image description here

WHY? Is this a numpy FFT implementation issue? Or is it a limitation of the standard FFT algorithm?

Upvotes: 1

Views: 192

Answers (2)

Michael
Michael

Reputation: 534

  1. To get the power spectrum, you need to take the magnitude of the Fourier coefficient. Plotting the Fourier coefficient directly discards the imaginary component and only plots the real component.
  2. Technically x and f shouldn't be plotted on the same x-axis, since they have different meanings.
import numpy as np
import matplotlib.pyplot as plt

T = 1 # Total signal duration (s)
N = 1024 # samples over signal duration
Freq = 30 # frequency: (Hz)
t = np.arange(N)/N*T # time array

df = 1.0/T # resolution of angular frequency
f = np.arange(N)*df


x = np.sin(2*np.pi*Freq*t)
xhat = np.fft.fft(x) # Fourier series of x

plt.plot(t, x)
plt.xlabel("t (s)")
plt.ylabel("x")
plt.savefig("fig1.png")

plt.cla()
plt.plot(f, np.abs(xhat))
plt.xlabel("f (Hz)")
plt.ylabel("|fft(x)|")
plt.savefig("fig2.png")

enter image description here enter image description here

Upvotes: 1

Ewan
Ewan

Reputation: 415

f is complex number, I should be using abs(f) for plotting. It had slipped my mind :P

Upvotes: 1

Related Questions