博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
经典傅里叶算法小集合 附完整c代码
阅读量:5861 次
发布时间:2019-06-19

本文共 11275 字,大约阅读时间需要 37 分钟。

 前面写过关于傅里叶算法的应用例子。

当然也就是举个例子,主要是学习傅里叶变换。

这个重采样思路还有点瑕疵,

稍微改一下,就可以支持多通道,以及提升性能。

当然思路很简单,就是切分,合并。

留个作业哈。

本文不讲过多的算法思路,傅里叶变换的各种变种,

绝大多数是为提升性能,支持任意长度而作。

当然各有所长,

当时提到参阅整理的算法:

例如 : 

 是优化速度, 

 是支持任意长度,

是经典实现。

当然,各有利弊,精度也不一。

最近一直对傅里叶算法没放手。

还是想要抽点时间,不依赖第三方库,实现一份不差于fftw的算法,

既要保证精度,又要保证性能,同时还要支持任意长度。

目前还在进行中,目前项目完成了45%左右。

越是学习,看的资料林林总总,越觉得傅里叶变换的应用面很广。

花点时间,采用纯c ,实现了经典的傅里叶算法,

调整代码逻辑,慢慢开始有点清晰了。

前人栽树后人乘凉,为了学习方便,

把本人用纯c实现的经典傅里叶算法开源出来给大家学习。

算法逻辑写得简洁明了,我也是尽力了。

当然,可能还有更好的实现思路,更多的改进算法。

不过,我的目的更多是便于学习和理解算法。

希望能帮助到一些也在学习傅里叶变换算法的同学。

贴上完整算法代码:

#include 
#include
#include
#include
#include
#include
#ifndef M_PI#define M_PI 3.14159265358979323846f#endiftypedef struct { float real, imag;} cmplx;cmplx cmplx_mul_add(const cmplx c, const cmplx a, const cmplx b) { const cmplx ret = { (a.real * b.real) + c.real - (a.imag * b.imag), (a.imag * b.real) + (a.real * b.imag) + c.imag }; return ret;}void fft_Stockham(cmplx *input, cmplx *output, size_t n, int flag) { size_t half = n >> 1; cmplx *tmp = (cmplx *) calloc(sizeof(cmplx), n); cmplx *y = (cmplx *) calloc(sizeof(cmplx), n); memcpy(y, input, sizeof(cmplx) * n); for (size_t r = half, l = 1; r >= 1; r >>= 1) { cmplx *tp = y; y = tmp; tmp = tp; float factor_w = -flag * M_PI / l; cmplx w = {cosf(factor_w), sinf(factor_w)}; cmplx wj = { 1, 0}; for (size_t j = 0; j < l; j++) { size_t jrs = j * (r << 1); for (size_t k = jrs, m = jrs >> 1; k < jrs + r; k++) { const cmplx t = {(wj.real * tmp[k + r].real) - (wj.imag * tmp[k + r].imag), (wj.imag * tmp[k + r].real) + (wj.real * tmp[k + r].imag)}; y[m].real = tmp[k].real + t.real; y[m].imag = tmp[k].imag + t.imag; y[m + half].real = tmp[k].real - t.real; y[m + half].imag = tmp[k].imag - t.imag; m++; } const float t = wj.real; wj.real = (t * w.real) - (wj.imag * w.imag); wj.imag = (wj.imag * w.real) + (t * w.imag); } l <<= 1; } memcpy(output, y, sizeof(cmplx) * n); free(tmp); free(y);}void fft_radix3(cmplx *in, cmplx *result, size_t n, int flag) { if (n < 2) { memcpy(result, in, sizeof(cmplx) * n); return; } size_t radix = 3; size_t np = n / radix; cmplx *res = (cmplx *) malloc(sizeof(cmplx) * n); cmplx *f0 = res; cmplx *f1 = f0 + np; cmplx *f2 = f1 + np; for (size_t i = 0; i < np; i++) { for (size_t j = 0; j < radix; j++) { res[i + j * np] = in[radix * i + j]; } } fft_radix3(f0, f0, np, flag); fft_radix3(f1, f1, np, flag); fft_radix3(f2, f2, np, flag); float wexp0 = -2 * (float) M_PI * (flag) / (float) (n); cmplx wt = {cosf(wexp0), sinf(wexp0)}; cmplx w0 = { 1, 0}; for (size_t i = 0; i < np; i++) { const float w0r = w0.real; w0.real = (w0r * wt.real) - (w0.imag * wt.imag); w0.imag = (w0.imag * wt.real) + (w0r * wt.imag); } cmplx w = { 1, 0}; for (size_t j = 0; j < radix; j++) { cmplx wj = w; for (size_t k = 0; k < np; k++) { result[k + j * np] = cmplx_mul_add(f0[k], cmplx_mul_add(f1[k], f2[k], wj), wj); const float wjr = wj.real; wj.real = (wjr * wt.real) - (wj.imag * wt.imag); wj.imag = (wj.imag * wt.real) + (wjr * wt.imag); } const float wr = w.real; w.real = (wr * w0.real) - (w.imag * w0.imag); w.imag = (w.imag * w0.real) + (wr * w0.imag); } free(res);}void fft_radix5(cmplx *x, cmplx *result, size_t n, int flag) { if (n < 2) { memcpy(result, x, sizeof(cmplx) * n); return; } size_t radix = 5; size_t np = n / radix; cmplx *res = (cmplx *) calloc(sizeof(cmplx), n); cmplx *f0 = res; cmplx *f1 = f0 + np; cmplx *f2 = f1 + np; cmplx *f3 = f2 + np; cmplx *f4 = f3 + np; for (size_t i = 0; i < np; i++) { for (size_t j = 0; j < radix; j++) { res[i + j * np] = x[radix * i + j]; } } fft_radix5(f0, f0, np, flag); fft_radix5(f1, f1, np, flag); fft_radix5(f2, f2, np, flag); fft_radix5(f3, f3, np, flag); fft_radix5(f4, f4, np, flag); float wexp0 = -2 * (float) M_PI * (flag) / (float) (n); cmplx wt = {cosf(wexp0), sinf(wexp0)}; cmplx w0 = { 1, 0}; for (size_t i = 0; i < np; i++) { const float w0r = w0.real; w0.real = (w0r * wt.real) - (w0.imag * wt.imag); w0.imag = (w0.imag * wt.real) + (w0r * wt.imag); } cmplx w = { 1, 0}; for (size_t j = 0; j < radix; j++) { cmplx wj = w; for (size_t k = 0; k < np; k++) { result[k + j * np] = cmplx_mul_add(f0[k], cmplx_mul_add(f1[k], cmplx_mul_add(f2[k], cmplx_mul_add(f3[k], f4[k], wj), wj), wj), wj); const float wjr = wj.real; wj.real = (wjr * wt.real) - (wj.imag * wt.imag); wj.imag = (wj.imag * wt.real) + (wjr * wt.imag); } const float wr = w.real; w.real = (wr * w0.real) - (w.imag * w0.imag); w.imag = (w.imag * w0.real) + (wr * w0.imag); } free(res);}void fft_radix6(cmplx *input, cmplx *output, size_t n, int flag) { if (n < 2) { memcpy(output, input, sizeof(cmplx) * n); return; } size_t radix = 6; size_t np = n / radix; cmplx *res = (cmplx *) calloc(sizeof(cmplx), n); cmplx *f0 = res; cmplx *f1 = f0 + np; cmplx *f2 = f1 + np; cmplx *f3 = f2 + np; cmplx *f4 = f3 + np; cmplx *f5 = f4 + np; for (size_t i = 0; i < np; i++) { for (size_t j = 0; j < radix; j++) { res[i + j * np] = input[radix * i + j]; } } fft_radix6(f0, f0, np, flag); fft_radix6(f1, f1, np, flag); fft_radix6(f2, f2, np, flag); fft_radix6(f3, f3, np, flag); fft_radix6(f4, f4, np, flag); fft_radix6(f5, f5, np, flag); float wexp0 = -2 * (float) M_PI * (flag) / (float) (n); cmplx wt = {cosf(wexp0), sinf(wexp0)}; cmplx w0 = { 1, 0}; for (size_t i = 0; i < np; i++) { const float w0r = w0.real; w0.real = (w0r * wt.real) - (w0.imag * wt.imag); w0.imag = (w0.imag * wt.real) + (w0r * wt.imag); } cmplx w = { 1, 0}; for (size_t j = 0; j < radix; j++) { cmplx wj = w; for (size_t k = 0; k < np; k++) { output[k + j * np] = cmplx_mul_add(f0[k], cmplx_mul_add(f1[k], cmplx_mul_add(f2[k], cmplx_mul_add(f3[k], cmplx_mul_add( f4[k], f5[k], wj), wj), wj), wj), wj); const float wjr = wj.real; wj.real = (wjr * wt.real) - (wj.imag * wt.imag); wj.imag = (wj.imag * wt.real) + (wjr * wt.imag); } const float wr = w.real; w.real = (wr * w0.real) - (w.imag * w0.imag); w.imag = (w.imag * w0.real) + (wr * w0.imag); } free(res);}void fft_radix7(cmplx *x, cmplx *result, size_t n, int flag) { if (n < 2) { memcpy(result, x, sizeof(cmplx) * n); return; } size_t radix = 7; size_t np = n / radix; cmplx *res = (cmplx *) calloc(sizeof(cmplx), n); cmplx *f0 = res; cmplx *f1 = f0 + np; cmplx *f2 = f1 + np; cmplx *f3 = f2 + np; cmplx *f4 = f3 + np; cmplx *f5 = f4 + np; cmplx *f6 = f5 + np; for (size_t i = 0; i < np; i++) { for (size_t j = 0; j < radix; j++) { res[i + j * np] = x[radix * i + j]; } } fft_radix7(f0, f0, np, flag); fft_radix7(f1, f1, np, flag); fft_radix7(f2, f2, np, flag); fft_radix7(f3, f3, np, flag); fft_radix7(f4, f4, np, flag); fft_radix7(f5, f5, np, flag); fft_radix7(f6, f6, np, flag); float wexp0 = -2 * (float) M_PI * (flag) / (float) (n); cmplx wt = {cosf(wexp0), sinf(wexp0)}; cmplx w0 = { 1, 0}; for (size_t i = 0; i < np; i++) { const float w0r = w0.real; w0.real = (w0r * wt.real) - (w0.imag * wt.imag); w0.imag = (w0.imag * wt.real) + (w0r * wt.imag); } cmplx w = { 1, 0}; for (size_t j = 0; j < radix; j++) { cmplx wj = w; for (size_t k = 0; k < np; k++) { result[k + j * np] = cmplx_mul_add(f0[k], cmplx_mul_add(f1[k], cmplx_mul_add(f2[k], cmplx_mul_add(f3[k], cmplx_mul_add( f4[k], cmplx_mul_add( f5[k], f6[k], wj), wj), wj), wj), wj), wj); const float wjr = wj.real; wj.real = (wjr * wt.real) - (wj.imag * wt.imag); wj.imag = (wj.imag * wt.real) + (wjr * wt.imag); } const float wr = w.real; w.real = (wr * w0.real) - (w.imag * w0.imag); w.imag = (w.imag * w0.real) + (wr * w0.imag); } free(res);}void fft_Bluestein(cmplx *input, cmplx *output, size_t n, int flag) { size_t m = 1 << ((unsigned int) (ilogbf((float) (2 * n - 1)))); if (m < 2 * n - 1) { m <<= 1; } cmplx *y = (cmplx *) calloc(sizeof(cmplx), 3 * m); cmplx *w = y + m; cmplx *ww = w + m; float a0 = (float) M_PI / n; w[0].real = 1; if (flag == -1) { y[0].real = input[0].real; y[0].imag = -input[0].imag; for (size_t i = 1; i < n; i++) { const float wexp = a0 * i * i; w[i].real = cosf(wexp); w[i].imag = sinf(wexp); w[m - i] = w[i]; y[i].real = (input[i].real * w[i].real) - (input[i].imag * w[i].imag); y[i].imag = (-input[i].imag * w[i].real) - (input[i].real * w[i].imag); } } else { y[0].real = input[0].real; y[0].imag = input[0].imag; for (size_t i = 1; i < n; i++) { const float wexp = a0 * i * i; w[i].real = cosf(wexp); w[i].imag = sinf(wexp); w[m - i] = w[i]; y[i].real = (input[i].real * w[i].real) + (input[i].imag * w[i].imag); y[i].imag = (input[i].imag * w[i].real) - (input[i].real * w[i].imag); } } fft_Stockham(y, y, m, 1); fft_Stockham(w, ww, m, 1); for (size_t i = 0; i < m; i++) { const float r = y[i].real; y[i].real = (r * ww[i].real) - (y[i].imag * ww[i].imag); y[i].imag = (y[i].imag * ww[i].real) + (r * ww[i].imag); } fft_Stockham(y, y, m, -1); float scale = 1.0f / m; if (flag == -1) { for (size_t i = 0; i < n; i++) { output[i].real = ((y[i].real * w[i].real) + (y[i].imag * w[i].imag)) * scale; output[i].imag = -((y[i].imag * w[i].real) - (y[i].real * w[i].imag)) * scale; } } else { for (size_t i = 0; i < n; i++) { output[i].real = ((y[i].real * w[i].real) + (y[i].imag * w[i].imag)) * scale; output[i].imag = ((y[i].imag * w[i].real) - (y[i].real * w[i].imag)) * scale; } } free(y);}size_t base(size_t n) { size_t t = n & (n - 1); if (t == 0) { return 2; } for (size_t i = 3; i <= 7; i++) { size_t n2 = n; while (n2 % i == 0) { n2 /= i; } if (n2 == 1) { return i; } } return n;}void FFT(cmplx *input, cmplx *output, size_t n) { memset(output, 0, sizeof(cmplx) * n); if (n < 2) { memcpy(output, input, sizeof(cmplx) * n); return; } size_t p = base(n); switch (p) { case 2: fft_Stockham(input, output, n, 1); break; case 3: fft_radix3(input, output, n, 1); break; case 5: fft_radix5(input, output, n, 1); break; case 6: fft_radix6(input, output, n, 1); break; case 7: fft_radix7(input, output, n, 1); break; default: fft_Bluestein(input, output, n, 1); break; }}void IFFT(cmplx *input, cmplx *output, size_t n) { memset(output, 0, sizeof(cmplx) * n); if (n < 2) { memcpy(output, input, sizeof(cmplx) * n); return; } size_t p = base(n); switch (p) { case 2: fft_Stockham(input, output, n, -1); break; case 3: fft_radix3(input, output, n, -1); break; case 5: fft_radix5(input, output, n, -1); break; case 6: fft_radix6(input, output, n, -1); break; case 7: fft_radix7(input, output, n, -1); break; default: { fft_Bluestein(input, output, n, -1); break; } } float scale = 1.0f / n; for (size_t i = 0; i < n; i++) { output[i].real = output[i].real * scale; output[i].imag = output[i].imag * scale; }}int main() { printf("Fast Fourier Transform\n"); printf("blog: http://cpuimage.cnblogs.com/\n"); printf("A Simple and Efficient FFT Implementation in C"); size_t N = 513; cmplx *input = (cmplx *) calloc(sizeof(cmplx), N); cmplx *output = (cmplx *) calloc(sizeof(cmplx), N); for (size_t i = 0; i < N; ++i) { input[i].real = i; input[i].imag = 0; } for (size_t i = 0; i < N; ++i) { printf("(%f %f) \t", input[i].real, input[i].imag); } for (int i = 0; i < 100; i++) { FFT(input, output, N); } printf("\n"); IFFT(output, input, N); for (size_t i = 0; i < N; ++i) { printf("(%f %f) \t", input[i].real, input[i].imag); } free(input); free(output); getchar(); return 0;}

项目地址:

想了好久都没想到取啥名字好,最后还是选择了cpu这个前缀。

以上,权当抛砖引玉。

若有其他相关问题或者需求也可以邮件联系俺探讨。

邮箱地址是: 

gaozhihan@vip.qq.com

转载于:https://www.cnblogs.com/cpuimage/p/9452536.html

你可能感兴趣的文章
Windows7操作系统安装教程(图文)
查看>>
IOS Core Animation Advanced Techniques的学习笔记(三)
查看>>
除了模拟手术教学,VR在医疗领域如何应用?
查看>>
盘点5款Ubuntu监控工具解决CPU暴增问题
查看>>
java 测试IP
查看>>
用CSS做导航菜单的4个理由
查看>>
NOIP2015 运输计划 二分答案+Tarjan LCA+树上差分
查看>>
构建之法读后感
查看>>
基本信息项目目标文档
查看>>
移动开发Html 5前端性能优化指南
查看>>
silverlight style和template 使用之tip
查看>>
Eclipse配置python环境
查看>>
第十二周总结
查看>>
Import declarations are not supported by current JavaScript version--JavaScript版本不支持导入声明...
查看>>
js兼容性大全
查看>>
晶振不起振的原因及其解决方法
查看>>
学习目标
查看>>
《利用python进行数据分析》学习笔记--数据聚合与分组(groupby)
查看>>
C++中的函数指针模板
查看>>
2015年个人总结
查看>>