web-dev-qa-db-fra.com

Tracé du spectre de puissance dans python

J'ai un tableau avec 301 valeurs, qui ont été recueillies à partir d'un clip avec 301 images. Cela signifie 1 valeur de 1 image. Le clip fonctionne à 30 ips, donc en fait 10 secondes

Maintenant, je voudrais obtenir le spectre de puissance de ce "signal" (avec le bon axe). J'ai essayé:

 X = fft(S_[:,2]);
 pl.plot(abs(X))
 pl.show()

J'ai aussi essayé:

 X = fft(S_[:,2]);
 pl.plot(abs(X)**2)
 pl.show()

Bien que je ne pense pas que ce soit le spectre réel.

le signal: enter image description here

Le spectre: enter image description here

Le spectre de puissance:

enter image description here

Quelqu'un peut-il fournir de l'aide avec cela? Je voudrais avoir un graphique en Hz.

30
Olivier_s_j

Numpy a une fonction de commodité, np.fft.fftfreq pour calculer les fréquences associées aux composants FFT:

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

Notez que la plus grande fréquence que vous voyez dans votre cas n’est pas 30 Hz, mais

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

Vous ne voyez jamais la fréquence d'échantillonnage dans un spectre de puissance. Si vous aviez eu un nombre pair d'échantillons, alors vous auriez atteint la fréquence de Nyquist , 15 Hz dans votre cas (bien que numpy l'aurait calculé comme étant -15).

47
Jaime

si rate est le taux d'échantillonnage (Hz), alors np.linspace(0, rate/2, n) est le tableau de fréquences de chaque point de fft. Vous pouvez utiliser rfft pour calculer le fft dans vos données est des valeurs réelles:

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

le signal x contient une onde sinusoïdale de 4Hz et 7Hz, il y a donc deux pics à 4Hz et 7Hz.

17
HYRY

De la page numpy fft http://docs.scipy.org/doc/numpy/reference/routines.fft.html :

Lorsque l'entrée a est un signal temporel et que A = fft (a), np.abs (A) correspond à son spectre d'amplitude et np.abs (A) ** 2 correspond à son spectre de puissance. Le spectre de phase est obtenu par np.angle (A).

4
glormph

Vous pouvez également utiliser scipy.signal.welch pour estimer la densité spectrale de puissance à l’aide de la méthode de Welch. Voici une comparaison entre np.fft.fft et 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] welch

3
Noam Peled

Puisque la FFT est symétrique par rapport à son centre, la moitié des valeurs suffit.

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)
2
Abhi