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

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

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

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

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

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

留个作业哈。

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

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

当然各有所长,

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

https://github.com/cpuimage/StockhamFFT

https://github.com/cpuimage/uFFT

https://github.com/cpuimage/BluesteinCrz

https://github.com/cpuimage/fftw3

例如 :

Stockham 是优化速度,

BluesteinCrz 是支持任意长度,

uFFT是经典实现。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

贴上完整算法代码:

#include <stdio.h>
#include <stdbool.h>
#include <math.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h> #ifndef M_PI
#define M_PI 3.14159265358979323846f
#endif typedef 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 >> ;
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 = ; r >= ; r >>= ) {
cmplx *tp = y;
y = tmp;
tmp = tp;
float factor_w = -flag * M_PI / l;
cmplx w = {cosf(factor_w), sinf(factor_w)};
cmplx wj = {, };
for (size_t j = ; j < l; j++) {
size_t jrs = j * (r << );
for (size_t k = jrs, m = jrs >> ; 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 <<= ;
}
memcpy(output, y, sizeof(cmplx) * n);
free(tmp);
free(y);
} void fft_radix3(cmplx *in, cmplx *result, size_t n, int flag) {
if (n < ) {
memcpy(result, in, sizeof(cmplx) * n);
return;
}
size_t radix = ;
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 = ; i < np; i++) {
for (size_t j = ; 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 = - * (float) M_PI * (flag) / (float) (n);
cmplx wt = {cosf(wexp0), sinf(wexp0)};
cmplx w0 = {, };
for (size_t i = ; 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 = {, };
for (size_t j = ; j < radix; j++) {
cmplx wj = w;
for (size_t k = ; 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 < ) {
memcpy(result, x, sizeof(cmplx) * n);
return;
}
size_t radix = ;
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 = ; i < np; i++) {
for (size_t j = ; 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 = - * (float) M_PI * (flag) / (float) (n);
cmplx wt = {cosf(wexp0), sinf(wexp0)};
cmplx w0 = {, };
for (size_t i = ; 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 = {, };
for (size_t j = ; j < radix; j++) {
cmplx wj = w;
for (size_t k = ; 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 < ) {
memcpy(output, input, sizeof(cmplx) * n);
return;
}
size_t radix = ;
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 = ; i < np; i++) {
for (size_t j = ; 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 = - * (float) M_PI * (flag) / (float) (n);
cmplx wt = {cosf(wexp0), sinf(wexp0)};
cmplx w0 = {, };
for (size_t i = ; 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 = {, };
for (size_t j = ; j < radix; j++) {
cmplx wj = w;
for (size_t k = ; 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 < ) {
memcpy(result, x, sizeof(cmplx) * n);
return;
}
size_t radix = ;
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 = ; i < np; i++) {
for (size_t j = ; 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 = - * (float) M_PI * (flag) / (float) (n);
cmplx wt = {cosf(wexp0), sinf(wexp0)};
cmplx w0 = {, };
for (size_t i = ; 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 = {, };
for (size_t j = ; j < radix; j++) {
cmplx wj = w;
for (size_t k = ; 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 = << ((unsigned int) (ilogbf((float) ( * n - ))));
if (m < * n - ) {
m <<= ;
}
cmplx *y = (cmplx *) calloc(sizeof(cmplx), * m);
cmplx *w = y + m;
cmplx *ww = w + m;
float a0 = (float) M_PI / n;
w[].real = ;
if (flag == -) {
y[].real = input[].real;
y[].imag = -input[].imag;
for (size_t i = ; 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[].real = input[].real;
y[].imag = input[].imag;
for (size_t i = ; 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, );
fft_Stockham(w, ww, m, );
for (size_t i = ; 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, -);
float scale = 1.0f / m;
if (flag == -) {
for (size_t i = ; 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 = ; 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 - );
if (t == ) {
return ;
}
for (size_t i = ; i <= ; i++) {
size_t n2 = n;
while (n2 % i == ) {
n2 /= i;
}
if (n2 == ) {
return i;
}
}
return n;
} void FFT(cmplx *input, cmplx *output, size_t n) {
memset(output, , sizeof(cmplx) * n);
if (n < ) {
memcpy(output, input, sizeof(cmplx) * n);
return;
}
size_t p = base(n);
switch (p) {
case :
fft_Stockham(input, output, n, );
break;
case :
fft_radix3(input, output, n, );
break;
case :
fft_radix5(input, output, n, );
break;
case :
fft_radix6(input, output, n, );
break;
case :
fft_radix7(input, output, n, );
break;
default:
fft_Bluestein(input, output, n, );
break;
}
} void IFFT(cmplx *input, cmplx *output, size_t n) {
memset(output, , sizeof(cmplx) * n);
if (n < ) {
memcpy(output, input, sizeof(cmplx) * n);
return;
}
size_t p = base(n);
switch (p) {
case :
fft_Stockham(input, output, n, -);
break;
case :
fft_radix3(input, output, n, -);
break;
case :
fft_radix5(input, output, n, -);
break;
case :
fft_radix6(input, output, n, -);
break;
case :
fft_radix7(input, output, n, -);
break;
default: {
fft_Bluestein(input, output, n, -);
break;
}
}
float scale = 1.0f / n;
for (size_t i = ; 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 = ;
cmplx *input = (cmplx *) calloc(sizeof(cmplx), N);
cmplx *output = (cmplx *) calloc(sizeof(cmplx), N);
for (size_t i = ; i < N; ++i) {
input[i].real = i;
input[i].imag = ;
}
for (size_t i = ; i < N; ++i) {
printf("(%f %f) \t", input[i].real, input[i].imag);
}
for (int i = ; i < ; i++) {
FFT(input, output, N);
}
printf("\n");
IFFT(output, input, N);
for (size_t i = ; i < N; ++i) {
printf("(%f %f) \t", input[i].real, input[i].imag);
}
free(input);
free(output);
getchar();
return ;
}

项目地址:

https://github.com/cpuimage/cpuFFT

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

以上,权当抛砖引玉。

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

邮箱地址是: 
gaozhihan@vip.qq.com

经典傅里叶算法小集合 附完整c代码的更多相关文章

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

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

  2. 音频自动增益 与 静音检测 算法 附完整C代码【转】

    转自:https://www.cnblogs.com/cpuimage/p/8908551.html 前面分享过一个算法<音频增益响度分析 ReplayGain 附完整C代码示例> 主要用 ...

  3. 基于RNN的音频降噪算法 (附完整C代码)

    前几天无意间看到一个项目rnnoise. 项目地址: https://github.com/xiph/rnnoise 基于RNN的音频降噪算法. 采用的是 GRU/LSTM 模型. 阅读下训练代码,可 ...

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

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

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

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

  6. 3D Lut 电影级调色算法 附完整C代码

    在前面的文章,我提到过VSCO Cam 的胶片滤镜算法实现是3d lut. 那么3d lut  到底是个什么东西呢? 或者说它是用来做什么的? 长话短说,3d lut(全称 : 3D Lookup t ...

  7. 自动曝光修复算法 附完整C代码

    众所周知, 图像方面的3A算法有: AF自动对焦(Automatic Focus)自动对焦即调节摄像头焦距自动得到清晰的图像的过程 AE自动曝光(Automatic Exposure)自动曝光的是为了 ...

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

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

  9. Java架构师方案—多数据源开发详解及原理(二)(附完整项目代码)

    1. mybatis下数据源开发工作 2. 数据源与DAO的关系原理模型 3. 为什么要配置SqlSessionTemplate类的bean 4. 多数据源应用测试 1. mybatis下数据源开发工 ...

随机推荐

  1. [翻译] SVProgressHUD

    SVProgressHUD https://github.com/TransitApp/SVProgressHUD SVProgressHUD is a clean and easy-to-use H ...

  2. Linux 下LAMP环境搭建_【all】

    LAMP = Linux + Apache + Mysql + PHP 0. Linux环境搭建 Linux 系统安装[Redhat] 1.http服务软件分类及企业实战用途介绍 静态程序: Apac ...

  3. 沉淀再出发:IoC和AOP的本质

    沉淀再出发:IoC和AOP的本质 一.前言 关于IoC和AOP这两个概念,如果我们没有深入的理解可以说是根本就不理解Spring这个架构的,同样的由Spring演变出来的Spring Boot和Spr ...

  4. Spark shuffle调优

    1:sparkconf.set("spark.shuffle.file.buffer","64K") --不建议使用,因为这么写相当于硬编码2:在conf/sp ...

  5. December 05th 2016 Week 50th Monday

    Today is my birthday and I have totally refreshed. Knowing yourself is the beginning of all wisdom. ...

  6. Spring Security 静态资源访问

    在搞 Spring Security 的时候遇到了一个小坑,就是静态资源加载的问题. 当我们继承了 WebSecurityConfigurerAdapter的时候,会去重写几个方法.去设定我们自己要过 ...

  7. BZOJ 1191 超级英雄Hero 二分图匹配

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1191 题目大意: 现在电视台有一种节目叫做超级英雄,大概的流程就是每位选手到台上回答主 ...

  8. cocos2d::CCFileUtils::sharedFileUtils()->getFileData(szFile, "r", &bufferSize) 不同平台返回值不一样

    string pathKey = CCFileUtils::sharedFileUtils()->fullPathForFilename(fileName); unsigned char* pB ...

  9. Linux学习总结(十五)文件查找 which whereis locate find

    which命令 用于查找并显示给定命令的绝对路径,环境变量PATH中保存了查找命令时需要遍历的目录.which指令会在环境变量$PATH设置的目录里查找符合条件的文件.也就是说,使用which命令,就 ...

  10. 使用iframe标签隐藏CSRF代码

    index.html <iframe src="1.html" width="0" height="0"></iframe ...