0

Как извлечь частоту, связанную с FFT значениями в Python?

28

Я использовал функцию fft из библиотеки numpy, и в результате получил массив комплексных чисел. Как мне получить точные значения частот?

2 ответ(ов)

0

np.fft.fftfreq возвращает частоты, соответствующие коэффициентам:

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)

Вопрос заключается в том, как получить частоту в герцах (Гц). Я полагаю, что формула следующая: частота (Гц) = abs(fft_freq * частота_кадров).

Вот пример кода, который иллюстрирует этот процесс.

Сначала создадим звуковой файл на частоте 440 Гц:

import math
import wave
import struct

if __name__ == '__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()

Этот код создает файл test.wav. Теперь мы считываем данные, выполняем FFT, находим коэффициент с максимальной мощностью и соответствующую частоту FFT, затем конвертируем в герцы:

import wave
import struct
import numpy as np

if __name__ == '__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)

    # Найдем пиковое значение в коэффициентах
    idx = np.argmax(np.abs(w))
    freq = freqs[idx]
    freq_in_hertz = abs(freq * frate)
    print(freq_in_hertz)
    # 439.8975

Таким образом, мы смогли определить частоту в герцах после выполнения преобразования Фурье и анализа коэффициентов.

0

Частота в данном случае определяется как индекс в массиве. На индексе n частота равна ( \frac{2\pi n} ), где ( N ) — длина массива (в радианах на единицу). Рассмотрим следующий пример:

>>> 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])

Результат показывает ненулевые значения в индексах 0, 2 и 6. Поскольку массив содержит 8 элементов, это означает, что:

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

Где ( e ) обозначает экспоненциальную функцию, а ( i ) — мнимую единицу. Таким образом, преобразование Фурье позволяет нам понять, как различные частоты влияют на сигнал.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь