Flutter中生成正弦波信号用于FFT测试的异常问题排查
问题根源与修正方案
核心问题分析
信号生成逻辑缺失采样率定义
你直接用采样点索引i作为时间变量,相当于默认采样率Fs=1Hz,但此时设置的frequency=0.01Hz,100个采样点仅覆盖1个完整周期,理论上FFT应在对应bin出现峰值,但后续FFT处理的错误掩盖了这一点。FFT输出处理完全错误
多数FFT库的realFft方法针对实输入信号,会返回压缩的共轭对称频域结果(仅保留前半部分),且返回值包含完整的实部和虚部信息。你直接将每个结果转为虚部为0的复数,完全丢弃了虚部,导致频域数据彻底失真。未计算有效幅度谱
原始FFT复数输出需要取模(或模平方)才能得到反映信号能量的幅度谱,直接查看实部无法体现频率分量的存在。
修正后的代码
import 'dart:math'; import 'package:complex/complex.dart'; import 'package:dart_fft/dart_fft.dart'; List<double> generateMockSignal() { final double amplitude = 50.0; // 实际信号频率(单位:Hz) final double frequency = 1.0; final double phase = 0.0; final int numSamples = 100; // 采样率(单位:Hz,定义每秒采集的样本数) final double sampleRate = 100.0; final List<double> signal = List.generate(numSamples, (i) { // 计算当前采样点的实际时间 double t = i / sampleRate; return amplitude * sin(2 * pi * frequency * t + phase); }); return signal; } List<double> computeFFTMagnitude(List<double> signal) { final int n = signal.length; final fft = FFT(n); // realFft返回完整的半长复数频域结果 final List<Complex> freqDomain = fft.realFft(signal); // 计算每个频点的幅度(复数模长) List<double> magnitude = freqDomain.map((complex) => complex.abs()).toList(); // 实信号FFT的对称分量被压缩,除DC和Nyquist分量外,其余幅度需乘以2还原 for (int i = 1; i < magnitude.length - 1; i++) { magnitude[i] *= 2; } return magnitude; }
验证说明
- 当设置
frequency=1.0Hz、sampleRate=100Hz、numSamples=100时,FFT的频率bin间隔为sampleRate/numSamples=1Hz,第1个非DC bin(索引1)会出现明显峰值。 - 若测试非整数周期信号(如
frequency=1.5Hz),会出现频谱泄漏,可添加汉宁窗等窗函数优化:在生成信号后,对每个采样点乘以0.5 * (1 - cos(2*pi*i/numSamples))。 - 避免设置过大振幅,若使用定点FFT实现可能触发数值溢出,导致杂散噪声。
内容的提问来源于stack exchange,提问作者sleepyboi
相关产品推荐
相关产品推荐

