Как извлечь частоту, связанную с FFT значениями в Python?
Я использовал функцию fft
из библиотеки numpy, и в результате получил массив комплексных чисел. Как мне получить точные значения частот?
2 ответ(ов)
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
Таким образом, мы смогли определить частоту в герцах после выполнения преобразования Фурье и анализа коэффициентов.
Частота в данном случае определяется как индекс в массиве. На индексе 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 ) — мнимую единицу. Таким образом, преобразование Фурье позволяет нам понять, как различные частоты влияют на сигнал.
Наиболее эффективный способ применения функции к массиву NumPy
Как задать верхние и нижние границы при использовании numpy.random.normal
Цветовой график 2D массива в matplotlib
Преобразование байтового массива обратно в массив numpy
Взвешенный процентиль с помощью numpy