6.14. FFT¶
傅里叶变换(Fourier transform)将时域信号分解为其组成的各个频率分量。快速傅里叶变换(FFT)是高效计算傅里叶变换的标准算法——这正是该模块存在的原因,也是足够长(1024 点、4096 点)以致实用的变换得以在微控制器上可行的原因。
在摄像头上,输入通常是来自麦克风、加速度计某一轴、电流传感器或振动探头的等间隔采样缓冲区;输出则是一段频谱,应用随后会从中检查峰值、能量或分类器特征。
numpy.fft 提供一维离散傅里叶变换。这两个函数是 fft()(正变换)和 ifft()(逆变换,以 N 归一化)。
变换长度必须是 2 的幂。其他长度会引发 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. 查找主频率¶
一种常见模式是在采样缓冲区中定位最大峰值——音频、振动、调制红外信号。方法如下:
采集
N个样本,其中N为 2 的幂。执行 FFT。
找到幅度最大的频段(bin)。
使用采样率将该频段索引转换为 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")