FFT算法的完整DSP实现

傅里叶变换或者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,算法参考上面给的流程图。

/*
* zx_fft.h
*
* Created on: 2013-8-5
* Author: monkeyzx
*/ #ifndef ZX_FFT_H_
#define ZX_FFT_H_ typedef float FFT_TYPE; #ifndef PI
#define PI (3.14159265f)
#endif typedef struct complex_st {
FFT_TYPE real;
FFT_TYPE img;
} complex; int fft(complex *x, int N);
int ifft(complex *x, int N);
void zx_fft(void); #endif /* ZX_FFT_H_ */
/*
* zx_fft.c
*
* Implementation of Fast Fourier Transform(FFT)
* and reversal Fast Fourier Transform(IFFT)
*
* Created on: 2013-8-5
* Author: monkeyzx
*/ #include "zx_fft.h"
#include <math.h>
#include <stdlib.h> /*
* Bit Reverse
* === Input ===
* x : complex numbers
* n : nodes of FFT. @N should be power of 2, that is 2^(*)
* l : count by bit of binary format, @l=CEIL{log2(n)}
* === Output ===
* r : results after reversed.
* Note: I use a local variable @temp that result @r can be set
* to @x and won't overlap.
*/
static void BitReverse(complex *x, complex *r, int n, int l)
{
int i = 0;
int j = 0;
short stk = 0;
static complex *temp = 0; temp = (complex *)malloc(sizeof(complex) * n);
if (!temp) {
return;
} for(i=0; i<n; i++) {
stk = 0;
j = 0;
do {
stk |= (i>>(j++)) & 0x01;
if(j<l)
{
stk <<= 1;
}
}while(j<l); if(stk < n) { /* 满足倒位序输出 */
temp[stk] = x[i];
}
}
/* copy @temp to @r */
for (i=0; i<n; i++) {
r[i] = temp[i];
}
free(temp);
} /*
* FFT Algorithm
* === Inputs ===
* x : complex numbers
* N : nodes of FFT. @N should be power of 2, that is 2^(*)
* === Output ===
* the @x contains the result of FFT algorithm, so the original data
* in @x is destroyed, please store them before using FFT.
*/
int fft(complex *x, int N)
{
int i,j,l,ip;
static int M = 0;
static int le,le2;
static FFT_TYPE sR,sI,tR,tI,uR,uI; M = (int)(log(N) / log(2)); /*
* bit reversal sorting
*/
BitReverse(x,x,N,M); /*
* For Loops
*/
for (l=1; l<=M; l++) { /* loop for ceil{log2(N)} */
le = (int)pow(2,l);
le2 = (int)(le / 2);
uR = 1;
uI = 0;
sR = cos(PI / le2);
sI = -sin(PI / le2);
for (j=1; j<=le2; j++) { /* loop for each sub DFT */
//jm1 = j - 1;
for (i=j-1; i<=N-1; i+=le) { /* loop for each butterfly */
ip = i + le2;
tR = x[ip].real * uR - x[ip].img * uI;
tI = x[ip].real * uI + x[ip].img * uR;
x[ip].real = x[i].real - tR;
x[ip].img = x[i].img - tI;
x[i].real += tR;
x[i].img += tI;
} /* Next i */
tR = uR;
uR = tR * sR - uI * sI;
uI = tR * sI + uI *sR;
} /* Next j */
} /* Next l */ return 0;
} /*
* Inverse FFT Algorithm
* === Inputs ===
* x : complex numbers
* N : nodes of FFT. @N should be power of 2, that is 2^(*)
* === Output ===
* the @x contains the result of FFT algorithm, so the original data
* in @x is destroyed, please store them before using FFT.
*/
int ifft(complex *x, int N)
{
int k = 0; for (k=0; k<=N-1; k++) {
x[k].img = -x[k].img;
} fft(x, N); /* using FFT */ for (k=0; k<=N-1; k++) {
x[k].real = x[k].real / N;
x[k].img = -x[k].img / N;
} return 0;
} /*
* Code below is an example of using FFT and IFFT.
*/
#define SAMPLE_NODES (128)
complex x[SAMPLE_NODES];
int INPUT[SAMPLE_NODES];
int OUTPUT[SAMPLE_NODES]; static void MakeInput()
{
int i; for ( i=0;i<SAMPLE_NODES;i++ )
{
x[i].real = sin(PI*2*i/SAMPLE_NODES);
x[i].img = 0.0f;
INPUT[i]=sin(PI*2*i/SAMPLE_NODES)*1024;
}
} static void MakeOutput()
{
int i; for ( i=0;i<SAMPLE_NODES;i++ )
{
OUTPUT[i] = sqrt(x[i].real*x[i].real + x[i].img*x[i].img)*1024;
}
} void zx_fft(void)
{
MakeInput(); fft(x,128);
MakeOutput(); ifft(x,128);
MakeOutput();
}

程序在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图形验证代码

SAMPLE_NODES = 128;
i = 1:SAMPLE_NODES;
x = sin(pi*2*i / SAMPLE_NODES); subplot(2,2,1); plot(x);title('Inputs');
axis([0 128 -1 1]); y = fft(x, SAMPLE_NODES);
subplot(2,2,2); plot(abs(y));title('FFT');
axis([0 128 0 80]); z = ifft(y, SAMPLE_NODES);
subplot(2,2,3); plot(abs(z));title('IFFT');
axis([0 128 0 1]);

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

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

C代码中:

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

matlab代码中:

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

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

FFT算法的更多相关文章

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

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

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

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

  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实现FFT算法

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

  5. 2维FFT算法实现——基于GPU的基2快速二维傅里叶变换

    上篇讲述了一维FFT的GPU实现(FFT算法实现——基于GPU的基2快速傅里叶变换),后来我又由于需要做了一下二维FFT,大概思路如下. 首先看的肯定是公式: 如上面公式所描述的,2维FFT只需要拆分 ...

  6. FFT算法的完整DSP实现

    傅里叶变换或者FFT的理论参考: [1] http://www.dspguide.com/ch12/2.htm The Scientist and Engineer's Guide to Digita ...

  7. 基于verilog的FFT算法8点12位硬件实现

    FFT算法8点12位硬件实现 (verilog) 1 一.功能描述: 1 二.设计结构: 2 三.设计模块介绍 3 1.蝶形运算(第一级) 3 2.矢量角度旋转(W) 4 3.CORDIC 结果处理 ...

  8. Matlab:Toeplitz矩阵-向量乘法的快速傅里叶(FFT)算法

    一.$\tt Toeplitz$矩阵与循环($\tt Circulant$)矩阵 定义 为$n\times n$阶循环矩阵. 定义 $T_n(i,j)=t_{j-i} $  为$n\times n$ ...

  9. 模意义下的FFT算法

    //写在前面 单就FFT算法来说的话,下面只给出个人认为比较重要的推导,详细的介绍可参考 FFT算法学习笔记 令v[n]是长度为2N的实序列,V[k]表示该实序列的2N点DFT.定义两个长度为N的实序 ...

随机推荐

  1. BZOJ 1449: [JSOI2009]球队收益( 最小费用最大流)

    先考虑假如全部输了的收益. 再考虑每场比赛球队赢了所得收益的增加量,用这个来建图.. --------------------------------------------------------- ...

  2. php mysql实现栏目分类递归

    header("content-type:text/html;charset=utf-8"); $dbhost = "localhost";   // 数据库主 ...

  3. javascript 作用域链

    最近想整理一下js执行代码的一些知识,如果有出错的地方还请指正. 执行环境(Execution Context) 所有的javascript代码都是在一个执行环境中被执行的.它只是一种机制,用来完成运 ...

  4. javascript学习笔记(window .alert 是什么)

    <script language="javascript"> var abc="25"; window .alert(abc); </scri ...

  5. C++标准程序库的输入输出流(I/O Stream)复制文件(4种方法)

    使用C++标准程序库的输入输出流(I/O   Stream)复制文件,存在许多的方法, 方法一:逐个字符复制#include   <   fstream   > std::ifstream ...

  6. Java ThreadLocal 学习

    同步机制是为了同步多个线程对相同资源的并发访问,是为了多个线程之间进行通信的有效方式. 而ThreadLocal是隔离多个线程的数据共享,从根本上就不在多个线程之间共享资源(变量),这样当然不需要对多 ...

  7. [055] SSL 3.0曝出Poodle漏洞的解决方式-----开发人员篇

    SSL 3.0曝出高危漏洞 2014年10月15日,Google研究人员发布SSL 3.0协议存在一个非常严重的漏洞,该漏洞可被黑客用于截取浏览器与server之间进行传输的加密数据,如网银账号.邮箱 ...

  8. CSS样式中ClearBoth的理解

    在CSS中我们会经常要用到“清除浮动”Clear,比较典型的就是clear:both; CSS手册上是这样说明的:该属性的值指出了不允许有浮动对象的边.这个属性是用来控制float属性在文档流的物理位 ...

  9. PHP - 数组去重,(折中:符串去重)

    [译]更快的方式实现PHP数组去重 Jan 11, 2016 • Hector 原文:Faster Alternative to PHP’s Array Unique Function 概述 使用PH ...

  10. 优雅的python

    在知乎上看到的问题--python有哪些优雅的代码实现. 下面的代码大概也算不上优雅. 一下代码在python3中实现 更多内容可见:http://book.pythontips.com/en/lat ...