未知实际采样率的Android加速度计数据如何进行FFT计算

核心前提
处理非恒定采样率信号的基础是你采集数据时同步存储了每个加速度样本对应的传感器时间戳,Android SensorEvent 回调自带纳秒级时间戳字段,基于系统启动时间计数,不受系统时间修改影响,采集时务必保留该字段。
方案1:重采样为均匀采样序列后做常规FFT(推荐,实现简单兼容性好)
这是最常用的处理方案,适合采样率波动范围不大的20Hz预设场景:
- 先基于原始时间戳计算实际平均采样率:总样本数除以第一个样本到最后一个样本的时间差,得到
Fs_avg - 确定重采样目标采样率,可选你预设的20Hz,也可以取略高于
Fs_avg的整数值,确保目标采样率大于你要分析的最高信号频率的2倍,满足奈奎斯特采样定律 - 生成均匀时间格点,用插值算法将非均匀采样的加速度值映射到均匀时间格点上:优先选线性插值,加速度计属于低频信号,线性插值的误差完全可接受,要求更高可换三次样条插值
- 得到均匀采样序列后,直接执行常规FFT计算即可,建议提前加汉宁/汉明窗减少频谱泄漏
示例代码(Python):
import numpy as np from scipy.interpolate import interp1d from scipy.fft import fft, fftfreq # 原始输入:timestamps为样本对应的时间戳数组(单位转成秒),acc_data为对应加速度值数组 timestamps = ... acc_data = ... # 计算平均采样率 total_duration = timestamps[-1] - timestamps[0] fs_avg = len(timestamps) / total_duration # 目标采样率取预设的20Hz fs_target = 20 # 生成均匀时间轴 t_uniform = np.arange(timestamps[0], timestamps[-1], 1/fs_target) # 线性插值得到均匀采样序列 interp_func = interp1d(timestamps, acc_data, kind="linear") acc_uniform = interp_func(t_uniform) # 加窗执行FFT,得到单侧频谱 n_sample = len(acc_uniform) window = np.hanning(n_sample) acc_windowed = acc_uniform * window fft_result = fft(acc_windowed) freq_axis = fftfreq(n_sample, 1/fs_target)[:n_sample//2] amplitude_spectrum = 2.0 / n_sample * np.abs(fft_result[:n_sample//2])
方案2:直接使用非均匀傅里叶变换(NUFFT)
如果你的采样率波动非常大,担心重采样插值带来的误差,可以直接用NUFFT处理非均匀采样序列,不需要做重采样:
- 目前主流数值计算工具都有成熟的NUFFT实现:Python可以用
scipy.signal.nufft或者pynufft库,MATLAB有内置的nufft函数 - 直接输入原始的时间戳和加速度值即可得到频谱结果,频率轴可以根据你的分析需求自定义范围
注意事项
- 如果你之前采集的数据没有保存时间戳,无法完成上述处理,只能重新采集时补充存储时间戳
- 频谱的最高有效频率由你原始采样的最小间隔决定,不要超过
1/(2*最小采样间隔),否则会出现混叠 - 两种方案都可以准确得到加速度信号的频谱特征,普通分析场景优先选方案1即可
内容的提问来源于stack exchange,提问作者ciolo
相关产品推荐
相关产品推荐

