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

基于傅里叶变换的音频重采样算法 (附完整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. Java学习---TCP Socket的学习

    基础知识 1. TCP协议 TCP是一种面向连接的.可靠的.基于字节流的运输层(Transport layer)通信协议.在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能,UDP是同一层 ...

  2. Sybase常用时间日期函数

    Sybase日期函数日期函数getdate()得到当前时间,可以设置得到各种时间格式.datepart(日期部分,日期)取指定时间的某一个部分,年月天时分秒.datediff(日期部分,日期1,日期2 ...

  3. Windows as a Service(1)—— Windows 10服务分支

    前言 作为公司的IT管理员,管理全公司Windows 10操作系统的更新一直是工作中的头疼之处.微软提供了很多方法来帮助我们管理公司的Windows 10更新,比如Windows Server Upd ...

  4. 沉淀再出发:java中注解的本质和使用

    沉淀再出发:java中注解的本质和使用 一.前言 以前XML是各大框架的青睐者,它以松耦合的方式完成了框架中几乎所有的配置,但是随着项目越来越庞大,XML的内容也越来越复杂,维护成本变高.于是就有人提 ...

  5. December 20th 2016 Week 52nd Tuesday

    With the wonder of your love, the sun above always shines. 拥有你美丽的爱情,太阳就永远明媚. To accept the love from ...

  6. Current urgent plan(3/30)

    1. resume improving 1.1 project from Udacity 1.2 project from class 1.3 find career center's help 1. ...

  7. mysql install steps

    the official documents for mysql 5.6 install key steps: # Preconfiguration setup shell> groupadd ...

  8. 英语的各种 n. adj. vt. vi. 等词性解释

    n. 名词 v. 动词(既可作及物动词,也可作不及物动词的就用这个表示) pron. 代词 adj. 形容词(后接名词) adv. 副词(修饰动词.形容词或其他副词) abbr. (这是一个缩写符号) ...

  9. css3—产品列表之鼠标滑过效果

    <!DOCTYPE HTML> <html> <head> <meta charset="UTF-8" /> <title&g ...

  10. JavaScript设计模式之设计原则

    何为设计 即按照哪一种思路或者标准来实现功能,功能相同,可以有不同的设计方案来实现 伴随着需求的增加,设计的作用就会体现出来,一般的APP每天都在变化,更新很快,需求不断在增加,如果设计的不好,后面很 ...