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

基于傅里叶变换的音频重采样算法 (附完整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. iOS设计模式 - 外观

    iOS设计模式 - 外观 原理图 说明 1. 当客服端需要使用一个复杂的子系统(子系统之间关系错综复杂),但又不想和他们扯上关系时,我们需要单独的写出一个类来与子系统交互,隔离客户端与子系统之间的联系 ...

  2. Python初学者第二十天 函数(3)-递归函数及练习题

    20day 1.递归的返回值: 递归返回值 2.递归的特性: a.必须有一个明确的结束条件 b.每次进入更深一层递归时,问题规模相比上次递归都应有所减少 c.递归效率不高,递归层次过多会导致栈溢出 3 ...

  3. 猴子选大王【PHP】

    目录 猴子选大王 指针解决 数组压栈 猴子选大王 一群猴子排成一圈,按1,2,...,n依次编号.然后从第1只开始数,数到第m只,把它踢出圈,从它后面再开始数,再数到第m只,在把它踢出去...,如此不 ...

  4. August 24th 2017 Week 34th Thursday

    If you have choices, choose the best. If you have no choice, do the best. 如果有选择,那就选择最好的:如果没有选择,那就努力做 ...

  5. Eclipse和JDK的安装配置

    工欲善其事,必先利其器.最近开始学习Java语言,必不可少的要先安装一个IDE,我选择了eclipse,下面我们讲讲如何来安装及配置. Step1:工具的下载 这里我们需要用到三个工具安装包,JDK. ...

  6. Inno Setup替代默认的背景图片

    一.这是默认的设置生成的安装程序界面. 不行,我要定制!我要换!那么,这两货是从哪里来的呢?既然是默认的就有,那我下意识的来到了inno setup的安装路径下,果然让我发现了. 好了,于是我用我准备 ...

  7. Vue - 如何实现一个双向绑定

    JS - 如何实现一个类似 vue 的双向绑定 Github JS 实现代码 先来看一张图: 这张图我做个简要的描述: 首先创建一个实例对象,分别触发了 compile  解析指令 和 observe ...

  8. sqoop2启动job报错

    set option --name verbose --value true   #打开报错详情输出 Exception has occurred during processing command  ...

  9. cloudstack 用admin 账号创建虚拟机只是提示insufficient resource

    报错: com.cloud.exception.ResourceUnavailableException: Resource [DataCenter:1] is unreachable: Unable ...

  10. python动态调用函数

    callmap = {ts.get_stock_basics: 'D:/dxw/code/all.csv', ts.get_sz50s: 'D:/dxw/code/50.csv', ts.get_hs ...