2

I have a vibration data in time domain and want to convert it to frequency domain with fft. However the plot of the FFT only shows a big spike at zero and nothing else.

This is my vibration data: https://pastebin.com/7RK57kJW

enter image description here

My code:

import numpy as np
import matplotlib.pyplot as plt

t = np.arange(3000)
a1_fft= np.fft.fft(a1, axis=0)
freq = np.fft.fftfreq(t.shape[-1])
plt.plot(freq, a1_fft)

My FFT Plot:

enter image description here

What am I doing wrong here? I am pretty sure my data is uniform, which provoces in other cases a similar problem with fft.

4
  • Try a logy or logoog plot Commented Jan 3, 2021 at 18:10
  • Your mean is ~1.32 (the first bin), while the sine amplitude is ~0.04. It's not surprising you can't see it Commented Jan 3, 2021 at 18:12
  • Another alternative is to take the FFT of data - data.mean() Commented Jan 3, 2021 at 18:12
  • I'm amazed I couldn't find a sufficiently exact duplicate to close this down. Nice work. Commented Jan 3, 2021 at 18:22

2 Answers 2

2

The bins of the FFT correspond to the frequencies at 0, df, 2df, 3df, ..., F-2df, F-df, where df is determined by the number of bins and F is 1 cycle per bin.

Notice the zero frequency at the beginning. This is called the DC offset. It's the mean of your data. In the data that you show, the mean is ~1.32, while the amplitude of the sine wave is around 0.04. It's not surprising that you can't see a peak that's 33x smaller than the DC term.

There are some common ways to visualize the data that help you get around this. One common methods is to keep the DC offset but use a log scale, at least for the y-axis:

plt.semilogy(freq, a1_fft)

OR

plt.loglog(freq, a1_fft)

Another thing you can do is zoom in on the bottom 1/33rd or so of the plot. You can do this manually, or by adjusting the span of the displayed Y-axis:

p = np.abs(a1_fft[1:]).max() * [-1.1, 1.1]
plt.ylim(p)

If you are plotting the absolute values already, use

p = np.abs(a1_fft[1:]).max() * [-0.1, 1.1]

Another method is to remove the DC offset. A more elegant way of doing this than what @J. Schmidt suggests is to simply not display the DC term:

plt.plot(freq[1:], a1_fft[1:])

Or for the positive frequencies only:

n = freq.size
plt.plot(freq[1:n//2], a1_fft[1:n//2])

The cutoff at n // 2 is only approximate. The correct cutoff depends on whether the FFT has an even or odd number of elements. For even numbers, the middle bin actual has energy from both sides of the spectrum and often gets special treatment.

Sign up to request clarification or add additional context in comments.

2 Comments

@LydiavanDyke. Thanks for the catch. I'm on mobile and just pulling stuff out of my memory.
@LydiavanDyke. Added your suggestion
0

The peak at 0 is the DC-gain, which is very high since you didn't normalize your data. Also, the Fourier transform is a complex number, you should plot the absolute value and phase separately. In this code I also plotted only the positive frequencies:

import numpy as np
import matplotlib.pyplot as plt

#Import data
a1 = np.loadtxt('a1.txt')
plt.plot(a1)

#Normalize a1
a1 -= np.mean(a1)

#Your code
t = np.arange(3000)
a1_fft= np.fft.fft(a1, axis=0)
freq = np.fft.fftfreq(t.shape[-1])

#Only plot positive frequencies
plt.figure()
plt.plot(freq[freq>=0], np.abs(a1_fft)[freq>=0])

3 Comments

Keep in mind that a1 -= np.mean(a1) is a destructive transformation.
What do you mean with destructive transformation?
It removes information from the original dataset. That's not necessarily harmful, but should be done with care.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.