傅里叶变换或者FFT的理论参考:

[1] http://www.dspguide.com/ch12/2.htm

The Scientist and Engineer's Guide to Digital Signal Processing,   By Steven W. Smith, Ph.D.

[2] http://blog.csdn.net/v_JULY_v/article/details/6196862,可当作[1]的中文参考

[3] 任意一本数字信号处理教材,上面都有详细的推导DCT求解转换为FFT求解的过程

[4] TI文档:基于TMS320C64x+DSP的FFT实现。 使用baidu/google可以搜索到。

1. 有关FFT理论的一点小小解释

关于FFT这里只想提到两点:

(1)DFT变换对的表达式(必须记住

          —— 称旋转因子

(2)FFT用途——目标只有一个,加速DFT的计算效率。

DFT计算X(k)需要N^2次复数乘法和N(N-1)次复数加法;FFT将N^2的计算量降为

FFT其实是很难的东西,即使常年在这个领域下打拼的科学家也未必能很好的写出FFT的算法。”——摘自参考上面提供的参考文献[1]

因此,我们不必太过纠结于细节,当明白FFT理论后,将已有的算法挪过来用就OK了,不必为闭着教材写不出FFT而郁闷不堪。

FFT的BASIC程序伪代码如下:

IFFT的BASIC程序伪代码如下(IFFT通过调用FFT计算):

FFT算法的流程图如下图,总结为3过程3循环:

(1)3过程:单点时域分解(倒位序过程) + 单点时域计算单点频谱 + 频域合成

(2)3循环:外循环——分解次数,中循环——sub-DFT运算,内循环——2点蝶形算法

分解过程或者说倒位序的获得参考下图理解:

2. FFT的DSP实现

下面为本人使用C语言实现的FFT及IFFT算法实例,能计算任意以2为对数底的采样点数的FFT,算法参考上面给的流程图。

  1. /*
  2. * zx_fft.h
  3. *
  4. * Created on: 2013-8-5
  5. * Author: monkeyzx
  6. */
  7.  
  8. #ifndef ZX_FFT_H_
  9. #define ZX_FFT_H_
  10.  
  11. typedef float FFT_TYPE;
  12.  
  13. #ifndef PI
  14. #define PI (3.14159265f)
  15. #endif
  16.  
  17. typedef struct complex_st {
  18. FFT_TYPE real;
  19. FFT_TYPE img;
  20. } complex;
  21.  
  22. int fft(complex *x, int N);
  23. int ifft(complex *x, int N);
  24. void zx_fft(void);
  25.  
  26. #endif /* ZX_FFT_H_ */
  1. /*
  2. * zx_fft.c
  3. *
  4. * Implementation of Fast Fourier Transform(FFT)
  5. * and reversal Fast Fourier Transform(IFFT)
  6. *
  7. * Created on: 2013-8-5
  8. * Author: monkeyzx
  9. */
  10.  
  11. #include "zx_fft.h"
  12. #include <math.h>
  13. #include <stdlib.h>
  14.  
  15. /*
  16. * Bit Reverse
  17. * === Input ===
  18. * x : complex numbers
  19. * n : nodes of FFT. @N should be power of 2, that is 2^(*)
  20. * l : count by bit of binary format, @l=CEIL{log2(n)}
  21. * === Output ===
  22. * r : results after reversed.
  23. * Note: I use a local variable @temp that result @r can be set
  24. * to @x and won't overlap.
  25. */
  26. static void BitReverse(complex *x, complex *r, int n, int l)
  27. {
  28. int i = 0;
  29. int j = 0;
  30. short stk = 0;
  31. static complex *temp = 0;
  32.  
  33. temp = (complex *)malloc(sizeof(complex) * n);
  34. if (!temp) {
  35. return;
  36. }
  37.  
  38. for(i=0; i<n; i++) {
  39. stk = 0;
  40. j = 0;
  41. do {
  42. stk |= (i>>(j++)) & 0x01;
  43. if(j<l)
  44. {
  45. stk <<= 1;
  46. }
  47. }while(j<l);
  48.  
  49. if(stk < n) { /* 满足倒位序输出 */
  50. temp[stk] = x[i];
  51. }
  52. }
  53. /* copy @temp to @r */
  54. for (i=0; i<n; i++) {
  55. r[i] = temp[i];
  56. }
  57. free(temp);
  58. }
  59.  
  60. /*
  61. * FFT Algorithm
  62. * === Inputs ===
  63. * x : complex numbers
  64. * N : nodes of FFT. @N should be power of 2, that is 2^(*)
  65. * === Output ===
  66. * the @x contains the result of FFT algorithm, so the original data
  67. * in @x is destroyed, please store them before using FFT.
  68. */
  69. int fft(complex *x, int N)
  70. {
  71. int i,j,l,ip;
  72. static int M = 0;
  73. static int le,le2;
  74. static FFT_TYPE sR,sI,tR,tI,uR,uI;
  75.  
  76. M = (int)(log(N) / log(2));
  77.  
  78. /*
  79. * bit reversal sorting
  80. */
  81. BitReverse(x,x,N,M);
  82.  
  83. /*
  84. * For Loops
  85. */
  86. for (l=1; l<=M; l++) { /* loop for ceil{log2(N)} */
  87. le = (int)pow(2,l);
  88. le2 = (int)(le / 2);
  89. uR = 1;
  90. uI = 0;
  91. sR = cos(PI / le2);
  92. sI = -sin(PI / le2);
  93. for (j=1; j<=le2; j++) { /* loop for each sub DFT */
  94. //jm1 = j - 1;
  95. for (i=j-1; i<=N-1; i+=le) { /* loop for each butterfly */
  96. ip = i + le2;
  97. tR = x[ip].real * uR - x[ip].img * uI;
  98. tI = x[ip].real * uI + x[ip].img * uR;
  99. x[ip].real = x[i].real - tR;
  100. x[ip].img = x[i].img - tI;
  101. x[i].real += tR;
  102. x[i].img += tI;
  103. } /* Next i */
  104. tR = uR;
  105. uR = tR * sR - uI * sI;
  106. uI = tR * sI + uI *sR;
  107. } /* Next j */
  108. } /* Next l */
  109.  
  110. return 0;
  111. }
  112.  
  113. /*
  114. * Inverse FFT Algorithm
  115. * === Inputs ===
  116. * x : complex numbers
  117. * N : nodes of FFT. @N should be power of 2, that is 2^(*)
  118. * === Output ===
  119. * the @x contains the result of FFT algorithm, so the original data
  120. * in @x is destroyed, please store them before using FFT.
  121. */
  122. int ifft(complex *x, int N)
  123. {
  124. int k = 0;
  125.  
  126. for (k=0; k<=N-1; k++) {
  127. x[k].img = -x[k].img;
  128. }
  129.  
  130. fft(x, N); /* using FFT */
  131.  
  132. for (k=0; k<=N-1; k++) {
  133. x[k].real = x[k].real / N;
  134. x[k].img = -x[k].img / N;
  135. }
  136.  
  137. return 0;
  138. }
  139.  
  140. /*
  141. * Code below is an example of using FFT and IFFT.
  142. */
  143. #define SAMPLE_NODES (128)
  144. complex x[SAMPLE_NODES];
  145. int INPUT[SAMPLE_NODES];
  146. int OUTPUT[SAMPLE_NODES];
  147.  
  148. static void MakeInput()
  149. {
  150. int i;
  151.  
  152. for ( i=0;i<SAMPLE_NODES;i++ )
  153. {
  154. x[i].real = sin(PI*2*i/SAMPLE_NODES);
  155. x[i].img = 0.0f;
  156. INPUT[i]=sin(PI*2*i/SAMPLE_NODES)*1024;
  157. }
  158. }
  159.  
  160. static void MakeOutput()
  161. {
  162. int i;
  163.  
  164. for ( i=0;i<SAMPLE_NODES;i++ )
  165. {
  166. OUTPUT[i] = sqrt(x[i].real*x[i].real + x[i].img*x[i].img)*1024;
  167. }
  168. }
  169.  
  170. void zx_fft(void)
  171. {
  172. MakeInput();
  173.  
  174. fft(x,128);
  175. MakeOutput();
  176.  
  177. ifft(x,128);
  178. MakeOutput();
  179. }

程序在TMS320C6713上实验,主函数中调用zx_fft()函数即可。

FFT的采样点数为128,输入信号的实数域为正弦信号,虚数域为0,数据精度定义FFT_TYPE为float类型,MakeInput和MakeOutput函数分别用于产生输入数据INPUT和输出数据OUTPUT的函数,便于使用CCS 的Graph功能绘制波形图。这里调试时使用CCS v5中的Tools -> Graph功能得到下面的波形图(怎么用自己琢磨,不会的使用CCS 的Help)。

输入波形

输入信号的频域幅值表示

FFT运算结果

对FFT运算结果逆变换(IFFT)


如何检验运算结果是否正确呢?有几种方法:

(1)使用matlab验证,下面为相同情况的matlab图形验证代码

  1. SAMPLE_NODES = 128;
  2. i = 1:SAMPLE_NODES;
  3. x = sin(pi*2*i / SAMPLE_NODES);
  4.  
  5. subplot(2,2,1); plot(x);title('Inputs');
  6. axis([0 128 -1 1]);
  7.  
  8. y = fft(x, SAMPLE_NODES);
  9. subplot(2,2,2); plot(abs(y));title('FFT');
  10. axis([0 128 0 80]);
  11.  
  12. z = ifft(y, SAMPLE_NODES);
  13. subplot(2,2,3); plot(abs(z));title('IFFT');
  14. axis([0 128 0 1]);

(2)使用IFFT验证:输入信号的FFT获得的信号再IFFT,则的到的信号与原信号相同

可能大家发现输入信号上面的最后IFFT的信号似乎不同,这是因为FFT和IFFT存在精度截断误差(也叫数据截断噪声,意思就是说,我们使用的float数据类型数据位数有限,没法完全保留原始信号的信息)。因此,IFFT之后是复数(数据截断噪声引入了虚数域,只不过值很小),所以在绘图时使用了计算幅值的方法,

C代码中:

  1. OUTPUT[i] = sqrt(x[i].real*x[i].real + x[i].img*x[i].img)*1024;

matlab代码中:

  1. subplot(2,2,3); plot(abs(z));title('IFFT');

所以IFFT的结果将sin函数的负y轴数据翻到了正y轴。另外,在CCS v5的图形中我们将显示信号的幅度放大了1024倍便于观察,而matlab中没有放大。

FFT算法的完整DSP实现的更多相关文章

  1. FFT算法的完整DSP实现(转)

    源:FFT算法的完整DSP实现 傅里叶变换或者FFT的理论参考: [1] http://www.dspguide.com/ch12/2.htm The Scientist and Engineer's ...

  2. FFT算法

    FFT算法的完整DSP实现 傅里叶变换或者FFT的理论参考: [1] http://www.dspguide.com/ch12/2.htm The Scientist and Engineer's G ...

  3. msp430学习笔记-实现开方log等计算及FFT算法(待续)

    MSP430 FFT算法实现 http://bbs.21ic.com/icview-391532-1-1.html http://blog.sina.com.cn/s/blog_6cd2030b010 ...

  4. 基于傅里叶变换的音频重采样算法 (附完整c代码)

    前面有提到音频采样算法: WebRTC 音频采样算法 附完整C++示例代码 简洁明了的插值音频重采样算法例子 (附完整C代码) 近段时间有不少朋友给我写过邮件,说了一些他们使用的情况和问题. 坦白讲, ...

  5. 音频降噪算法 附完整C代码

    降噪是音频图像算法中的必不可少的. 目的肯定是让图片或语音 更加自然平滑,简而言之,美化. 图像算法和音频算法 都有其共通点. 图像是偏向 空间 处理,例如图片中的某个区域. 图像很多时候是以二维数据 ...

  6. mser 最大稳定极值区域(文字区域定位)算法 附完整C代码

    mser 的全称:Maximally Stable Extremal Regions 第一次听说这个算法时,是来自当时部门的一个同事, 提及到他的项目用它来做文字区域的定位,对这个算法做了一些优化. ...

  7. 音频自动增益 与 静音检测 算法 附完整C代码

    前面分享过一个算法<音频增益响度分析 ReplayGain 附完整C代码示例> 主要用于评估一定长度音频的音量强度, 而分析之后,很多类似的需求,肯定是做音频增益,提高音量诸如此类做法. ...

  8. 快速傅立叶变换(FFT)算法

    已知多项式f(x)=a0+a1x+a2x2+...+am-1xm-1, g(x)=b0+b1x+b2x2+...+bn-1xn-1.利用卷积的蛮力算法,得到h(x)=f(x)g(x),这一过程的时间复 ...

  9. 用C实现FFT算法

    用C语言编写FFT算法  转http://blog.sina.com.cn/s/blog_65d639d50101buo1.html #include "math.h" #defi ...

随机推荐

  1. C++学习之路(七):以const,enum,inline替换#define

    这篇博文主要是编程中的一些问题和技巧.如题目所示,这些关键字的作用不再进行描述.直接描述功能和实例代码. 首先,在头文件中对类进行定义,是不会为类分配内存空间的,在这一点上类定义可以和普通变量类型的声 ...

  2. C++学习之路(五):复制构造函数与赋值运算符重载

    之前没有细想过两者的区别,今天对此进行简要记录,后续完善补充. 复制构造函数是在类对象被创建时调用的,但是赋值运算符是被已经存在的对象调用完成赋值操作. 复制构造函数只在对象实例化时才被调用,即在复制 ...

  3. Yii 1.1.17 六、开启路由与使用缓存

    一.开启路由 1.在配置文件main.php的components中 定义如下: // 定义路由 'urlManager'=>array( // URL模式为PATHINFO 'urlForma ...

  4. centos6.5升级Linux内核步骤

    centos6.5升级Linux内核步骤 http://www.jianshu.com/p/c75f00182b4c 使用的操作系统是是centos6.5,按照官方的推荐的配置,把linux内核升级到 ...

  5. sicily 1009. Mersenne Composite N

    Description One of the world-wide cooperative computing tasks is the "Grand Internet Mersenne P ...

  6. 【LOJ6201】【bzoj4939】【YNOI2016】掉进兔子洞

    一道比较简单的莫队…… 用bitset维护三个区间的交元素. #include<bits/stdc++.h> ; ; #define UI unsigned int #define rep ...

  7. 一个真正的客户端非阻塞的 connect

    前言  - 一个简短开场白 winds 的 select 和 linux 的 select 是两个完全不同的东西. 然而凡人喜欢把它们揉在一起. 非阻塞的connect业务是个自带超时机制的 conn ...

  8. python初学-元组、集合

    元组: 元组基本和列表一样,区别是 元组的值一旦创建 就不能改变了 tup1=(1,2,3,4,5) print(tup1[2]) ---------------------------------- ...

  9. 堆--LogN的数据结构

    我们这里的堆是指用来表示元素集合的一种数据结构 一个二叉树是一个堆是由堆的两个性质决定的(以小根堆为例) 1:任何节点的值都小于或等于其子节点的值 2:该二叉树最多在两层上具有叶节点,其中最底层的叶节 ...

  10. LeetCode解题报告—— Longest Valid Parentheses

    Given a string containing just the characters '(' and ')', find the length of the longest valid (wel ...