Search code examples
pythonfftfrequency

how use fft in accelemetros data to transform in spectrum power?


I placed vibrations of a component using accelerometers, then produced a dataframe with accelerations, that is, dataframe with the following columns: accX, accY and accZ. It is a variable in time, that is, a time series.

My idea is to transform the domain (time (s)) of this variable into the frequency domain (Hz) using fast transform furrier. And for that, I've been researching how I can do it, and one of the most used is fft from the numpy library. However, I couldn't bring it to mine.

dataframe of vibrations data


I have been trying:

# Apply the FFT function to each column
fft_result_X = np.fft.fft(accX)
fft_result_Y = np.fft.fft(accY)
fft_result_Z = np.fft.fft(accZ)

# Calculate the magnitude of the power spectrum of each column
power_spectrum_X = np.abs(fft_result_X) ** 2
power_spectrum_Y = np.abs(fft_result_Y) ** 2
power_spectrum_Z = np.abs(fft_result_Z) ** 2

# Frequencies corresponding to the spectrum
frequencies = np.fft.fftfreq(len(accX), 1/62.5)

result this frequencies and power_spectruns

But, scaling up the accY power spectrum plot, there is a strange behavior in my eyes, see:

accY power spectrum plot

I've also been using:

data = dado['accX'].values
ps = np.abs(np.fft.fft(data))**2

time_step = 1 / 62.5 # sampling frequency
freqs = np.fft.fftfreq(data.size, time_step)
idx = np.argsort(freqs)

plt.plot(freqs[idx], ps[idx])
plt.show()

accX power spectrum


Solution

  • The numpy.fft.fft() will return both conjugate pairs. What you want to use is the numpy.fft.rfft(). Same thing for numpy.fft.rfftfreq(). Additionally, you should probably normalize your results as well. See the below for a similar example I made.

    from datetime import datetime as dt
    start=dt.now()
    
    import numpy as np
    import pandas as pd
    from scipy.fft import rfft, rfftfreq  
    import matplotlib.pyplot as plt
    
    
    data_filepath = "Lab 3 Data.xlsx"
    df = pd.read_excel(data_filepath)
    
    V1 = np.array(list(df["Voltage Data 1"]))
    V2 = np.array(list(df["Voltage Data 2"]))
    V3 = np.array(list(df["Voltage Data 3"]))
    
    V1_fft = (abs(rfft(V1) / V1.size))[0:601]
    V2_fft = (abs(rfft(V2) / V2.size))[0:601]
    V3_fft = (abs(rfft(V3) / V3.size))[0:601]
    
    t1 = np.linspace(0, V1.size / 1200, V1.size)
    t2 = np.linspace(0, V2.size / 1200, V2.size)
    t3 = np.linspace(0, V3.size / 1200, V3.size)
    
    f1 = rfftfreq(1200, 1 / 1200)
    f2 = rfftfreq(1200, 1 / 1200)
    f3 = rfftfreq(1200, 1 / 1200)
    
    fig1, ax1 = plt.subplots(3, 1, figsize = (6.5, 6), dpi = 80)
    
    ax1[0].plot(t1, V1, color = "blue", alpha = 0.5, label = "Data Set 1")
    ax1[0].axvspan(4, 4.2, color = "blue", alpha = 0.2, label = "Data Set 1 Limits")
    
    ax1[1].plot(t2, V2, color = "red", alpha = 0.5, label = "Data Set 2")
    ax1[1].axvspan(1.8, 2, color = "red", alpha = 0.1, label = "Data Set 2 Limits")
    
    ax1[2].plot(t3, V3, color = "green", alpha = 0.5, label = "Data Set 3")
    
    fig1.suptitle("Figure 1: Voltage over Time Comparison,\n Selected Fourier Transform Data Limits")
    
    plt.setp(ax1[1], xlabel= "Time (s)")
    plt.setp(ax1[:], ylabel = "Voltage (V)")
    
    fig2, ax2 = plt.subplots(3, 1, figsize = (6.5, 6), dpi = 80)
    ax2[0].plot(f1, V1_fft)
    ax2[1].plot(f2, V2_fft)
    ax2[2].plot(f3, V3_fft)
    
    
    print("Runtime: {0}".format(dt.now()-start))
    plt.show()