文章目录

(一)FFT的基本原理
(二)FFT代码
(三)使用典型函数进行测试

(一)FFT的基本原理

  • FFT的总思路

      第一步,将长序列DFT分解成短序列的DFT(本来是N点的DFT,被分解成两个 N/2 的DFT)第二步,分别将 N/2 的DFT分解成 N/4 的DFT第三步,继续分。。。最后被分成 2点 的DFT
    
  • 注意事项

      只要开始的序列长度是2的正整数次方,就可以最终被分解成2点的DFT分解原则是:对输入进行偶奇分解,对输出进行前后分解(关于偶奇分解可以看上一篇雷德算法)
    
  • 前后分解

  • 蝶形运算(可以体现出偶奇分解和前后分解)

(二)FFT代码

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define N 1024
#define PI 3.1415/*复数结构体类型*/
typedef struct{double realPart;
double imaginaryPart;
}complexNumber;complexNumber x[N], W[N/2]; //序列数组以及旋转因子数组int size_x=0;               //输入序列的长度,只能为2的次幂
void fastFourierOperation();//快速傅里叶变换算法
void initRotationFactor();  //生成旋转因子数组
void changePosition();      //偶奇变换算法
void outputArray();         //遍历输出数组
void add(complexNumber ,complexNumber ,complexNumber*); //复数加法
void mul(complexNumber ,complexNumber ,complexNumber*); //复数乘法
void sub(complexNumber ,complexNumber ,complexNumber*); //复数减法 int main()
{printf("请输入序列的长度:");              //输入序列的大小scanf("%d",&size_x);printf("\n请分别输入序列的实部和虚部\n");  //输入序列的实部和虚部for(int i=0;i<size_x;i++){printf("请输入第%d个序列的实部:",i);scanf("%lf",&x[i].realPart);printf("请输入第%d个序列的虚部:",i);scanf("%lf",&x[i].imaginaryPart);}printf("\n输出原序列:\n");outputArray();initRotationFactor();  //生成旋转因子数组 fastFourierOperation();//调用快速傅里叶变换printf("\n输出FFT后的结果:\n");outputArray();         //遍历输出数组return 0;
}/*快速傅里叶变换*/
void fastFourierOperation()
{int l=0;complexNumber up,down,product;changePosition();                  //偶奇变换算法for(int i=0;i<size_x/2;i++)        //一级蝶形运算{   l=1<<i;for(int j=0;j<size_x;j+= 2*l ) //一组蝶形运算{            for(int k=0;k<l;k++)       //一个蝶形运算{       mul(x[j+k+l],W[size_x*k/2/l],&product);add(x[j+k],product,&up);sub(x[j+k],product,&down);x[j+k]=up;x[j+k+l]=down;}}}
}/*生成旋转因子数组*/
void initRotationFactor()
{for(int i=0;i<size_x/2;i++){W[i].realPart=cos(2*PI/size_x*i);//用欧拉公式计算旋转因子W[i].imaginaryPart=-1*sin(2*PI/size_x*i);}
}/*偶奇变换算法*/
void changePosition()
{int j=0,k;//待会儿进行运算时需要用到的变量 complexNumber temp;for (int i=0;i<size_x-1;i++) { if(i<j) {//若倒序数大于顺序数,进行变址(换位);否则不变,防止重复交换,变回原数temp=x[i];x[i]=x[j];x[j]=temp;}k=size_x/2;    //判断j的最高位是否为0while(j>=k) {              //最高位为1j=j-k;k=k/2;}j=j+k;        //最高位为0}printf("\n输出倒序后的结果:\n");outputArray();
}/*遍历输出数组*/
void outputArray()
{for(int i=0;i<size_x;i++){if(x[i].imaginaryPart<0){printf("%.4f-j%.4f\n",x[i].realPart,abs(x[i].imaginaryPart));}else{printf("%.4f+j%.4f\n",x[i].realPart,x[i].imaginaryPart);}}
}/*复数加法的定义*/
void add(complexNumber a,complexNumber b,complexNumber *c)
{c->realPart=a.realPart+b.realPart;c->imaginaryPart=a.imaginaryPart+b.imaginaryPart;
}/*复数乘法的定义*/
void mul(complexNumber a,complexNumber b,complexNumber *c)
{c->realPart=a.realPart*b.realPart - a.imaginaryPart*b.imaginaryPart;c->imaginaryPart=a.realPart*b.imaginaryPart + a.imaginaryPart*b.realPart;
}/*复数减法的定义*/
void sub(complexNumber a,complexNumber b,complexNumber *c)
{c->realPart=a.realPart-b.realPart;c->imaginaryPart=a.imaginaryPart-b.imaginaryPart;
}

(三)使用典型函数进行测试

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define N 8 /*复数结构体类型*/
typedef struct{double realPart;
double imaginaryPart;
}complexNumber;complexNumber x[N], W[N/2]; //序列数组以及旋转因子数组
int size_x=N;
double PI=atan(1)*4;        //圆周率
void fastFourierOperation();//快速傅里叶变换算法
void initRotationFactor();  //生成旋转因子数组
void changePosition();      //偶奇变换算法
void outputArray();         //遍历输出数组
void add(complexNumber ,complexNumber ,complexNumber*); //复数加法
void mul(complexNumber ,complexNumber ,complexNumber*); //复数乘法
void sub(complexNumber ,complexNumber ,complexNumber*); //复数减法 /*长度为1024的冲激序列 */
void init1()
{printf("Example:度为1024的冲激序列\n");x[0].realPart=1;x[0].imaginaryPart=0;for(int i=1;i<N;i++){x[i].realPart=0;x[i].imaginaryPart=0;}
}/*长度为1024的矩形序列 */
void init2()
{               printf("Example:长度为1024的矩形序列\n"); for(int i=0;i<N;i++){x[i].realPart=1;x[i].imaginaryPart=0;}
}/*长度为1024的sin[2πk/1024]序列 */
void init3()
{             printf("Example:长度为1024的sin[2πk/1024]序列\n"); for(int i=0;i<N;i++){x[i].realPart=sin(2*PI*i/N);x[i].imaginaryPart=0;}
}/*长度为1024的cos[2πk/1024]序列 */
void init4()
{             printf("Example:长度为1024的cos[2πk/1024]序列\n");for(int i=0;i<N;i++){x[i].realPart=cos(2*PI*i/N);x[i].imaginaryPart=0;}
}int main()
{init3();               //调用不同的初始化函数,使用不同的例程进行测试 printf("=============================================================================================================================================================================================\n");printf("输出原序列:\n");outputArray();initRotationFactor();  //生成旋转因子数组 fastFourierOperation();//调用快速傅里叶变换printf("\n\n=============================================================================================================================================================================================\n");printf("输出FFT后的结果:\n");outputArray();         //遍历输出数组return 0;
}/*快速傅里叶变换*/
void fastFourierOperation()
{int l=0;complexNumber up,down,product;changePosition();                            //偶奇变换算法for(int i=0;i<log(size_x)/log(2);i++)        //一级蝶形运算{   l=1<<i;for(int j=0;j<size_x;j+= 2*l )          //一组蝶形运算{            for(int k=0;k<l;k++)                //一个蝶形运算{       mul(x[j+k+l],W[size_x*k/2/l],&product);add(x[j+k],product,&up);sub(x[j+k],product,&down);x[j+k]=up;x[j+k+l]=down;}}}
}/*生成旋转因子数组*/
void initRotationFactor()
{for(int i=0;i<size_x/2;i++){W[i].realPart=cos(2*PI/size_x*i);//用欧拉公式计算旋转因子W[i].imaginaryPart=-1*sin(2*PI/size_x*i);}
}/*偶奇变换算法*/
void changePosition()
{int j=0,k;//待会儿进行运算时需要用到的变量 complexNumber temp;for (int i=0;i<size_x-1;i++) { if(i<j) {//若倒序数大于顺序数,进行变址(换位);否则不变,防止重复交换,变回原数temp=x[i];x[i]=x[j];x[j]=temp;}k=size_x/2;    //判断j的最高位是否为0while(j>=k) {              //最高位为1j=j-k;k=k/2;}j=j+k;        //最高位为0}printf("\n\n=============================================================================================================================================================================================\n");printf("输出倒序后的结果:\n");outputArray();
}/*遍历输出数组*/
void outputArray()
{int num=0;for(int i=0;i<size_x;i++){        if(x[i].imaginaryPart<0){printf("%.4f-j%.4f     ",x[i].realPart,fabs(x[i].imaginaryPart));}else{printf("%.4f+j%.4f     ",x[i].realPart,x[i].imaginaryPart);}num++;if(num==10){printf("\n");num=0;}}
}/*复数加法的定义*/
void add(complexNumber a,complexNumber b,complexNumber *c)
{c->realPart=a.realPart+b.realPart;c->imaginaryPart=a.imaginaryPart+b.imaginaryPart;
}/*复数乘法的定义*/
void mul(complexNumber a,complexNumber b,complexNumber *c)
{c->realPart=a.realPart*b.realPart - a.imaginaryPart*b.imaginaryPart;c->imaginaryPart=a.realPart*b.imaginaryPart + a.imaginaryPart*b.realPart;
}/*复数减法的定义*/
void sub(complexNumber a,complexNumber b,complexNumber *c)
{c->realPart=a.realPart-b.realPart;c->imaginaryPart=a.imaginaryPart-b.imaginaryPart;
}

部分运行效果如下:

使用C语言实现FFT算法(快速傅里叶变换)相关推荐

  1. (FFT)快速傅里叶变换在目标跟踪中的运用

    随着科学技术的不断发展,许多用于加快计算速度的算法应运而生,快速傅里叶变换就是其中之一,快速傅里叶变换是傅里叶变换的一种快速计算方式.傅里叶变换在科学研究中运用非常广泛,刚开始出现时,主要用于信号分析 ...

  2. 一文让你秒懂FFT(快速傅里叶变换)

    引言 快速计算两个多项式的乘法 1.多项式乘法 例如 所以 那么我们该如何来储存一个多项式呢?最一般的方法就是储存多项式的系数,我们只需要把系数映射到一个表中,按顺序存储,这样的话,表中的第k个数字正 ...

  3. 【FFT】快速傅里叶变换详解

    傅里叶变换历史 傅里叶是一位法国数学家和物理学家的名字,英语原名是Jean Baptiste Joseph Fourier(1768-1830), Fourier对热传递很感兴趣,于1807年在法国科 ...

  4. [转]十分简明易懂的FFT(快速傅里叶变换)

    FFT前言 快速傅里叶变换 (fast Fourier transform),即利用计算机计算离散傅里叶变换(DFT)的高效.快速计算方法的统称,简称FFT.快速傅里叶变换是1965年由J.W.库利和 ...

  5. 超详细易懂FFT(快速傅里叶变换)及代码实现

    前言 昨天学了一晚上,终于搞懂了FFT.希望能写一篇清楚易懂的题解分享给大家,也进一步加深自己的理解. FFT算是数论中比较重要的东西,听起来就很高深的亚子.但其实学会了(哪怕并不能完全理解),会实现 ...

  6. FFT(快速傅里叶变换)学习笔记

    简介 FFTFFTFFT (法法塔)是个什么玩意?他的全名叫快速傅里叶变换(然而貌似和傅里叶并没有太大关系),用来快速求出多项式的点值表示,这个东西一般用来解决多项式相乘的问题. 一般的高精度乘法,我 ...

  7. 名词解释 算法的有限性_欲借助 FFT 算法快速计算两有限长序列的线性卷积,则过程中要调用 ( ) 次 FFT 算法_学小易找答案...

    [单选题]计算 N=2 L ( L 为整数)点的按时间抽取基 -2FFT 需要 ( ) 级蝶形运算 [单选题]Les étudiants chinois, une fois arrivés en Fr ...

  8. c代码实现 ifft运算_fft算法c语言_matlab fft算法_ifft c语言

    FFT快速算法C程序_工学_高等教育_教育专区.电子信息工程综合课程设计报告书 DSP 课程设计 报告 题学 目: 院: FFT 快速算法 C 程序 计算机与信息工程学院 09 ... fft算法代码 ...

  9. C++实现 (FFT)一维快速傅里叶变换

    一维离散傅里叶变换的公式为: 如果直接基于该定义进行编程实现,则算法时间复杂度为O(N2).具体的编程实现我们已经在<C++实现一维离散傅里叶变换>中介绍过了. 当一维信号长度达到几十万个 ...

最新文章

  1. 数据结构显示树的所有结点_您需要了解的有关树数据结构的所有信息
  2. spring_在运行时更新代码(已Spring解密)
  3. 改善Java应用程序性能的快速技巧
  4. 8、linux上安装hbase
  5. (王道408考研操作系统)第二章进程管理-第四节3:死锁处理策略之检测和解除
  6. android命名规范阿里,阿里android开发手册 PDF 下载
  7. 1087 有多少不同的值 (20分)
  8. Emacs Lisp基本语法(六)
  9. sql 查找重复数据,并且重复数据有子集
  10. 祝贺泰山JDK8开源
  11. his提供哪些服务_品牌战略咨询能为企业提供哪些服务
  12. SQL Server版本和下载地址
  13. DDoS和CC攻击的技术原理区别
  14. ICQ官方中文版 v10.0.12161.0
  15. 2022:股票程序化交易实战2022Q3
  16. java远控_利用Java实现远程控制
  17. 去除nginx.conf文件中注释和空格行方法
  18. nuxt.js实战asyncdata服务端渲染
  19. nmap -oG -iL 写入文件和读取文件之[网鼎杯 2020 朱雀组]Nmap
  20. Linux中传统的IPC机制

热门文章

  1. 小爱课程表适配-正方教务
  2. 【计算机网络】计算机网络纠错本
  3. 链游平台 Attarius Network 加入章鱼网络成为候选应用链
  4. 【Unity】动态生成圆环体Mesh
  5. 前端面试题 HTML5 CSS3(盒子模型、盒子水平垂直居中、经典布局) JS(闭包、深浅克隆、数据劫持和拦截) 算法(排序、去重、数组扁平化) Vue(双向数据绑定原理、通信方式)
  6. iOS逆向-ipa包重签名及非越狱手机安装多个微信
  7. selenium元素定位截图
  8. findEveryThing软件查找计算机本地资源
  9. 15种常用ARGB颜色
  10. [土狗之路]coursera 北京大学C++ 魔兽世界:装备