web-dev-qa-db-fra.com

comment extraire la fréquence associée aux valeurs fft dans python

J'ai utilisé la fonction fft dans numpy, ce qui a entraîné un tableau complexe. Comment obtenir les valeurs de fréquence exactes?

35
ria

np.fft.fftfreq Vous indique les fréquences associées aux coefficients:

import numpy as np

x = np.array([1,2,1,0,1,2,1,0])
w = np.fft.fft(x)
freqs = np.fft.fftfreq(len(x))

for coef,freq in Zip(w,freqs):
    if coef:
        print('{c:>6} * exp(2 pi i t * {f})'.format(c=coef,f=freq))

# (8+0j) * exp(2 pi i t * 0.0)
#    -4j * exp(2 pi i t * 0.25)
#     4j * exp(2 pi i t * -0.25)

L'OP demande comment trouver la fréquence en Hertz. Je crois que la formule est frequency (Hz) = abs(fft_freq * frame_rate).

Voici du code qui le démontre.

Tout d'abord, nous faisons un fichier wave à 440 Hz:

import math
import wave
import struct

if __== '__main__':
    # http://stackoverflow.com/questions/3637350/how-to-write-stereo-wav-files-in-python
    # http://www.sonicspot.com/guide/wavefiles.html
    freq = 440.0
    data_size = 40000
    fname = "test.wav"
    frate = 11025.0
    amp = 64000.0
    nchannels = 1
    sampwidth = 2
    framerate = int(frate)
    nframes = data_size
    comptype = "NONE"
    compname = "not compressed"
    data = [math.sin(2 * math.pi * freq * (x / frate))
            for x in range(data_size)]
    wav_file = wave.open(fname, 'w')
    wav_file.setparams(
        (nchannels, sampwidth, framerate, nframes, comptype, compname))
    for v in data:
        wav_file.writeframes(struct.pack('h', int(v * amp / 2)))
    wav_file.close()

Cela crée le fichier test.wav. Maintenant, nous lisons les données, les FFT, trouvons le coefficient avec la puissance maximale et trouvons la fréquence fft correspondante, puis convertissons en Hertz:

import wave
import struct
import numpy as np

if __== '__main__':
    data_size = 40000
    fname = "test.wav"
    frate = 11025.0
    wav_file = wave.open(fname, 'r')
    data = wav_file.readframes(data_size)
    wav_file.close()
    data = struct.unpack('{n}h'.format(n=data_size), data)
    data = np.array(data)

    w = np.fft.fft(data)
    freqs = np.fft.fftfreq(len(w))
    print(freqs.min(), freqs.max())
    # (-0.5, 0.499975)

    # Find the peak in the coefficients
    idx = np.argmax(np.abs(w))
    freq = freqs[idx]
    freq_in_hertz = abs(freq * frate)
    print(freq_in_hertz)
    # 439.8975
57
unutbu

Fréquences associées aux valeurs DFT (en python)

Par fft , Fast Fourier Transform, nous comprenons un membre d'une grande famille d'algorithmes qui permettent le fast calcul de la DFT, Discrete Fourier Transform, d'un signal équisamplé.

A DFT convertit une liste de [~ # ~] n [~ # ~] des nombres complexes à une liste de [~ # ~] n [~ # ~] nombres complexes, étant entendu que les deux listes sont périodiques avec période [~ # ~] n [~ # ~] .

Ici, nous traitons de l'implémentation numpy de la fft .

Dans de nombreux cas, vous pensez

  • un signal x défini dans le domaine temporel de la longueur [~ # ~] n [~ # ~] , échantillonné à intervalle constant dt ,
  • sa DFT [~ # ~] x [~ # ~] (ici spécifiquement X = np.fft.fft(x)), dont les éléments sont échantillonnés sur la fréquence axe avec un taux d'échantillonnage dw .

Une définition

  • la période (ou durée) du signal x, échantillonnée à dt avec N échantillons est est

    T = dt*N
    
  • les fréquences fondamentales (en Hz et en rad/s) de X, vos DFT sont

    df = 1/T
    dw = 2*pi/T # =df*2*pi
    
  • la fréquence supérieure est la fréquence de Nyquist

    ny = dw*N/2
    

    (et ce n'est pas dw*N)

Les fréquences associées à un élément particulier de la DFT

Les fréquences correspondant aux éléments de X = np.fft.fft(x) pour un indice donné 0<=n<N Peuvent être calculées comme suit:

def rad_on_s(n, N, dw):
    return dw*n if n<N/2 else dw*(n-N)

ou d'un seul coup

w = np.array([dw*nif n<N/2 else dw*(n-N) for n in range(N)])

si vous préférez considérer les fréquences en Hz, s/w/f/

f = np.array([df*n if n<N/2 else df*(n-N) for n in range(N)])

Utilisation de ces fréquences

Si vous souhaitez modifier le signal d'origine x -> y en appliquant un opérateur dans le domaine fréquentiel sous la forme d'une fonction de fréquence uniquement, le chemin à parcourir est de calculer le w'le sable

Y = X*f(w)
y = ifft(Y)

Présentation de np.fft.fftfreq

Bien sûr, numpy a une fonction pratique np.fft.fftfreq Qui renvoie des fréquences sans dimension plutôt que ceux dimensionnels mais c'est aussi simple que

f = np.fft.fftfreq(N)*N*df
w = np.fft.fftfreq(N)*N*dw
30
gboffi

La fréquence n'est que l'indice du tableau. À l'indice n, la fréquence est 2πn / la longueur du tableau (radians par unité). Considérer:

>>> numpy.fft.fft([1,2,1,0,1,2,1,0])
array([ 8.+0.j,  0.+0.j,  0.-4.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+4.j,
        0.+0.j])

le résultat a des valeurs non nulles aux indices 0, 2 et 6. Il y a 8 éléments. Ça signifie

       2πit/8 × 0       2πit/8 × 2       2πit/8 × 6
    8 e           - 4i e           + 4i e
y ~ ———————————————————————————————————————————————
                          8
5
kennytm