0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

快速傅里叶变换FFT原理

冬至子 来源:湖畔随想录 作者:付聪 2023-07-20 14:38 次阅读

两种含义

学习信号处理经常会被各种变换搞得晕头转向,这也是很正常的事,大可不必惊慌。晕的原因有两个,一是各种变换公式看上去差不多,中间有或多或少的联系,但又很不一样,可能适用于不同的情况,有不同的限制等;二是这门学科确实起名太混淆了点,比如DTFT(Discrete Time Fourier Transform,离散时间傅里叶变换),DFT(Discrete Fourier Transform,离散傅里叶变换),DFS(Discrete Fourier Series,离散傅里叶级数),FFT(Fast Fourier Transform,快速傅里叶变换)。这些变换名字差不多,公式也差不多,不太容易搞清楚各自确切的含义和互相的联系。

本文不去很深入的研究每一个变换,只关注工程实践中最常用的FFT,来简单剖析一下它的含义,性质和一些用法。

FFT的含义可以从两个角度去理解,首先是DFS角度,其次是DTFT角度。

从DFS角度来说:FFT本质上就DFT,而DFT和DFS没有什么不同。

第一句很好理解,因为FFT就是DFT的快速算法

快了多少呢?DFT的时间复杂度是N^2,FFT的时间复杂度是NlogN。所以,假设N=1024,那就快了N/logN=102.4倍,可以说天壤之别。

现在看DFS:

图片

图片

DFS是离散周期序列x[n]到离散周期序列X[k]的变换,x[n]和X[k]周期相同均为N。因为非周期信号工程中更常见,科学家们就截取了DFS对的各自一个周期,定义为DFT变换。这样DFT本质上就是DFS,只是隐含了周期性的假设。

所以,对一个非周期信号x[n]进行长度为N的DFT变换,首先是对x[n]进行周期为N的周期延拓,再求这个周期信号的DFS变换X(k),最后截取X(k)一个周期,就得到x[n]的DFT。

因为离散序列通过DFT(或DFS)变换后还是离散序列,这意味着变换前后都很方便用计算机处理,所以DFT在实践中非常重要。

另外还可以从DTFT的角度来理解FFT。

先看DTFT的公式:

图片

图片

DTFT是离散非周期信号到连续周期信号的变换,频域是周期连续信号,显然是以2Pi为周期(所有频率都是以2Pi为周期)。DFS是对这个非周期信号进行周期延拓,在频域就是对DTFT进行采样。我们可以认为DFS设定的信号的周期延拓的周期N(也就是FFT的长度N)为DTFT一个周期内的采样个数,N设定的越长,采样越频繁。

比如下图:

图片

图1 一个 [1 1 1 1] 的有限长序列分别进行长度为8,16,128,1024的FFT

可见DFS选择不同的周期N延拓非周期信号的时候,相当于对DTFT的每个周期进行采样点为N的采样。因为DTFT以[0, 2Pi)为周期,则DFS中0对应频率0,N对应频率2Pi。

注意上面都是说的DFS,而FFT本质上就是DFS。

N的选择

计算FFT的时候,最好选择长度N为2的n次幂,即N=2^n。因为FFT是采用“分治”(divide-and-conquer)思想实现的算法,层层二分显然是最好的分治,这样长度就需要是2的N次幂。现代的FFT算法也支持长度N为任意值,都可以得到正确的结果,只是速度上的快慢差别而已。最慢的情况是N是一个质数,这样算法无法进行任何的分解,好一点的情况是N是一个非质数,最好的情况是N是2的n次幂。比如我们用 Matlab(R2016a)做一个实验:

代码:

A=[1,2,3];

tic    

fft(A, 121000);

toc;

tic

fft(A, 121001);

toc;

tic

fft(A, 131072);

toc;

结果:

Elapsed time is 0.006575 seconds.

Elapsed time is 0.039950 seconds.

Elapsed time is 0.004747 seconds.

当N等于质数121001时,FFT的运行时间大概是121000时的6倍,而N取值131072(2^17)时算得最快。

一些性质

共轭对称

从FFT的公式可轻松推出,FFT变换后,第k个频点和第N-k个频点是共轭关系。这样,第k个频点的信息量完全等于第N-k个频点的信息量,因此在频域我们可以只处理差不多一半的频点,处理完毕后再利用共轭的性质把另一半恢复出来,减少了一半的计算量。但这个“差不多一半”不是精确的“N/2”,而是N/2+1。因为频点的取值范围是[0, N-1],0频点没有频点和它共轭,但必须把它算在信息里面。

相位信息

信号的相位信息,在经过FFT之后,通过 arctan(X) 反映出来,比如求这个信号的相位信息:

smallvalue = 1e-10;

fs = 1000;

N = 1000;

t = (0:N-1)/fs;

f=linspace(0,fs,N+1);

f1= 50;

y = cos(2*pi*f1*t+pi/4);

Y = fft(y);

Y(intersect(find(real(Y)< smallvalue), find(imag(Y)< smallvalue)))=0;

plot(f(1:N),angle(Y));

图片

图二 信号的相位信息

注意,如果FFT计算出的复数等于0的话,因为 Matlab 的计算精度问题,其实都是一些很小的值,比如实部 re = 1.05e-12,虚部 im = 3e-12。这些值对功率谱没什么影响,但取 arctan(im/re) 时却是一些很大的值,范围在[-Pi, Pi],这显然是不合理的。

所以我手动去掉了某些极小值。

Y(intersect(find(real(Y)

加窗

在实际应用中,对一段信号做FFT通常要先加窗,根本原因也是FFT隐藏的周期性。

比如分别对下图第一列中的两个信号求FFT,首先是做周期延拓,再求DFS。第一行的信号,周期延拓后正好是一个完美的连续函数,DFT完全不受影响,仍然只有原始信号的频率,其实就是一个单一频率。而第二行的信号,周期延拓后变成了一个不连续的函数,简单的说,也就是引入了其他频率分量,因此DFT后产生了原始信号没有的频率,这就叫频谱泄漏。

而加窗使得信号周期延拓后变得连续,减少了频谱泄漏。

图片

图3 频谱泄漏的产生

注意,如果正好是周期信号一个周期的延拓,那样是没有频谱泄漏的,理论上也不需要加窗。但实际工程应用中的信号过于复杂,不可能做到这一点,所以加窗就变成了一个标准操作。

加窗导致信号的能量发生了变化,想当于每个点乘以 sum_of_window / len_of_window,那么IFFT之后需要乘以 len_of_window / sum_of_window 把能量补偿回来。

线性卷积

一个线性时不变系统的输出就是输入信号和系统冲激响应的线性卷积。

线性卷积的公式是:

图片

可见,加入x1的长度是N1,x2的长度是N2,那么x3的长度就是N1+N2-1。

但是因为FFT隐含的周期性,FFT的时域卷积是周期信号的线性卷积。而周期信号一旦卷积起来,就好像是按照周期N循环一样,所以称为循环卷积。

线性卷积的快速解法:

  1. 选取 N>=(N1+N2-1);
  2. 计算两个序列 x1[n] 和 x2[n] 的N点FFT X1[k] 和 X2[k];
  3. 计算乘积 X3[k]=X1[k]*X2[k];
  4. 计算 X3[k] 的IFFT逆变换得到 x1[n] 和 x2[n] 的循环卷积,由于N足够大,其实等于线性卷积。

但还有一种情况是实时的线性卷积,这种情况很常见,比如实时录制的音频流卷积一个滤波器,再实时的输出处理后的信号。我们也可以利用FFT来节省计算资源,但显然音频流的长度是不可知的,也就无法通过上面的方式进行计算。

但可以通过如下途径来“分段”循环卷积。

简单说明一下:h是滤波器系数,假如它的长度是L,则定义FFT的长度N=2L,在h的后面补零。in_data是输入数据,out_data是输出数据。长度为N的输入数据需要两步才能处理完成,每一步都需要做长度为N的FFT/IFFT,之后,丢弃生成的前N/2长度的数据,保留后面N/2长度的数据到输出缓冲区中。所以若产生N长度的数据,需要做两次N长度的FFT/IFFT。具体过程请参考图示进行推导。

图片

图4 分段循环卷积

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FFT
    FFT
    +关注

    关注

    15

    文章

    434

    浏览量

    59276
  • 信号处理器
    +关注

    关注

    1

    文章

    250

    浏览量

    25240
  • 频谱仪
    +关注

    关注

    7

    文章

    339

    浏览量

    35962
  • 傅里叶变换
    +关注

    关注

    6

    文章

    437

    浏览量

    42547
  • DFS
    DFS
    +关注

    关注

    0

    文章

    26

    浏览量

    9147
收藏 人收藏

    评论

    相关推荐

    Vivado中快速傅里叶变换FFT IP的配置及应用

    快速傅里叶变换 (Fast Fourier Transform,FFT), 即利用计算机计算离散傅里叶变换(DFT)的高效、快速计算方法的统
    的头像 发表于 07-20 16:46 3902次阅读
    Vivado中<b class='flag-5'>快速</b><b class='flag-5'>傅里叶变换</b><b class='flag-5'>FFT</b> IP的配置及应用

    快速傅里叶变换FFT结果的物理意义

    本帖最后由 86hupeng 于 2012-11-28 09:03 编辑 FFT是离散傅立叶变换快速算法,可以将一个信号变换到频域。有些信号在时域上是很难看出什么特征的,但是如
    发表于 10-24 20:04

    【安富莱——DSP教程】第24章 快速傅里叶变换原理(FFT

    第24章快速傅里叶变换原理(FFT) 在数字信号处理中常常需要用到离散傅立叶变换(DFT),以获取信号的频域特征。尽管传统的DFT算法能够获取信号频域特征,但是算法计算量大,耗时长,不
    发表于 06-26 10:40

    第24章 快速傅里叶变换原理(FFT

    DFT被发现以来,在很长的一段时间内都不能被应用到实际的工程项目中,直到一种快速的离散傅立叶计算方法——FFT,被发现,离散是傅立叶变换才在实际的工程中得到广泛应用。需要强调的是,FFT
    发表于 09-27 08:09

    详解快速傅里叶变换FFT算法

    本帖最后由 richthoffen 于 2019-7-19 16:41 编辑 详解快速傅里叶变换FFT算法
    发表于 07-18 08:07

    详解快速傅里叶变换FFT算法

    详解快速傅里叶变换FFT算法
    发表于 03-28 11:48

    详解快速傅里叶变换FFT算法

    详解快速傅里叶变换FFT算法
    发表于 05-25 09:31

    快速傅里叶变换FFT算法及其应用

    快速傅里叶变换FFT算法及其应用
    发表于 05-28 09:13

    如何在iMX8X arm处理器上利用GPU加速运算快速傅里叶变换FFT

    傅里叶变换 FFT。本文所演示的ARM平台来自于Toradex Colibri iMX8X 计算机模块,此模块是 Toradex 基于 NXP iMX8 X 推出的紧凑型 Arm 核心板。iMX8X 具有
    发表于 12-28 07:15

    详解快速傅里叶变换FFT算法

    详解快速傅里叶变换FFT算法
    发表于 03-05 11:07

    详解快速傅里叶变换FFT算法

    快速傅里叶变换 FFT 是离散傅里叶变换 DFT 的一种快速算法,只有 FFT 才能在现实中有实
    发表于 01-15 16:24 0次下载

    快速傅里叶变换FFT的C程序代码实现

    本文为您讲解快速傅里叶变换FFT的C语言程序代码实现的具体方法,C编程需要解决的问题及FFT计算结果验证。
    发表于 10-08 16:38 6.1w次阅读
    <b class='flag-5'>快速</b><b class='flag-5'>傅里叶变换</b><b class='flag-5'>FFT</b>的C程序代码实现

    数字信号处理第4章-快速傅里叶变换(FFT)

    数字信号处理第4章-快速傅里叶变换(FFT)
    发表于 12-28 14:23 0次下载

    快速傅里叶变换FFT结果的物理意义的程序详细说明

    本文档的主要内容详细介绍的是快速傅里叶变换FFT结果的物理意义详细程序说明单片机keil C51/avr/dsp程序。
    发表于 07-15 17:39 14次下载
    <b class='flag-5'>快速</b><b class='flag-5'>傅里叶变换</b><b class='flag-5'>FFT</b>结果的物理意义的程序详细说明

    快速傅里叶变换-FFT分析仪基础知识

    FFT频谱分析仪的概念是围绕快速傅里叶变换建立的,该变换基于约瑟夫·傅里叶(Joseph Fourier,1768-1830)开发的傅里叶分析技术。例如,使用他的
    发表于 01-16 14:26 1100次阅读