经典傅里叶算法小集合 附完整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代码的更多相关文章
- 音频自动增益 与 静音检测 算法 附完整C代码
前面分享过一个算法<音频增益响度分析 ReplayGain 附完整C代码示例> 主要用于评估一定长度音频的音量强度, 而分析之后,很多类似的需求,肯定是做音频增益,提高音量诸如此类做法. ...
- 音频自动增益 与 静音检测 算法 附完整C代码【转】
转自:https://www.cnblogs.com/cpuimage/p/8908551.html 前面分享过一个算法<音频增益响度分析 ReplayGain 附完整C代码示例> 主要用 ...
- 基于RNN的音频降噪算法 (附完整C代码)
前几天无意间看到一个项目rnnoise. 项目地址: https://github.com/xiph/rnnoise 基于RNN的音频降噪算法. 采用的是 GRU/LSTM 模型. 阅读下训练代码,可 ...
- 音频降噪算法 附完整C代码
降噪是音频图像算法中的必不可少的. 目的肯定是让图片或语音 更加自然平滑,简而言之,美化. 图像算法和音频算法 都有其共通点. 图像是偏向 空间 处理,例如图片中的某个区域. 图像很多时候是以二维数据 ...
- mser 最大稳定极值区域(文字区域定位)算法 附完整C代码
mser 的全称:Maximally Stable Extremal Regions 第一次听说这个算法时,是来自当时部门的一个同事, 提及到他的项目用它来做文字区域的定位,对这个算法做了一些优化. ...
- 3D Lut 电影级调色算法 附完整C代码
在前面的文章,我提到过VSCO Cam 的胶片滤镜算法实现是3d lut. 那么3d lut 到底是个什么东西呢? 或者说它是用来做什么的? 长话短说,3d lut(全称 : 3D Lookup t ...
- 自动曝光修复算法 附完整C代码
众所周知, 图像方面的3A算法有: AF自动对焦(Automatic Focus)自动对焦即调节摄像头焦距自动得到清晰的图像的过程 AE自动曝光(Automatic Exposure)自动曝光的是为了 ...
- 基于傅里叶变换的音频重采样算法 (附完整c代码)
前面有提到音频采样算法: WebRTC 音频采样算法 附完整C++示例代码 简洁明了的插值音频重采样算法例子 (附完整C代码) 近段时间有不少朋友给我写过邮件,说了一些他们使用的情况和问题. 坦白讲, ...
- Java架构师方案—多数据源开发详解及原理(二)(附完整项目代码)
1. mybatis下数据源开发工作 2. 数据源与DAO的关系原理模型 3. 为什么要配置SqlSessionTemplate类的bean 4. 多数据源应用测试 1. mybatis下数据源开发工 ...
随机推荐
- Java学习---TCP Socket的学习
基础知识 1. TCP协议 TCP是一种面向连接的.可靠的.基于字节流的运输层(Transport layer)通信协议.在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能,UDP是同一层 ...
- Sybase常用时间日期函数
Sybase日期函数日期函数getdate()得到当前时间,可以设置得到各种时间格式.datepart(日期部分,日期)取指定时间的某一个部分,年月天时分秒.datediff(日期部分,日期1,日期2 ...
- Windows as a Service(1)—— Windows 10服务分支
前言 作为公司的IT管理员,管理全公司Windows 10操作系统的更新一直是工作中的头疼之处.微软提供了很多方法来帮助我们管理公司的Windows 10更新,比如Windows Server Upd ...
- 沉淀再出发:java中注解的本质和使用
沉淀再出发:java中注解的本质和使用 一.前言 以前XML是各大框架的青睐者,它以松耦合的方式完成了框架中几乎所有的配置,但是随着项目越来越庞大,XML的内容也越来越复杂,维护成本变高.于是就有人提 ...
- December 20th 2016 Week 52nd Tuesday
With the wonder of your love, the sun above always shines. 拥有你美丽的爱情,太阳就永远明媚. To accept the love from ...
- 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. ...
- mysql install steps
the official documents for mysql 5.6 install key steps: # Preconfiguration setup shell> groupadd ...
- 英语的各种 n. adj. vt. vi. 等词性解释
n. 名词 v. 动词(既可作及物动词,也可作不及物动词的就用这个表示) pron. 代词 adj. 形容词(后接名词) adv. 副词(修饰动词.形容词或其他副词) abbr. (这是一个缩写符号) ...
- css3—产品列表之鼠标滑过效果
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8" /> <title&g ...
- JavaScript设计模式之设计原则
何为设计 即按照哪一种思路或者标准来实现功能,功能相同,可以有不同的设计方案来实现 伴随着需求的增加,设计的作用就会体现出来,一般的APP每天都在变化,更新很快,需求不断在增加,如果设计的不好,后面很 ...