离散傅里叶变换C++代码
2016-01-25 15:54
288 查看
/* * myfft.h */ #ifndef __MYFFT_H__ #define __MYFFT_H__ #include <windows.h> typedef struct _my_complex { double r; //复数实部 double i; //复数虚部 _my_complex(){} _my_complex(double _r, double _i){r = _r; i = _i;} ~_my_complex(){} _my_complex operator + (const _my_complex & c) //重载加号运算符 { return _my_complex(r + c.r, i + c.i); } _my_complex operator - (const _my_complex & c) //重载减号运算符 { return _my_complex(r - c.r, i - c.i); } _my_complex operator * (const _my_complex & c) //重载乘号运算符 { return _my_complex(r * c.r - i * c.i, r * c.i + i * c.r); } }my_complex; int myfft_by_define_c2c_1d(my_complex * in, int n1, my_complex * out, int n2, int line_width = 1, int is_inv = 0); //按照定义进行一维复数离散傅里叶变换 int myfft_by_define_c2c_2d(my_complex * in, int m, int n, int is_inv = 0); //按照定义进行二维复数离散傅里叶变换 int myfft_c2c_1d_base2(my_complex * in, int n, int line_width = 1, int is_inv = 0); //进行一维复数离散快速傅里叶变换(基2) int print_complex_array_1d(my_complex * in, int n); int print_complex_array_2d(my_complex * in, int m, int n); #endif //__MYFFT_H__
/* * myfft.cpp */ #include <stdio.h> #include <stdlib.h> #include <math.h> #include "myfft.h" #define PI 3.1415926 /*------------按照定义进行一维复数离散傅里叶变换---------------------------------------- * 原理: * 一维离散傅里叶变换公式为: X[k] = ∑x *e^(-2πi * nk/N),其中n=0,1,2,...,N-1 * 一维离散傅里叶逆变换公式为: x = 1/N * ∑X[k]*e^(2πi * nk/N),其中k=0,1,2,...,N-1 * 欧拉公式:e^ix = cos(x) + isin(x) * * 参数1:in 输入的一维复数数组 * 参数2:n1 输入的一维复数数组的长度 * 参数3:out 输出的一维复数数组 * 参数4:n2 输出的一维复数数组的长度(必须和n1相等) * 参数5:line_width 数组下标的间隔(默认为1),对于行变换等于1,对于列变换等于一行的宽度 * 参数6:is_inv 是否是逆变换(默认不是) * * 过客 & 386520874@qq.com & 2016.01.25 */ int myfft_by_define_c2c_1d(my_complex * in, int n1, my_complex * out, int n2, int line_width/*=1*/, int is_inv/*=0*/) { if(n1 != n2){return 0;} double _2PI_N = 2.0 * PI / n1; if(is_inv == 0) //正变换 { for(int m = 0; m < n1; m++) { int M = m * line_width; for(int k = 0; k < n1; k++ ) { int K = k * line_width; out[M].r += in[K].r * cos(_2PI_N * m * k) + in[K].i * sin(_2PI_N * m * k); //计算实部 out[M].i += -in[K].r * sin(_2PI_N * m * k) + in[K].i * cos(_2PI_N * m * k); //计算虚部 } } }else if(is_inv == 1) //逆变换 { for(int m = 0; m < n1; m++) { int M = m * line_width; for(int k = 0; k < n1; k++ ) { int K = k * line_width; out[M].r += in[K].r * cos(_2PI_N * m * k) - in[K].i * sin(_2PI_N * m * k); //计算实部 out[M].i += in[K].r * sin(_2PI_N * m * k) + in[K].i * cos(_2PI_N * m * k); //计算虚部 } out[M].r /= n1; //归一化 out[M].i /= n1; //归一化 } } return 1; } //按照定义进行二维复数离散傅里叶变换 int myfft_by_define_c2c_2d(my_complex * in, int m, int n, int is_inv/*=0*/) { my_complex * temp = new my_complex[m * n]; memset(temp, 0, sizeof(my_complex) * m * n); for(int y = 0; y < n; y++) //先行变换 { myfft_by_define_c2c_1d(in + y * n, n, temp + y * n, n, 1, is_inv); } memset(in, 0, sizeof(my_complex) * m * n); for(int x = 0; x < m; x++) //再列变换 { myfft_by_define_c2c_1d(temp + x, m, in + x, m, n, is_inv); } delete [] temp; temp = NULL; return 1; } /*------------进行一维复数离散快速傅里叶变换(基2)---------------------------------------- * 原理: * 对于FFT算法,一般是基2型的,即要求被变换的数组长度必须是2的m幂次方, * 这种要求过于苛刻,当然相比于按照定义进行计算来说,速度是很快的。此外, * 还有基4的算法,以及混合基算法等,但都对数组长度N有严格的限制。 * 所以想自己开发一个适合任意N的FFT算法,还是比较难的,目前还是调用FFTW库暂时凑合着用吧。 * * 参数1:in 输入的一维复数数组 * 参数2:n 输入/出的一维复数数组的长度 * 参数3:line_width 数组下标的间隔(默认为1),对于行变换等于1,对于列变换等于一行的宽度 * 参数4:is_inv 是否是逆变换(默认不是) * * 过客 & 386520874@qq.com & 2016.01.25 */ int myfft_c2c_1d_base2(my_complex * in, int n, int line_width/*=1*/, int is_inv/*=0*/) { int ttt = n; int L = 1; //蝶形运算的层数 while(ttt = ttt >> 1){L++;} my_complex * X = in; int N = n; int len = 1 << L; //将输入的一维数组对齐为 N=2^L if(n * 2 == len) //刚好是2的幂 { L -= 1; }else if(n < len) //说明n不是2的幂 { // printf("Erorr: n is not 2^m format.\n"); //非基2算法还有待开发 // return 0; N = len; X = new my_complex ; //扩充数组大小 int aaa = sizeof(my_complex); memset(X, 0, sizeof(my_complex) * N); //全部初始化为0 memcpy(X, in, sizeof(my_complex) * n); //复制数据 } //--------数组倒位序 二进制(n0n1n2) => (n2n0n1)------------------- //例如: 3的二进制为 011,对应的倒位序为 110,即为6 my_complex * XX = new my_complex ; for(int i = 0; i < N; i++) { int p = 0; for(int f = 0; f < L; f++) { if(i & (1 << f)) { p += 1 << (L - f - 1); } } XX[i] = X[p]; } memcpy(X, XX, sizeof(my_complex) * N); //复制数据 delete [] XX; XX = NULL; //---------旋转因子------------------- my_complex * W = new my_complex[N / 2]; memset(W, 0, sizeof(my_complex) * N / 2); //全部初始化为0 for(int i = 0; i < N / 2; i++) { W[i] = my_complex(cos(-2.0 * PI * i / N), sin(-2.0 * PI * i / N)); } //---------FFT算法(基2)---------------- for(int f = 0; f < L; f++) //蝶形运算层数 { int G = 1 << (L - f); int num = 1 << f; for(int u = 0; u < num; u++) //每组的元素个数 { for(int g = 0; g < G; g += 2) //每层的组数 { my_complex X1 = X[g * num + u]; my_complex X2 = X[(g + 1) * num + u]; X[g * num + u] = X1 + W[u * (1 << (L - f - 1))] * X2; //蝶形运算 X[(g + 1) * num + u] = X1 - W[u * (1 << (L - f - 1))] * X2; //蝶形运算 } } } if(X != NULL && X != in) //说明另外申请了内存空间 { memcpy(in, X, sizeof(my_complex) * n); if(X){delete [] X; X = NULL;} } if(W != NULL){delete [] W; W = NULL;} return 1; } int print_complex_array_1d(my_complex * in, int n) { for(int i = 0; i < n; i++) { printf("%d:%f+i%f ", i, in[i].r, in[i].i); } printf("\n"); return 1; } int print_complex_array_2d(my_complex * in, int m, int n) { for(int y = 0; y < n; y++) { for(int x = 0; x < m; x++) { printf("%d_%d:%f+i%f ", y, x, (*(in + y * m + x)).r, (*(in + y * m + x)).i); } printf("\n"); } printf("\n"); return 1; }
/* * main.cpp */ #include <stdio.h> #include <stdlib.h> #include "myfft.h" int main(int argc, char * argv[]) //DFT测试 一维 { int n = 8; int n1 = n; int n2 = n; my_complex * in = new my_complex[n1]; my_complex * out = new my_complex[n2]; double data[] = {4, 3, 2, 6, 7, 8, 9, 0}; for(int i = 0; i < n; i++) { in[i].r = data[i]; in[i].i = 0; out[i].r = 0; out[i].i = 0; } print_complex_array_1d(in, n1); //----------正变换---------------------- myfft_by_define_c2c_1d(in, n1, out, n2, 1, 0); //按照定义进行一维复数离散傅里叶变换 print_complex_array_1d(out, n2); //----------逆变换---------------------- memset(in, 0, sizeof(my_complex) * n); myfft_by_define_c2c_1d(out, n2, in, n1, 1, 1); //按照定义进行一维复数离散傅里叶变换 print_complex_array_1d(in, n1); if(in){delete [] in; in = NULL;} if(out){delete [] out; out = NULL;} system("pause"); return 0; } /* 0:4.000000+i0.000000 1:3.000000+i0.000000 2:2.000000+i0.000000 3:6.000000+i0.000000 4:7.000000+i0.000000 5:8.000000+i0.000000 6:9.000000+i0.000000 7:0.000000+i0.000000 0:39.000000+i0.000000 1:-10.778175+i6.292892 2:0.000001+i-5.000001 3:4.778176+i-7.707106 4:5.000000+i0.000001 5:4.778172+i7.707108 6:-0.000002+i4.999998 7:-10.778169+i-6.292899 0:4.000000+i-0.000001 1:3.000000+i-0.000001 2:2.000000+i-0.000000 3:6.000000+i-0.000000 4:7.000000+i0.000000 5:8.000000+i0.000000 6:9.000000+i0.000001 7:0.000000+i0.000001 请按任意键继续. . . */ int main2(int argc, char * argv[]) //DFT测试 二维 { int m = 3; int n = 3; my_complex * in = new my_complex[m * n]; in[0] = my_complex(0, 0); in[1] = my_complex(2, 0); in[2] = my_complex(4, 0); in[3] = my_complex(6, 0); in[4] = my_complex(1, 0); in[5] = my_complex(3, 0); in[6] = my_complex(5, 0); in[7] = my_complex(7, 0); in[8] = my_complex(4, 0); print_complex_array_2d(in, m, n); //----------正变换---------------------- myfft_by_define_c2c_2d(in, m, n, 0); //按照定义进行二维复数离散傅里叶变换 print_complex_array_2d(in, m, n); //----------逆变换---------------------- myfft_by_define_c2c_2d(in, m, n, 1); //按照定义进行二维复数离散傅里叶变换 print_complex_array_2d(in, m, n); if(in){delete [] in; in = NULL;} system("pause"); return 0; } /* 0_0:0.000000+i0.000000 0_1:2.000000+i0.000000 0_2:4.000000+i0.000000 1_0:6.000000+i0.000000 1_1:1.000000+i0.000000 1_2:3.000000+i0.000000 2_0:5.000000+i0.000000 2_1:7.000000+i0.000000 2_2:4.000000+i0.000000 0_0:32.000000+i0.000000 0_1:0.500000+i0.866025 0_2:0.500001+i-0.866027 1_0:-7.000001+i5.196152 1_1:-1.000000+i-1.732051 1_2:-8.499999+i-6.062178 2_0:-6.999999+i-5.196154 2_1:-8.500001+i6.062177 2_2:-1.000000+i1.732051 0_0:0.000000+i-0.000000 0_1:2.000000+i-0.000000 0_2:4.000000+i-0.000000 1_0:6.000000+i-0.000000 1_1:1.000000+i-0.000000 1_2:3.000000+i0.000000 2_0:5.000000+i-0.000000 2_1:7.000000+i0.000000 2_2:4.000000+i0.000001 请按任意键继续. . . */ int main3(int argc, char * argv[]) //FFT测试 一维(基2) { int n = 8; my_complex * in = new my_complex ; double data[] = {4, 3, 2, 6, 7, 8, 9, 0}; for(int i = 0; i < n; i++) { in[i].r = data[i]; in[i].i = 0; } print_complex_array_1d(in, n); //----------正变换---------------------- myfft_c2c_1d_base2(in, n, 1, 0); //进行一维复数离散快速傅里叶变换(基2) print_complex_array_1d(in, n); if(in){delete [] in; in = NULL;} system("pause"); return 0; } /* 0:4.000000+i0.000000 1:3.000000+i0.000000 2:2.000000+i0.000000 3:6.000000+i0.000000 4:7.000000+i0.000000 5:8.000000+i0.000000 6:9.000000+i0.000000 7:0.000000+i0.000000 0:39.000000+i0.000000 1:-10.778175+i6.292893 2:0.000000+i-5.000000 3:4.778175+i-7.707106 4:5.000000+i0.000000 5:4.778174+i7.707107 6:-0.000000+i5.000000 7:-10.778175+i-6.292894 请按任意键继续. . . */
相关文章推荐
- c++之Unicode下vs中CString 转char*
- c++中的前向声明
- C++中的引用
- 详解C++编程中数组的基本用法
- c++ 进程_调用其他程序,关闭其他程序
- C语言小知识点练习总结
- 一个比较有意思的C语言问题
- c++类默认拷贝构造函数---浅复制
- C++ template —— 动多态与静多态(六)
- 617C. Watering Flowers【几何】
- Boost 学习之算法篇 all_of 与 all_of_equal
- 快乐司机(贪心)
- 实例讲解C++编程中lambda表达式的使用
- C语言 百炼成钢14
- C++ template —— 模板特化(五)
- 重学C++ (九) 重载操作符与转换
- bign类C++高精度模板
- 结合C++11新特性来学习C++中lambda表达式的用法
- C++ template —— 实例化和模板实参演绎(四)
- c语言操作mysql