FFT算法实现

article/2025/10/18 22:30:39

关于FFT算法的原理这里就不多说了,具体参考有关书籍。

DFT与FFT运算量的比较

N点DFT的运算量

 

复数乘法

复数加法

一个X(k)

N

N-1

N个X(k)(N点DFT)

N*N

N(N-1)

 

N点FFT的运算量

 

复数乘法

复数加法

N个X(k)

(N/2)*log2N

N*log2N

 

如何用计算机程序实现FFT呢

参考《数字信号处理》(西电版)P115的蝶形运算公式,可以推导出用计算机程序实现的公式。由于word中输入公式太麻烦了,这里先将推导过程写在纸上,然后拍照上传到这里。



 根据上面的推导结果,就可以用程序来实现FFT了。看下面的例程。

#include "math.h"
#define PI	3.14159
#define N   128//real:实数
//imaginary:虚数
#pragma DATA_SECTION(Input,"ExRamMem");//这是DSP处理器(CCSv4开发环境)中的一种操作内存的方法
int Input[N] = {0.0};//用于存放待处理数据
#pragma DATA_SECTION(SinTab,"ExRamMem");
float SinTab[N] = {0.0};//用于FFT运算的正弦表
#pragma DATA_SECTION(CosTab,"ExRamMem");
float CosTab[N] = {0.0};//用于FFT运算的余弦表
#pragma DATA_SECTION(Real,"ExRamMem");
float Real[N] = {0.0};//待处理数据的实部
#pragma DATA_SECTION(Imag,"ExRamMem");
float Imag[N] = {0.0};//待处理数据的虚部
#pragma DATA_SECTION(Mag,"ExRamMem");
float Mag[N] = {0.0};//FFT的幅度谱//函数功能:生成一个正弦波信号
void GenSin(void)
{int i;for ( i=0;i<N;i++ ){INPUT[i]=sin(PI*2*i/N*3)*1024;}
}//函数功能:计算用于FFT运算的正、余弦表。
//(me)注意:旋转因子和正、余弦表不是同一个概念。
void TwiddleCmpt(void)
{int i;for ( i=0; i<N; i++ ){SinTab[i] = sin(PI*2*i/N);CosTab[i] = cos(PI*2*i/N);}
}//输入参数:real:待处理的数据的实部
//		  imag:待处理的数据的虚部
//返回参数:暂时就返回OK
//函数功能:计算实部real和虚部imag的N点FFT。
//注意:因为FFT的运算为了节约内存,而将下一级的运算结果直接覆盖上一级,所以下面的程序中要采取temp_R、temp_I、temp_R_kb暂时存放一下。
int FFT(float real[N],float imag[N])
{//调试发现:定义long型变量与定义int型变量时的计算速度居然不一样,定义long型变量的计算速度要慢一点,即使是参与运算的相关变量都是long型的。但是没办法当FFT点数较大时,int型变量的范围是不够用的。long i,j=0,k,b,p,Nv2,Nm1,bm1,bx2;	//Nv2表示N/2,Nm2表示N-1,bm1表示b-1,bx2表示b乘2,PIx2表示PI乘2,定义这五个数是为了减少运算时间。float temp,temp_R,temp_I,temp_R_kb;long L,M;//	f=N;
//	for(m=1;(f=f/2)!=1;m++)		//判断N是否能够被2整除,判断N是2的几次幂。
//	{}Nv2=N/2;Nm1=N-1;M=log(N)/log(2);//这里的倒序采用雷德算法。//=================== following code invert sequence ===================for(i=0; i<Nm1; i++){if(i < j){temp = real[j];real[j] = real[i];real[i] = temp;}k = Nv2;while(k <= j){j = j - k;k = k/2;}j = j + k;}//===================following code FFT ===================for (L=1; L<=M; L++ )//for(1):控制运算级数{b = 1;i = L - 1;while (i > 0){b=b*2; i--;}	// b= 2^(L-1),蝶尖距bm1 = b-1;	//在进行第二层循环前,先将bm1和bx2算出来。bx2 = b*2;for (j=0; j<=bm1; j++ )//for(2):同一级中的蝶群数。{p=1; i=M-L;while (i > 0){p = p*2; i--;}p = p*j;	// p=pow(2,M-L)*j;for (k=j; k<N; k=k+bx2)//for(3):一个蝶群中有多少只蝴蝶{temp_R = real[k]; temp_I = imag[k]; temp_R_kb = real[k+b];real[k]  = real[k] + real[k+b] * CosTab[p] + imag[k+b] * SinTab[p];imag[k]  = imag[k] - real[k+b] * SinTab[p] + real[k+b] * CosTab[p];real[k+b]= temp_R  - real[k+b] * CosTab[p] - real[k+b] * SinTab[p];	//因为此时的real[k]已被上一条语句覆盖,但这里还是想用之前的real[k],所以才事先将real[k]存储在temp_R中,temp_I和temp_R_kb与此类似。imag[k+b]= temp_I  + temp_R_kb * SinTab[p] - real[k+b] * CosTab[p];} // END for (3) } // END for (2) } // END for (1) for ( i=0; i<Nv2; i++ )//计算幅度谱{Mag[i] = sqrt(real[i] * real[i] + imag[i] * imag[i]);//FFT的输出是由实部和虚部组成,要想看频谱,还求实部和虚部平方和再开根号,这样得到就才是幅度谱。}asm("	NOP");return(OK);
}int fft(void)
{Uint16 	i;GenSin();TwiddleCmpt();for(i=0; i<N; i++){Real[i] = Input[i];//把采集到的N个数据付给FFT的实部。Imag[i] = 0.0;//虚部置0Mag[i] = 0.0;//幅度置0}FFT(Real, Imag);return(OK);
}

正弦波生成函数GenSin()生成波形如下

经过fft处理后得到的幅度谱如下

注意:

1.  这里得到的幅度谱,其横坐标只是下标值,若想将横坐标转换为频率,还需要进行计算,公式是:f=n*Fs/N,其中n是对应处理结果Mag的下标值,Fs是采样率,N是fft点数,f即是n点对应的频率。

2.  如下图这个处理结果,给人的感觉是只有Mag[3]的值较大,其他都是0,其实有很多点的值不是等于0的,只是他们的值相对Mag[3]太小,所以显得他们是0。

3.  这里的信号源是交流信号,即不含直流分量,所Mag的第0点的值是0。而一般情况下AD的采样结果都是正值,也就是采样信号中会含有直流分量,这时候在第0点也会有值,只不过该点对应的频率是0。

CCSv4软件自带的频谱分析工具分析的fft处理结果如下


关于倒序

以N=128(2^7)为例,给出倒序前后的序号。

倒序前序号

倒序后序号

十进制

二进制

二进制

十进制

0

000 0 000

000 0 000

0

1

000 0 001

100 0 000

64

2

000 0 010

010 0 000

32

3

000 0 011

110 0 000

96

4

000 0 100

001 0 000

16

……

……

……

……

126

111 1 110

011 1 111

63

127

111 1 111

111 1 111

127

 

倒序除了上面的雷德算法也外,可以采用下面这种更为直接的方法进行,不过这种方法的效率显然没有雷德算法高。

{int x0,x1,x2,x3,x4,x5,x6,xx;//倒序//=================== following code invert sequence ===================//for(i=0; i<128; i++){x0=x1=x2=x3=x4=x5=x6=0;x0=i&0x01; x1=(i/2)&0x01; x2=(i/4)&0x01; x3=(i/8)&0x01;x4=(i/16)&0x01; x5=(i/32)&0x01; x6=(i/64)&0x01;xx=x0*64+x1*32+x2*16+x3*8+x4*4+x5*2+x6;imag[xx] = real[i];}for(i=0; i<128; i++ ){real[i] = imag[i];imag[i] = 0;}
}

 



http://chatgpt.dhexx.cn/article/2tZ8ZlkV.shtml

相关文章

使用python手写FFT算法

FFT(Fast Fourier Transform) 是 DFT(Discrete Fourier Transform)的快读实现&#xff0c;它在机理上没有改变DFT的算法&#xff0c;只是在实现上采用的巧妙的实现。 使 O ( N 2 ) O(N^2) O(N2)的实现变成了 O ( N l o g 2 N ) O(Nlog_2N) O(Nlog2​N)的实现&#xff0c;优化算…

C语言实现FFT算法

C语言实现FFT算法 fft1d.c和fft1d.h见https://download.csdn.net/download/weixin_43216875/12009644 1 fft1d.h #ifndef FFT1D_H #define FFT1D_H#include "math.h"#define PI 3.1415926535897932384626433832795028841971typedef struct complex //复数类型 {flo…

Matlab实现DITFFT算法

这段时间刚好在学习数字信号处理的快速傅立叶变换&#xff0c;也刚好应着老师布置的作业用matlab实现N点的FFT。 方法也是采用教科书上的DITFFT&#xff0c;当然关键也就是分治的思想&#xff0c;分成奇偶序列&#xff0c;再观察旋转因子和步长的不同来编写算法 该算法首先的部…

FFT算法的C语言实现

FFT算法的C语言实现 &#xff1a;数字信号处理 需要注意的几个点 #mermaid-svg-Q0Cv61uzu3GVxhM0 .label{font-family:trebuchet ms, verdana, arial;font-family:var(--mermaid-font-family);fill:#333;color:#333}#mermaid-svg-Q0Cv61uzu3GVxhM0 .label text{fill:#333}#mer…

优雅的FFT算法

简 介&#xff1a; 利用FFT算法实现快速傅里叶变换&#xff0c; 在理论、工程中具有非常广泛的应用。 除了能够在合适的计算平台完成FFT算法&#xff0c;同时还需要注意到它在频谱分析中可能带来的频率混叠以及频率泄露等问题。 关键词&#xff1a; FFT&#xff0c;算法实现 #m…

STM32 FFT算法实现

DSP 库运行环境搭建 在 MDK 里面搭建 STM32F4 的 DSP 运行环境(使用.lib 方式)是很简单的&#xff0c;分为 3 个步骤&#xff1a; 1&#xff0c; 添加文件。 首先&#xff0c;我们在例程工程目录下新建&#xff1a;DSP_LIB 文件夹&#xff0c;存放我们将要添加的文件&#xff…

FFT算法解析

问题描述 两个n次多项式相乘,其时间复杂度为 O(n2) ,通过FFT来减小其问题的复杂度。 分析过程 FFT的基本思路是:我知道一个多项式表达式可以根据其表达式算出结果,同理我们也可以根据其结果算出表达式。对于A,B两个n次多项式,一共所有又2n+1个参数需要求解,我们至少需要…

FFT算法再学以及终于理解

前言 人生如逆旅&#xff0c;我亦是行人。 一、FFT FFT&#xff08;Fast Fourier Transformation&#xff09;&#xff0c;中文名快速傅里叶变换&#xff0c;用来 加速多项式乘法 &#xff0c;就是用来降低算法的时间复杂度的&#xff0c;将时间复杂度由原来的 O(n^2) 变为了O…

十分简明易懂的FFT(快速傅里叶变换)

FFT前言 快速傅里叶变换 (fast Fourier transform),即利用计算机计算离散傅里叶变换&#xff08;DFT)的高效、快速计算方法的统称&#xff0c;简称FFT。快速傅里叶变换是1965年由J.W.库利和T.W.图基提出的。采用这种算法能使计算机计算离散傅里叶变换所需要的乘法次数大为减少&…

第四章快速傅里叶变换FFT

一、基2FFT算法 1.直接计算DFT的特点 对于N点DFT的乘法和加法运算次数均为N^2(运算量较大)减少运算量的基本途径&#xff1a;将N点DFT分解成多个较短的DFT旋转因子具有 周期性&#xff1a; 对称性&#xff1a;或又或者 2.时域抽取法基2FFT基本原理 分类&#xff1a;基2FFT分…

数学专题小结:FFT算法

快速傅里叶变换(FFT,Fast Fourier Transform)是信号处理的常用手段,可以把时域信号变成频域信号,时域的卷积运算对应于频域就成了简单的乘法运算。由于两个多项式的乘积,其系数的运算实际上也是一种卷积运算,因此可以用FFT来计算多项式的乘法。网上关于FFT算法的讲解大多…

转:fft算法(快速傅里叶变换算法)

FFT (Fast Fourier Transform) 是一种快速傅里叶变换算法。它是用来将一个信号从时域转换到频域的算法。这个算法通过分治策略&#xff0c;将一个长度为 N 的复数序列分解成 N/2 个长度为 2 的复数序列&#xff0c;然后对这些小的序列分别进行 FFT 计算。 最简单的 FFT 算法是暴…

快速傅里叶变换(FFT)算法学习

前言 人生如逆旅&#xff0c;我亦是行人。 一、介绍 算法的世界多么广大&#xff0c;我们可以将算法大致分为两类&#xff1a; 第一类是较为有用的算法&#xff1a;比如一些经典的图算法&#xff0c;像 DFS 和 BFS&#xff08;深度 / 广度优先算法&#xff09;&#xff0c;这些…

FFT算法讲解——麻麻我终于会FFT了!

FFT——快速傅里叶变换 这块不写东西空荡荡的&#xff0c;我决定还是把FFT的定义给贴上吧 FFT&#xff08;Fast Fourier Transformation&#xff09;是离散傅氏变换&#xff08;DFT&#xff09;的快速算法。即为快速傅氏变换。它是根据离散傅氏变换的奇、偶、虚、实等特性&…

怎么计算网站流量?

如何计算网站的流量呢&#xff1f;在这华仔给大家分享一个如何计算流量的算法&#xff1a; 举个栗子&#xff1a;1G1024M&#xff0c;10G就是101024M10240M. 一个1M的文件被下载1000次的流量约为1G;被下载10000次的流量约为10G. 假如你每月的网站流量为10G&#xff0c;那10G的流…

CDN流量是什么,怎么计算?

CDN流量通俗来讲就是使用CDN加速时&#xff0c;网络加速会产生一个数据使用量&#xff0c;到达某一个时段&#xff0c;统计出这个时段使用的量&#xff0c;也就是CDN流量&#xff0c;和网站流量的使用很像。 随着互联网的发展&#xff0c;用户在使用网络时对网站的浏览速度和…

流量计算器

为所做的工作处于初始开发的阶段&#xff0c;所以数据一直在变化&#xff0c;导致1s的流量大小一直也在变化。每次都需要手动根据新的参数进行计算&#xff0c;真的好烦。 所以呢&#xff0c;作为一个程序员&#xff0c;能让程序做的事情&#xff0c;自己就不要动手了呀&#x…

Flink1.14相关-3.数据流量计算

1. 前言 使用环境 Flink1.14.6Centos7.9Java8 Flink1.14.6安装部署测试参考&#xff1a;参考链接 2 .数据采集 2.1 信号监听 需要监听文件夹下的新文件产生&#xff0c;并且数据库中的值未更新时才发送消息通知后续模块开始采集数据。【后面需要重新搭建监听部分和判断部分…

适应多场景的客流量统计-人流量统计算法

在商场、展厅、景区等受人流量影响较大的场所&#xff0c;流量统计算法可以快速获取流量数据和动态趋势&#xff0c;辅助评估店铺和部分活动的效果&#xff0c;帮助商业决策。另外&#xff0c;在地铁站、火车站、机场等公共场所。实时检测人数可以及时预警高密度人群&#xff0…

网站的服务器带宽计算,服务器带宽和流量计算方式

服务器带宽和流量计算方式。网站流量和带宽该怎么计算&#xff0c;给一些参照数据信息&#xff0c;由于不清楚流量和带宽是怎么计算的&#xff0c;因此不清楚用多宽的带宽更有效、更节省资产! 网站服务器上最好是安装流量统计手机软件(强烈推荐应用DUMeter)&#xff0c;假如流量…