6.14. FFT

Преобразование Фурье раскладывает сигнал из временной области на составляющие его частоты. Быстрое преобразование Фурье (FFT) – это стандартный алгоритм для его эффективного вычисления, ради которого и существует этот модуль и благодаря которому преобразования достаточной для практической пользы длины (1024 точки, 4096 точек) вообще становятся посильными для микроконтроллера.

На камере входными данными обычно является буфер равномерно расположенных отсчётов с микрофона, оси акселерометра, датчика тока или вибрационного зонда; на выходе получается спектр, в котором приложение затем ищет пики, энергию или признаки для классификатора.

numpy.fft предоставляет одномерное дискретное преобразование Фурье. Имеются две функции: fft() (прямое) и ifft() (обратное, нормированное на N).

Длина преобразования должна быть степенью двойки. Другие длины вызывают исключение ValueError. N = 256 и N = 1024 – распространённый выбор: достаточно длинные для приемлемого разрешения по частоте при большинстве встроенных частот дискретизации и достаточно короткие, чтобы поместиться в RAM и завершиться с запасом в пределах одного периода кадра.

fft() принимает действительную часть входных данных в качестве первого позиционного аргумента и необязательную мнимую часть в качестве второго и возвращает кортеж из двух элементов (real, imag) – действительные массивы.

6.14.1. Действительный вход, амплитуда на выходе

Когда приложение подаёт только действительный вход и нуждается лишь в амплитудном спектре:

real, imag = np.fft.fft(x)
magnitude  = np.sqrt(real * real + imag * imag)

Результатом является действительный ndarray той же длины, что и вход. Вспомогательная функция spectrogram() делает ровно это без промежуточных выделений памяти – правильный вызов внутри потокового цикла.

6.14.2. Обратное преобразование

ifft() нормировано так, что прямой и обратный проход возвращают исходный вход с точностью до погрешности чисел с плавающей точкой. Оба вызова принимают и возвращают пару действительных массивов:

real, imag       = np.fft.fft(y)
re_back, im_back = np.fft.ifft(real, imag)

6.14.3. Поиск доминирующей частоты

Распространённая задача – нахождение наибольшего пика в буфере отсчётов: аудио, вибрация, модулированный ИК-сигнал. Рецепт:

  1. Захватите N отсчётов, где N – степень двойки.

  2. Выполните FFT.

  3. Найдите бин с наибольшей амплитудой.

  4. Преобразуйте индекс бина в Гц, используя частоту дискретизации.

from ulab import numpy as np

N  = 1024
fs = 8000.0                       # sample rate, Hz

# ... fill ``samples`` with N data points ...

real, imag = np.fft.fft(samples)
spectrum   = np.sqrt(real * real + imag * imag)

half      = spectrum[:N // 2]     # only first half is meaningful
peak_bin  = np.argmax(half)
peak_hz   = peak_bin * fs / N

print("peak at", peak_hz, "Hz")