快速傅里叶FFT----C语言版本
presented by YanKM
由于个人纯属新手写md文件,故:尽量看吧(哈哈哈哈)
FFT这个东西据说比DFT要快许多,应为时间的复杂度变了,从原来的O(n^2)降到了O(nlogn)。对于整个FFT的介绍大家可以看看详细的算法介绍和推导过程维基百科
在这里,我们重点对整个代码框架做一个介绍
1. 复数
记住,这里我们说C语言并不是MATLAB,所以复数的运算我们得要自己定义
typedef struct comp {
double real;
double imag;
}Complex;
还有相应的运算(加、减、乘)
Complex add (Complex a, Complex b){
Complex c;
c.real = a.real + b.real;
c.imag = a.imag + b.imag;
return c;
}
Complex sub (Complex a, Complex b){
Complex c;
c.real = a.real - b.real;
c.imag = a.imag - b.imag;
return c;
}
Complex mul (Complex a, Complex b){
Complex c;
c.real = a.real * b.real - a.imag * b.imag;
c.imag = a.real * b.imag + a.imag * b.real;
return c;
}
这些不是这里的重点内容,不会的话可以复习一下复数的基本运算
2. 计算等级分割及重新排序
既然运算等级是O(nlogn),那么必然有个log(n)的级别,这就来源于等级分割。
我们先看几个例子:
个数 | 等级层数 |
---|---|
4 | 2 |
8 | 3 |
2^n | n |
所以我们可以对于个数可以直接进行log2(N)即可。但是log运算得要用第三方库(math.h),且运算耗时,我们直接可以进行手动计算次数(毕竟N都是2的幂指数)
tmp = N;
while (tmp != 0) {
tmp /= 2;
times++;
}
times--;
然后我们来看一下重新排序。这个就有点操作了,举例为先:
原顺序 | 新顺序 |
---|---|
0123 | 0213 |
01234567 | 04261537 |
可能我们对这些数字并不敏感(我也是一样),个人先想到这个有点像最大堆的拆分过程,然而实际上可以说这是对的(真香)。
上面哪个方法,可以用,自己也尝试了一下,空间占用很是问题。假如我们在开发板上用那种递归搞,俩字:呵呵
还有一种空间占用小且速度快的一种思路,从二进制的角度看问题,由于是八个数,所以索引编号从000到111即可,故前面的第二组数字为例,看一下变化:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|
000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 |
0 | 4 | 2 | 6 | 1 | 5 | 3 | 7 |
---|---|---|---|---|---|---|---|
000 | 100 | 010 | 110 | 001 | 101 | 011 | 111 |
可以发现二进制的顺序直接颠倒(001->100,110->011),所以对于颠倒我们看可以使用堆栈
所以有下面的代码
int buf = (int*) malloc (times * sizeof(int));
for (i = 0; i < length; i++) {
tmp = i;
// push
for (j = 0; j < times; j++) {
buf[j] = tmp % 2;
tmp /= 2;
}
tmp = 0;
// pop
for (j = 0; j < times; j++) {
tmp *= 2;
tmp += buf[j];
}
number[i] = tmp;
}
所以对于重新排序的整体代码就出锅了。
int* change (int length) {
int* number = (int*) malloc (length * sizeof(int));
int* buf;
int i = 0, times = 0, j = 0, k = 0; int tmp = length;
while