经典傅里叶算法小集合 附完整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下数据源开发工 ...
随机推荐
- [翻译] VLDContextSheet
VLDContextSheet 效果: A clone of the Pinterest iOS app context menu. 复制了Pinterest应用的菜单效果. Example Usag ...
- C# 多维数组 交错数组的区别,即 [ , ] 与 [ ][ ]的区别
多维数组的声明 在声明时,必须指定数组的长度,格式为 type [lenght ,lenght ,lengh, ... ] int [,] test1 = new int [3,3]; 或声明时即赋值 ...
- 沉淀,再出发:百度地图api的使用浅思
沉淀,再出发:百度地图api的使用浅思 一.前言 百度地图想必大家都使用过,但是看到别人使用百度地图的API时候是不是一头雾水呢,其实真正明白了其中的意义就像是调用豆瓣电影api的接口一样的简单, ...
- 【2017.10.13 ROS机器人操作系统】ROS系统常用术语及资源
ROS机器人操作系统是一种后操作系统,提供了类似于软件开发中使用到的中间件的功能. ROS: Robot Operating System 机器人操作系统 Package: 功能包 Stack: 功能 ...
- January 07 2017 Week 1st Saturday
Procrastination is the thief of time. 拖延乃是光阴之窃贼. My parents always tell me that things ought to be d ...
- 【[NOI2010]超级钢琴】
我竟然又在写主席树 现在可是九月啦,我却还在写这种noip不可能考的算法 我觉得我真的要凉 题意很明确,就是给你一个序列,让从中选择\(k\)段连续的序列,长度必须大于等于\(L\)小于等于\(R\) ...
- [luogu1979] 华容道
题面 先讲点无关的,这道题是真的恶心... 好了,第一眼看到这道题,肯定是准备暴搜的,但是想了一想,省选难度的题目不可能一上来就让你暴搜吧,于是开启了无穷无尽的分析,我们不妨设指定棋子叫做移动 ...
- 2019.3.26 为什么说HTTP是无状态协议/无连接
无状态 1.协议对于事务处理没有记忆能力 2.对同一个url请求没有上下文关系 3.每次的请求都是独立的,它的执行情况和结果与前面的请求和之后的请求时无直接关系的,它不会受前面的请求应答情况直接影响, ...
- 《metasploit渗透测试魔鬼训练营》学习笔记第六章--客户端渗透
四.客户端攻击 客户端攻击与服务端攻击有个显著不同的标识,就是攻击者向用户主机发送的恶意数据不会直接导致用户系统中的服务进程溢出,而是需要结合一些社会工程学技巧,诱使客户端用户去访问这些恶意 ...
- elk6.*版本搭建连接 比较好一点的
https://www.cnblogs.com/harvey2017/p/8922164.html