You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中生成正弦波信号用于FFT测试的异常问题排查

问题根源与修正方案

核心问题分析

  1. 信号生成逻辑缺失采样率定义
    你直接用采样点索引i作为时间变量,相当于默认采样率Fs=1Hz,但此时设置的frequency=0.01Hz,100个采样点仅覆盖1个完整周期,理论上FFT应在对应bin出现峰值,但后续FFT处理的错误掩盖了这一点。

  2. FFT输出处理完全错误
    多数FFT库的realFft方法针对实输入信号,会返回压缩的共轭对称频域结果(仅保留前半部分),且返回值包含完整的实部和虚部信息。你直接将每个结果转为虚部为0的复数,完全丢弃了虚部,导致频域数据彻底失真。

  3. 未计算有效幅度谱
    原始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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 13:18:03