FFT算法实现

2023-11-03

关于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;//虚部置0
   		Mag[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;
        }
}

 


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FFT算法实现 的相关文章

随机推荐

  • uniapp swiper轮播图片+视频

    1 效果 2 代码展示
  • Java高并发- 锁的优化及 JVM 对锁优化所做的努力

    在高并发环境下 激烈的锁竞争会导致程序的性能下降 所以我们有必要讨论一下有关 锁 的性能问题及注意事项 如 避免死锁 减小锁粒度 锁分离等 一 锁优化 1 1 减小锁持有时间 在锁竞争过程中 单个线程对锁的持有时间与系统性能有着直接的关系
  • docker安装golang

    这里写目录标题 下载golang的Docker镜像 使用Golang镜像 下载golang的Docker镜像 docker search golang 查询Golang的镜像信息 选择使用第一个 执行命令 docker pull docke
  • [Android]ProgressBar进度条

    ProgressBar ProgressBar是进度条控件 ProgressBar的应用场景很多 比如用户登录时 后台发送请求 以及进行等待服务器返回信息等一些比较耗时的操作 这个时候如果没有提示 用户可能会以为程序崩溃了或手机死机了 会大
  • C++容器篇,list容器

    C 容器篇 list容器 1 list的介绍和使用 1 1 list的介绍 list的参考文档 list是C 的容器之一 其本质是双向链表 它是可以在常数时间复杂度内进行插入和删除的序列式容器 list和forword list非常相似 其
  • stm32实现json格式传输/ cjson使用

    cjson是一个开源的C文件 可以实现用C语言生成json格式数据 目录 步骤1 准备工作 步骤2 cjson函数简单讲解 步骤3 一个例子 生成json格式数据 步骤1 准备工作 在keil里添加cjson c和cjson h cjson
  • linux下生成高强度密码的四大神器

    导读 安全是一个大的话题 给服务器设置一个高强度的密码是非常重要的 你可能会疑惑一个高强度的密码究竟是什么样的呢 怎么才能生成一个那样的密码呢 不用担心下面我们将介绍 4 种简单方法让你在 Linux 中生成一个高强度密码 1 在 Linu
  • CentOS 6和CentOS 7的磁盘空间清理

    收集整理了一些在CentOS 6或者CentOS 7服务器中 快速清理磁盘空间的方法 首先 必须先安装yum utils工具组件 yum y install yum utils 1 删除日志文件 find var name log size
  • Struts2+Spring3+Mybatis3开发环境搭建

    本文主要介绍Struts2 Spring3 Mybatis3开发环境搭建 Struts和Spring不过多介绍 MyBatis 是支持普通 SQL 查询 存储过程和高级映射的优秀持久层框架 MyBatis 消除了几乎所有的 JDBC 代码和
  • [开源之美] nanomsg -- 进程间通讯

    认识 nanomsg 这个项目 源于项目内部分享 实际分析和使用一段时间之后 确实觉得项目beautiful 先附上Git地址 nanomsg Git下载地址 nanomsg 的编译 编译很简单 没有其他第三方依赖 根据Git上编译文档可以
  • linux 格式化含义,RMAN备份FORMAT格式中%a的含义

    Oracle文档对 a的描述是 a Specifies the activation IDofthedatabase rman备份并保存 查询 a RMAN gt backup tablespace users format home or
  • Unity使用NavmeshObstacle解决多人寻路终点堵塞问题以及解决NavmeshObstacle打开抖动(瞬移)问题

    不知道为什么 就这个东西 国内各大论坛和网站就是搜不到 最终还是得谷歌 太过基础的就不讲了 问题一 在unity使用navmeshAgent进行多人寻路设置同一个终点后 所有角色都会向对应位置寻路 当前面单位到达后后面单位会一直无法到达导致
  • kiki's game

    http acm hdu edu cn showproblem php pid 2147 Problem Description Recently kiki has nothing to do While she is bored an i
  • Python 全栈系列217 Nginx负载均衡MongoAgent

    说明 虽然不想在完成量化系统的构建前再去分叉搞别的东西 但是在批量计算指标时需要频繁的使用MongoAgent 而这个服务只能做成单线程异步的 所以计算60万次指标需要2 3天时间 考虑到之后可能会有重刷的情况 所以我想还是给MongoAg
  • 被监督写博客-Day7

    今天在ctftime上找了比赛 但是吧 不太行 只能等着明天结束后的wp了 回归刷题日常 题目一 极客大挑战 2019 HardSQL 说真的 真的不喜欢SQL注入的题 打开题目后又是熟悉的界面 看了wp说是报错注入 学习一下两个函数 up
  • jmeter windows 安装指导

    软件安装 Windows安装 软件下载 进入官网 http jmeter apache org 直接下载zip包 下载后直接解压 eg我的解压路径如下 D Program Files apache jmeter 5 5 bin jdk安装
  • 用C++进行设计模式解析和实现

    http c chinaitlab com special sjms Index html 用C 进行设计模式解析和实现
  • 【精】HDFS的HA系列(一)--- 背景、架构

    本文作为HDFS HA系列的第一篇文章 主要简单描述一下HDFS HA的产生背景和整体架构 同时也会对后续系列文章要讲解的内容列出一个大致提纲 一 Hadoop HA背景 单点故障 英语 single point of failure 缩写
  • RabbitMQ快速实战与集群架构详解

    RabbitMQ 1 MQ介绍 1 1 什么是MQ 为什么要用MQ 1 2 MQ的优缺点 1 3 几大MQ产品特点比较 2 Rabbitmq安装 2 1 实验环境 2 2 版本选择 2 3 安装Erlang语言包 2 4 安装RabbitM
  • FFT算法实现

    关于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