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

基于C++任意点数的FFT/IFFT(时域和频域)实现

    函数说明:更改主函数体中的N和length(=log2(N))既可以实现任意点数(2的幂次)的FFT/ IFFT的实现,fft函数中flag标志位控制是正变换还是逆变换。


1.复数操作类

     定义复数类,重载复数四则运算符号,重载输出运算符,重载赋值运算符。

/**********预编译文件头文件complex.h********/
#include"iostream"
using namespace std;
class complex
{
	double real,image;
public:
	complex(){real=0;image=0;}
	complex(float i,float j){real=i;image=j;}
	double getr(){return real;}
	double geti(){return image;}
	void show()
	{
		if(image>=0)
			cout<<real<<"+"<<image<<"j"<<"   ";
		else
			cout<<real<<image<<"j"<<"   ";
	}
	void setvalue(double i=0,double j=0)
	{
		real=abs(i)<0.0001?0:i;
		image=abs(j)<0.0001?0:j;
	}
	complex operator +(complex&);
	complex operator-(complex&);
	complex operator*(complex&);
	complex operator /(int n);
	void operator+=(complex&);
	void operator =(complex&);
	friend complex W(int m,int n, int flag);
};
complex complex::operator +(complex& c)
	{
		complex t;
		t.real=real+c.real;
		t.image=image+c.image;
		return t;
	}
complex complex::operator*(complex& c)
	{
		complex t;
		t.real=real*c.real-image*c.image ;
		t.image=real*c.image+image*c.real;
		return t;

	}
complex complex::operator/ (int n)
	{
		complex temp;
		temp.real=real/n;
		temp.image=image/n;
		return temp;
	 }
complex complex::operator -(complex& c)
	{
		complex t;
		t.real=real-c.real;
		t.image=image-c.image;
		return t;
	}
void complex::operator+=(complex&c)
	{
		real=real+c.real;
		image=image+c.image;
	}
void complex::operator =(complex&c)
	{
		real=abs(c.real)<0.00001?0:(c.real);
		image=abs(c.image)<0.00001?0:(c.image);
	}


2.主函数

/*******************主函数体***********************/
#include "stdafx.h"
#include"iostream"
#include"cmath"
#include"complex.h"
#define pi 3.141592657
#define N 16//需要运算的fft的点数
#define length 4//存储需要的二进制位,即length=log2(N)
using namespace std;
/*********************重新排列输入序列函数****************************/
void bit_reversal(complex a[],int n)
{
	int bitdesicion(unsigned);//用来重现排序原来的输入信号序列应该对应变换的信号的序号
	complex temp;
	int j;
	for(int i=0;i<n;i++)
	{
		j=(int)bitdesicion(i);
		if(i<j){temp=a[i];a[i]=a[j];a[j]=temp;}
	}
}
int bitdesicion(unsigned n)
{
    int j=0;
	double k;
	double result=0;
	int bit[length]={0};
	while(n){bit[j]=n%2;n=n/2;j++;}//将n分解成进制码存储于int指针类型bit中
	j=0;
	while(j<length)
	{k=length-1-j;result=result+bit[j]*pow(2.0,k);j++;}
     return (int)result;
}

/*********************显示信号数组的元素的函数*********************************/
void play(complex a[],int len)
{
	for(int i=0;i<len;i++)
	{
		a[i].show();
		if((i+1)%4==0) cout<<"  "<<endl;
	}
   cout<<'\n'<<endl;
}

/************获得加权系数W,flag标记为正变换或者逆变换系数*******************/
void getW(complex w[],int len,int flag)
{
	if(flag)
	for(int i=0 ; i<len ; i++ )
			w[i].setvalue(cos(pi*2*i/len),-sin(pi*2*i/len));
	else
	for(int j=0 ; j<len ; j++ )
			w[j].setvalue(cos(pi*2*j/len),sin(pi*2*j/len) );
}
/****************************基2时域FFT算法***********************************/
void fft_temporal(complex input[],int len,int flag)
{
	int i,j;int L,k;
	void bit_reversal(complex a[],int);
	bit_reversal(input,len);//len 代表输入数据的长度
	cout<<"重新排序后输入信号为:"<<endl;play(input,len);
	complex* w=new complex[len];getW(w,len,flag);//获得快速傅里叶的系数,flag为标志位,代表获得正变换系数,代表获得逆变换系数
	if(flag)
	    cout<<"FFT系数如下"<<endl;
	else 
		cout<<"IFFT系数如下"<<endl;
    play(w,len);
	complex* tempdata=new complex[len];
	complex* tempw=new complex[len/2];

/*********************最核心--蝶形算法**************************************/
for(i=1;i<=length;i++)//i代表第i级蝶形,length表示log2(N)
	{		
		L=(int)pow(2.0,i);
		for(j=0;j<len;j+=L)//L为相应单个蝶形运算包含的节点数也是每组蝶形运算的间隔数
		{ 
			for(k=0;k<L/2;k++)  
				tempw[k]=w[k*len/L]*input[j+L/2+k]; //傅里叶加权系数和对应输入信号的乘积事先准备好
			for(k=0;k<L/2;k++)//L/2将每一个蝶形算法依据是加还是减够成两个部分,每个部分是蝶形点间隔数的一半
			{
				tempdata[j+k]=input[j+k]+tempw[k];
			    tempdata[j+L/2+k]=input[j+k]-tempw[k];
			} 
		}
	       for(j=0;j<len;j++) input[j]=tempdata[j];
	 }
 	if(!flag) for(j=0;j<len;j++) input[j]=tempdata[j]/len;//逆变换必须乘加权系数/N才能得到正确的结果
        delete[]w;
        delete[]tempw;
	delete[]tempdata;
}

/**************************************基2频域FFT算法***********************************/
void fft_frequency(complex input[],int len,int flag)
{
	int i,j;int L,k;
	void bit_reversal(complex a[],int);
	complex* w=new complex[len];getW(w,len,flag);//获得快速傅里叶的系数,flag为标志位,代表获得正变换系数,代表逆变换
	complex* tempdata=new complex[len];
	if(flag)
	    cout<<"FFT系数如下"<<endl;
	else 
		cout<<"IFFT系数如下"<<endl;
    play(w,len);
/********************************最核心--蝶形算法*****************************************/
for(i=1;i<=length;i++)//i代表第i级蝶形,length表示log2(N)
	{		
		L=(int)pow(2.0,length+1-i);
		for(j=0;j<len;j+=L)//L为相应单个蝶形运算包含的节点数也是每组蝶形运算的间隔数
		{ 
			for(k=0;k<L/2;k++)//L/2将每一个蝶形算法依据是加还是减够成两个部分,每个部分是蝶形点间隔数的一半
			{
				tempdata[j+k]=input[j+k]+input[j+L/2+k];
			    tempdata[j+L/2+k]=w[k*len/L]*(input[j+k]-input[j+L/2+k]);
			}
		    for(k=0;k<len;k++) input[k]=tempdata[k];
		}
	 }
 	if(!flag) for(j=0;j<len;j++) input[j]=input[j]/len;//逆变换必须乘加权系数/N才能得到正确的结果
	bit_reversal(input,len);//len 代表输入数据的长度,频率的FFT在最后要重新排序
    delete[]w;delete[]tempdata;
}

/************************主函数********************************************/
int _tmain(int argc, _TCHAR* argv[])
{
/***********************函数声明*****************************/
   void play(complex a[],int);//显示整个数组<pre name="code" class="cpp">   void getW(complex w[],int len,int flag);//获得正变换(flag=1)或者逆变换系数(flag=0)
   void fft_temporal(complex input[],int len,int flag);//基时间的fft,flag控制为正变换或者逆变换
   void fft_frequency(complex input[],int len,int flag);//基频率的fft
/************************************************************/
   complex input[N];
   complex output[N];
   for(int i=0;i<N;i++)  input[i].setvalue(i,0);
   cout<<"输入信号为:"<<endl;play(input,N);
   fft_temporal(input,N,1);//"1控制为正变换"
   cout<<"基2时域FFT输出信号为:"<<endl;play(input,N);
   for(int j=0;j<N;j++) 
      output[j]=input[j];
   fft_temporal(output,N,0);//"0"控制为逆变换
   cout<<"基2时域IFFT输出信号为:"<<endl;play(output,N);
   fft_frequency(output,N,1);
   cout<<"基2频率FFT输出信号为:"<<endl;play(output,N);
   fft_frequency(output,N,0);
   cout<<"基2频率IFFT输出信号为:"<<endl;play(output,N);
   return 0;
}

 
 





转载于:https://www.cnblogs.com/engineerLF/p/5393172.html

相关文章:

  • 第 19 章 Class
  • 双击防止网页放大缩小HTML5
  • 多种方式求阶乘
  • 开发android App干坏事(二)-wifi控制
  • Net Core中数据库事务隔离详解——以Dapper和Mysql为例
  • FFmpeg常用基本命令
  • java异常——RuntimeException和User Define Exception
  • 判断图片url是否存在图片
  • 【从业余项目中学习1】C# 实现XML存储用户名密码(MD5加密)
  • 利用jquery和jsonp来获取跨站数据,并实现cookie共享
  • BIND+DLZ智能解析系统
  • 100万并发连接服务器笔记之Java Netty处理1M连接会怎么样
  • 去掉JAVA部分依赖的事例
  • JPPF并行计算框架类加载机制研究
  • ASP.NET MVC 5 -从控制器访问数据模型
  • 【108天】Java——《Head First Java》笔记(第1-4章)
  • 10个最佳ES6特性 ES7与ES8的特性
  • co模块的前端实现
  • mac修复ab及siege安装
  • 不用申请服务号就可以开发微信支付/支付宝/QQ钱包支付!附:直接可用的代码+demo...
  • 测试开发系类之接口自动化测试
  • 动态规划入门(以爬楼梯为例)
  • 跨域
  • 融云开发漫谈:你是否了解Go语言并发编程的第一要义?
  • 通信类
  • 问:在指定的JSON数据中(最外层是数组)根据指定条件拿到匹配到的结果
  • 项目管理碎碎念系列之一:干系人管理
  • 长三角G60科创走廊智能驾驶产业联盟揭牌成立,近80家企业助力智能驾驶行业发展 ...
  • 新海诚画集[秒速5センチメートル:樱花抄·春]
  • #define
  • #常见电池型号介绍 常见电池尺寸是多少【详解】
  • #免费 苹果M系芯片Macbook电脑MacOS使用Bash脚本写入(读写)NTFS硬盘教程
  • #预处理和函数的对比以及条件编译
  • $HTTP_POST_VARS['']和$_POST['']的区别
  • (6)STL算法之转换
  • (pytorch进阶之路)CLIP模型 实现图像多模态检索任务
  • (Redis使用系列) Springboot 使用Redis+Session实现Session共享 ,简单的单点登录 五
  • (差分)胡桃爱原石
  • (附源码)计算机毕业设计ssm电影分享网站
  • (黑马出品_高级篇_01)SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式
  • (介绍与使用)物联网NodeMCUESP8266(ESP-12F)连接新版onenet mqtt协议实现上传数据(温湿度)和下发指令(控制LED灯)
  • (一)认识微服务
  • (转)Java socket中关闭IO流后,发生什么事?(以关闭输出流为例) .
  • (转)微软牛津计划介绍——屌爆了的自然数据处理解决方案(人脸/语音识别,计算机视觉与语言理解)...
  • .NET CORE 2.0发布后没有 VIEWS视图页面文件
  • .NET6实现破解Modbus poll点表配置文件
  • .NET简谈互操作(五:基础知识之Dynamic平台调用)
  • .net流程开发平台的一些难点(1)
  • .NET企业级应用架构设计系列之结尾篇
  • .NET与java的MVC模式(2):struts2核心工作流程与原理
  • /etc/apt/sources.list 和 /etc/apt/sources.list.d
  • [.NET 即时通信SignalR] 认识SignalR (一)
  • [AI]文心一言爆火的同时,ChatGPT带来了这么多的开源项目你了解吗
  • [BZOJ 3680]吊打XXX(模拟退火)
  • [caffe(二)]Python加载训练caffe模型并进行测试1