Plotting power spectrum in python

后端 未结 5 1991
情深已故
情深已故 2020-12-07 09:51

I have an array with 301 values, which were gathered from a movie clip with 301 frames. This means 1 value from 1 frame. The movie clip is running at 30 fps, so is in fact 1

相关标签:
5条回答
  • 2020-12-07 10:24

    Numpy has a convenience function, np.fft.fftfreq to compute the frequencies associated with FFT components:

    from __future__ import division
    import numpy as np
    import matplotlib.pyplot as plt
    
    data = np.random.rand(301) - 0.5
    ps = np.abs(np.fft.fft(data))**2
    
    time_step = 1 / 30
    freqs = np.fft.fftfreq(data.size, time_step)
    idx = np.argsort(freqs)
    
    plt.plot(freqs[idx], ps[idx])
    

    enter image description here

    Note that the largest frequency you see in your case is not 30 Hz, but

    In [7]: max(freqs)
    Out[7]: 14.950166112956811
    

    You never see the sampling frequency in a power spectrum. If you had had an even number of samples, then you would have reached the Nyquist frequency, 15 Hz in your case (although numpy would have calculated it as -15).

    0 讨论(0)
  • 2020-12-07 10:28

    From the numpy fft page http://docs.scipy.org/doc/numpy/reference/routines.fft.html:

    When the input a is a time-domain signal and A = fft(a), np.abs(A) is its amplitude spectrum and np.abs(A)**2 is its power spectrum. The phase spectrum is obtained by np.angle(A).

    0 讨论(0)
  • 2020-12-07 10:37

    if rate is the sampling rate(Hz), then np.linspace(0, rate/2, n) is the frequency array of every point in fft. You can use rfft to calculate the fft in your data is real values:

    import numpy as np
    import pylab as pl
    rate = 30.0
    t = np.arange(0, 10, 1/rate)
    x = np.sin(2*np.pi*4*t) + np.sin(2*np.pi*7*t) + np.random.randn(len(t))*0.2
    p = 20*np.log10(np.abs(np.fft.rfft(x)))
    f = np.linspace(0, rate/2, len(p))
    plot(f, p)
    

    enter image description here

    signal x contains 4Hz & 7Hz sin wave, so there are two peaks at 4Hz & 7Hz.

    0 讨论(0)
  • 2020-12-07 10:41

    Since FFT is symmetric over it's centre, half the values are just enough.

    import numpy as np
    import matplotlib.pyplot as plt
    
    fs = 30.0
    t = np.arange(0,10,1/fs)
    x = np.cos(2*np.pi*10*t)
    
    xF = np.fft.fft(x)
    N = len(xF)
    xF = xF[0:N/2]
    fr = np.linspace(0,fs/2,N/2)
    
    plt.ion()
    plt.plot(fr,abs(xF)**2)
    
    0 讨论(0)
  • 2020-12-07 10:46

    You can also use scipy.signal.welch to estimate the power spectral density using Welch’s method. Here is an comparison between np.fft.fft and scipy.signal.welch:

    from scipy import signal
    import numpy as np
    import matplotlib.pyplot as plt
    
    fs = 10e3
    N = 1e5
    amp = 2*np.sqrt(2)
    freq = 1234.0
    noise_power = 0.001 * fs / 2
    time = np.arange(N) / fs
    x = amp*np.sin(2*np.pi*freq*time)
    x += np.random.normal(scale=np.sqrt(noise_power), size=time.shape)
    
    # np.fft.fft
    freqs = np.fft.fftfreq(time.size, 1/fs)
    idx = np.argsort(freqs)
    ps = np.abs(np.fft.fft(x))**2
    plt.figure()
    plt.plot(freqs[idx], ps[idx])
    plt.title('Power spectrum (np.fft.fft)')
    
    # signal.welch
    f, Pxx_spec = signal.welch(x, fs, 'flattop', 1024, scaling='spectrum')
    plt.figure()
    plt.semilogy(f, np.sqrt(Pxx_spec))
    plt.xlabel('frequency [Hz]')
    plt.ylabel('Linear spectrum [V RMS]')
    plt.title('Power spectrum (scipy.signal.welch)')
    plt.show()
    

    [fft[2]

    0 讨论(0)
提交回复
热议问题