6.14. FFT

傅里叶变换(Fourier transform)将时域信号分解为其组成的各个频率分量。快速傅里叶变换FFT)是高效计算傅里叶变换的标准算法——这正是该模块存在的原因,也是足够长(1024 点、4096 点)以致实用的变换得以在微控制器上可行的原因。

在摄像头上,输入通常是来自麦克风、加速度计某一轴、电流传感器或振动探头的等间隔采样缓冲区;输出则是一段频谱,应用随后会从中检查峰值、能量或分类器特征。

numpy.fft 提供一维离散傅里叶变换。这两个函数是 fft()(正变换)和 ifft()(逆变换,以 N 归一化)。

变换长度必须是 2 的幂。其他长度会引发 ValueErrorN = 256N = 1024 是常见选择:在大多数嵌入式采样率下足够长以获得可用的频率分辨率,又足够短以装入 RAM 并在一个帧周期内充分完成。

fft() 以输入的实部作为第一个位置参数,以可选的虚部作为第二个参数,并返回一个由实数数组构成的二元组 (real, imag)

6.14.1. 实数输入、幅度输出

当应用只提供实数输入且只需要幅度谱时:

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

结果是一个与输入等长的实数 ndarrayspectrogram() 辅助函数正是执行这一操作,且不产生中间分配——是流式循环内部应当调用的函数。

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 的幂。

  2. 执行 FFT。

  3. 找到幅度最大的频段(bin)。

  4. 使用采样率将该频段索引转换为 Hz。

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