当前位置: 首页 > news >正文

信号分析~FFT

没问题,咱们把所有数学公式和深奥的信号处理术语都扔到一边。作为 C# 程序员,我们用最直观的“代码逻辑”“生活类比”来解构快速傅里叶变换(FFT)。


1. 到底什么是 FFT?(棱镜类比)

想象一下,你手里有一束白光,你无法一眼看出它是由哪些颜色的光组成的。但是,如果你让它穿过一个三棱镜,白光就会被分解成红、橙、黄、绿、青、蓝、紫的光谱。

在数字信号处理中:

  • 原始采集的数据(随时间波动的电流/电压信号)就是那束白光(时域信号 Time Domain)。
  • FFT 算法就是那个三棱镜
  • FFT 输出的结果就是被分解出来的各色光谱(频域信号 Frequency Domain),它会告诉你:这个信号在 50Hz 频率上有很大的能量(可能是电机震动),在 1000Hz 上也有能量(可能是风扇尖叫)。

image


2. 持续采集的数据,如何“喂”给 FFT?

这是初学者最容易困惑的地方:数据是一直源源不断进来的,而 FFT 是一个函数,它需要一个固定长度的数组作为输入。

所以,你不能把整条无限长的数据丢进去,而是要通过“滑动窗口(Sliding Window)”的方式,把连续的数据切成一段一段固定大小的“数据块”(在代码里通常叫 Buffer 或 Frame)。

核心概念:FFT 点数( N )

你每次喂给 FFT 函数的数组长度,就是 FFT 点数,通常用 N 表示。

  • 铁律: N 必须是 2 的次幂(例如 512, 1024, 2048, 4096...)。因为 FFT 算法内部使用了分治法,2 的次幂计算速度最快。
  • 如果你的设备采样率是 Freq = 1000 Hz (1秒采集1000个点),你选了 N = 1024,那么大约每 1 秒,你就能攒够一个数组做一次 FFT。

连续数据的“切片”过程

假设我们设定 N = 1024,重叠度(Overlap)为 50%:

  1. 第 1 次分析: 采集到第 1 ~ 1024 个点。把这 1024 个 double 复制到一个单独的数组里,送去执行 FFT。
  2. 第 2 次分析: 不用等下一个 1024 点。因为有 50% 重叠,我们只需要再新采集 512 个点。此时,取第 513 ~ 1536 个点(包含了前一次的后半段),组合成新的 1024 个点,送去执行 FFT。
  3. 第 3 次分析: 再等 512 个新点,取第 1025 ~ 2048 个点,做 FFT……

由此循环往复。每一次 FFT 产生的分析结果,就是瀑布图上的一条线(一个时间点)。随着时间推移,这些线在 Y 轴上累加,就形成了瀑布。


3. FFT 函数的输入与输出(程序员视角)

在 C# 中,以 MathNet.Numerics 库为例,FFT 的核心函数长这样:

// 输入:一个长度为 N 的复数数组(Complex 是库里自带的结构体)
// 输出:直接修改原数组,原数组里的数据会被替换为频域结果
MathNet.Numerics.IntegralTransforms.Fourier.Forward(complexSignal, FourierOptions.NoScale);

为什么输入是“复数(Complex)”?

原始采集的数据明明只是 double 类型的电压或振动值(只有实部,没有虚部),为什么函数要求传 Complex 数组?

  • 做法: 你只需要创建一长一模一样的 Complex 数组,把采集到的 double 值赋给它的 Real(实部),把 Imaginary(虚部)全部设为 0 即可。

关键:如何理解 FFT 的输出结果?

假设你传入了一个长度 N = 1024 的数组,FFT 执行完后,这个数组里的内容就变了。它不再代表时间,而是代表频率区间(英文叫 Bin)

因为数学对称性,1024 个输出点里,只有前一半(0 到 512)是有用的,后一半是镜像(重复的),直接扔掉。

这 0 ~ 512 个复数,究竟代表什么?请看下表映射关系:

数组索引 (i) 对应的物理频率 (Hz) 如何计算该频率的幅值(能量大小)
[0] 0 Hz (直流分量/信号平均值) complexSignal[0].Magnitude
[1] 1 X (Freq / N) complexSignal[1].Magnitude
[2] 2 X (Freq / N) complexSignal[2].Magnitude
... ... ...
[512] 512 X (Freq / N) (等于 Freq / 2,即最高有效频率) complexSignal[512].Magnitude

image


4. C# 伪代码:实现一个标准的 FFT 分析管道

结合上面的理论,你的 C# 业务逻辑代码大概长这样:

using MathNet.Numerics;
using System.Numerics; // 包含 Complex 结构体public class FftAnalyzer
{private int _fftPoints = 1024; // N 必须是 2 的次幂private double _sampleRate = 2000; // 假设硬件采样率是 2000Hz// 当滑动窗口攒够了 1024 个原始 double 数据时,调用此方法public double[] AnalyzeFrame(double[] rawTimeData){// 1. 准备复数数组Complex[] complexSignal = new Complex[_fftPoints];// 2. 加窗(防止频谱泄露,MathNet自带函数)double[] window = Window.Hanning(_fftPoints);for (int i = 0; i < _fftPoints; i++){// 原始数据乘上窗函数的值,填入实部,虚部为 0complexSignal[i] = new Complex(rawTimeData[i] * window[i], 0);}// 3. 执行快速傅里叶变换 (FFT)// 执行后,complexSignal 内部的值已经变成了频域复数MathNet.Numerics.IntegralTransforms.Fourier.Forward(complexSignal, FourierOptions.NoScale);// 4. 提取有效的一半数据(0 到 N/2),并计算幅值int halfPoints = _fftPoints / 2;double[] magnitudeResult = new double[halfPoints];for (int i = 0; i < halfPoints; i++){// 计算复数的模长,并进行归一化缩放(乘以 2/N)double rawMagnitude = complexSignal[i].Magnitude * (2.0 / _fftPoints);// 如果是声学,通常在这里转成 dB:20 * Math.Log10(rawMagnitude)magnitudeResult[i] = rawMagnitude; }// 返回的这个数组,长度为 512// magnitudeResult[0] 是 0Hz 的幅值// magnitudeResult[511] 是接近 1000Hz 的幅值return magnitudeResult; }
}

5. 最终如何变成瀑布图?

你每秒钟可能会调用上面的 AnalyzeFrame 方法好几十次。

  • 第一次调用,得到 magnitudeResult_1(一个包含 512 个元素的数组)。这就是瀑布图的第一行数据。
  • 第二次调用,得到 magnitudeResult_2这就是瀑布图的第二行数据。

把这些数组像砌砖一样,一行一行在时间轴(Y轴)上累加起来,交给 ScottPlot 或 SciChart 这样的图表控件,一张炫酷的 3D 瀑布图或热力图就诞生了。

看到这里,对于数据怎么从“一长串数字”变成“一帧帧频域幅值”,逻辑上感觉闭合了吗?

http://www.gsyq.cn/news/1407860.html

相关文章:

  • 无需编程的文本挖掘神器:KH Coder完整指南与实战技巧
  • 别再手动查规则了!ChatGPT一键解析《Gloomhaven》《Terraforming Mars》等硬核桌游的终极提示词库(含中文语境优化版,限前500名领取)
  • 窗帘品牌加盟考察关键要点清单!_米兰软装_扶持_保障 - 资讯纵览
  • 井下做业实时监测透明化三维立体重构视频伴生数字伴生安全治理
  • 矿山做业全域透明.风险清零透明化三维立体重构AI预判解决方案
  • 如何快速批量下载网易云音乐歌单的FLAC无损音乐:终极指南
  • 矿山做业实景透明.智能预警透明化三维立体重构AI预判盲区管控
  • 抖音实况动图去水印实测:2026年AI横评6款工具,帮你还原纯净Live Photo - 科技热点发布
  • 带标注的交警指挥手势识别数据集,识别率97.9%,可识别停车,右转等8种手势,1731张图,支持yolo,coco json,voc xml,文末有模型训练代码
  • 京东登录模拟:模拟滑块验证后的登录流程(基础版)。京东模拟登录实战:从滑块验证到请求构造的完整指南
  • 【故障诊断】最大二阶循环平稳盲反卷积(CYCBD)在滚动体轴承故障诊断中的应用附Matlab代码
  • 最新版MATLAB(R2025b)软件安装步骤
  • 释放被锁住的音乐:QMCDecode让你的QQ音乐文件重获自由
  • 【算法实现与优化 44】从分治到蝶形运算:图解FFT与IFFT的迭代与递归实现
  • 终极QMC音乐解锁指南:3分钟将加密音乐转换为标准格式
  • 计算机视觉驱动的禽蛋裂纹识别技术应用【附代码】
  • CANoe实战指南:Log高效保存与智能回放策略
  • 【.NET】集成SqlSugar实现仓储模式
  • 计算机视觉驱动的鸭蛋双黄与裂纹与新鲜度无损检测【附代码】
  • 自适应反步控制实战:从理论到单机械臂稳定控制
  • 规范驱动开发实践:ZeeSpec工具在Greenfield与Brownfield项目中的应用
  • Android开发转AI Agent:第2天——temperature调到1.5,LLM开始胡说八道
  • 动态秩适应与结构化剪枝:打造高效多媒体理解大模型
  • Java在AI时代的战略价值:从企业基石到智能引擎
  • 2026年跨境POD系统选购指南:风擎科技等主流方案深度对比 - 资讯纵览
  • VAST XML校验工具vastlint:广告技术中的严格语法守卫者
  • IT之家:解构2026年GEO服务商五强——格局、壁垒与唯一性 - 罗兰艺境GEO
  • 每年花百万买CATIA?通过许可优化,某车企如何在不增加采购下提升30%利用率
  • 双重引擎:量子计算与AI如何将人类文明推向恒星时代
  • Cesium 冷门但致命的 FOV 机制:横竖屏自动切换原理