thethruth87
thethruth87

Reputation: 23

Wrong freqs & amplitudes with numpy.fft, furthermore odd drawing of spectra

To understand the usage of ffts, I've just implemented a low-pass filter for a discrete signal in python.

The resulting filtered signal is pretty much what I wanted to get, but unfortunately, the spectra are not what I had expected. They seem OK on the first look, but as you can see, both the amplitudes and frequences are not correct.

The frequencys should be 0Hz, 220Hz, 660Hz and the amplitudes 3, 2, 1; but it comes out as shown in the plot below. Please note that the amplitudes in that plot are not correct due I wrote abs(F)/N instead of 2*abs(F)/N on the plot command. But when I do so, the DC value doubles to 6, which is wrong I think.

enter image description here

And also the drawing of the spectrum seems a little odd to me, please have a look at this:

enter image description here

I have no idea what I am doing wrong and would very much appreciate some help on this.

import numpy as np
import matplotlib.pyplot as plt
from math import pi

N = 2048

w0 = 2*pi*220
t = np.linspace(0, 0.1, N)
signal = lambda x: 3 + 2*np.sin(w0*x) + np.sin(3*w0*x)

f = np.array(signal(t))
F = np.fft.fft(f)
Fo = F.copy()       # just for printing the unfiltered spectrum
freq = np.fft.fftfreq(len(f), 1/N)

# That's the filter, all parts over the frequency of fg should be damped.
fg = 50
for i in range(0, len(f)):
    F[i] *= (1 if abs(freq[i]) < fg else 0)

ff = np.fft.ifft(F)

plt.subplot(3, 1, 1)
plt.plot(t, f, label='f original')
plt.plot(t, ff, label='f filtered')
plt.axis(xmin=0, xmax=16e-3)
plt.legend()

plt.subplot(3, 1, 2)
plt.plot(freq, abs(Fo)/N, label='spec original')
plt.axis(xmin=-200, xmax=200)
plt.legend()

plt.subplot(3, 1, 3)
plt.plot(freq, abs(F)/N, label='spec filtered')
plt.axis(xmin=-200, xmax=200)
plt.legend()

plt.show()

Upvotes: 1

Views: 2866

Answers (1)

tom10
tom10

Reputation: 69172

There are two questions here:

1) Your freq axis is off by a factor of 10 since fftfreq wants the sample spacing (eg, in seconds), which should be total_time/N (or, 0.1/N in your case), not 1/N as you're using.

2) The funny looking plot is because the returned values from the fft are not ordered by increasing values of the frequency, and it happens that the last frequency in the returned values are at the middle frequency in the plot, so that line just ends there. Try instead: just plotting points (rather than points connected by a line) and it will look reasonable; or use fftshift.

Upvotes: 1

Related Questions