当前位置: 首页 > 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.jsqmd.com/news/899479/

相关文章:

  • 2026论文全流程终极榜单:10款AI智能降重工具, 合规修正一路顺畅
  • 窗帘品牌加盟考察关键要点清单!_米兰软装_扶持_保障 - 资讯纵览
  • 群体智能优化算法驱动的多行程车辆路径问题优化算法【附代码】
  • EndNote进阶:解锁中文作者拼音姓名在英文参考文献中的完整显示
  • 2026系统分析
  • 抖音实况动图去水印实测:2026年AI横评6款工具,帮你还原纯净Live Photo - 科技热点发布
  • 最新版MATLAB(R2025b)软件安装步骤
  • 【Python 实战解析】巧用 utf-8-sig 编码,彻底攻克 Excel 打开 CSV 文件乱码难题
  • 2026年5月全国TPU薄膜优选供应商榜单:鞋材“隐形冠军”星达,如何用27年打造“中国梦工厂”? - 资讯纵览
  • token不够? 试试轻度智能 文本行为分析 + 概率预测 二合一工具
  • 从2的0次方到256次方:一张表看懂计算机的“二进制宇宙”
  • 2026年 消化内镜清洗消毒设备/二氧化碳送气泵/高频电刀/送水装置等内镜配套设备与耗材厂家推荐榜单:专业医疗品牌深度解析及选购指南 - 品牌企业推荐师(官方)
  • 2026 年主流短信供应商对比 - 资讯纵览
  • 释放被锁住的音乐:QMCDecode让你的QQ音乐文件重获自由
  • 终极百度网盘下载加速方案:Python命令行工具突破限速瓶颈
  • 5分钟搭建微信群消息自动转发系统:告别手动复制的烦恼
  • 每年花百万买CATIA?通过许可优化,某车企如何在不增加采购下提升30%利用率
  • 【算法实现与优化 44】从分治到蝶形运算:图解FFT与IFFT的迭代与递归实现
  • 保姆级横评!如何下载视频号的视频到手机相册?2026年这7个方法实测告诉你哪个最靠谱 - 科技热点发布
  • 【.NET】集成SqlSugar实现仓储模式
  • GraphRAG【部署 01】Linux环境安装部署GraphRAG并使用Ollama本地大模型
  • 2026年iherb最新折扣码618大促优惠码 - 李先生sir
  • 小红书改版后发布按钮抓不到?两个思路绕开Shadow DOM限制
  • 2026年值得推荐的原装进口艺术漆榜单:意大利石灰基、矿物、灰泥艺术涂料与德系精工谁更强? - 资讯纵览
  • 2026年5月知网AI率突然飙升?4款降AI软件深度推荐+实测 - 我要发一区
  • 从开题到定稿零返工:okbiye AI 毕业论文写作功能实测与流程拆解
  • 经济下行压力大,EB-Cable的license费用怎么砍?我这儿有几招狠的
  • Android开发转AI Agent:第2天——temperature调到1.5,LLM开始胡说八道
  • 4款降AI软件实测红黑榜:2026年5月哪个能真的去AI痕迹 - 我要发一区
  • 解耦异构算力与多协议接入:基于Docker与源码交付的开源企业级GB28181/RTSP边缘计算AI视频管理平台架构深度解析