目录

  • 源码
    • FFT.c
    • FFT.h
  • 使用方法
    • 初始化
    • 输入数据
    • FFT 快速傅里叶变换
    • 解算FFT结果
      • 使用python绘制FFT波形
    • IFFT 快速傅里叶逆变换
    • 解算IFFT结果

Windows 10 20H2
Visual Studio 2015
Python 3.8.12 (default, Oct 12 2021, 03:01:40) [MSC v.1916 64 bit (AMD64)] :: Anaconda, Inc. on win32


小改自用于ARM上的FFT与IFFT源代码(C语言,不依赖特定平台)—— syrchina V6.55版,其V6.6版改用了动态内存分配,可能不适用于部分单片机平台。

要使用窗函数处理,见常见窗函数的C语言实现及其形状,适用于单片机、DSP作FFT运算

经过仔细阅读和测试,syrchina大佬的版本(2011.05.22)应该是优化自吉帅虎大佬的版本(2010.2.20),主要是优化了查表和蝶形算法的部分,在VS2015中Debug模式下计算一轮1024点的FFT足足快了几乎一倍,且它们的输出结果是一样的。syrchina大佬的版本附有IFFT的算法,故这里稍作修改,做个记录,供以后使用。
吉帅虎版

syrchina版

源码

FFT.c

#include "FFT.h"Complex data_of_N_FFT[FFT_N];          //定义存储单元,原始数据与复数结果均使用之
double SIN_TABLE_of_N_FFT[FFT_N / 4 + 1];//创建正弦函数表 初始化FFT程序
void Init_FFT(void)
{int i;for (i = 0; i <= FFT_N / 4; i++){SIN_TABLE_of_N_FFT[i] = sin(2 * i * PI / FFT_N);}
}double Sin_find(double x)
{int i = (int)(FFT_N * x); //注意:i已经转化为0~N之间的整数了! i = i >> 1;                  // i = i / 2;if (i > FFT_N / 4){    //根据FFT相关公式,sin()参数不会超过PI, 即i不会超过N/2 i = FFT_N / 2 - i;//i = i - 2*(i-Npart4);}return SIN_TABLE_of_N_FFT[i];
}double Cos_find(double x)
{int i = (int)(FFT_N*x);//注意:i已经转化为0~N之间的整数了! i = i >> 1;if (i < FFT_N / 4){ //不会超过N/2 return SIN_TABLE_of_N_FFT[FFT_N / 4 - i];}else //i > Npart4 && i < N/2 {return -SIN_TABLE_of_N_FFT[i - FFT_N / 4];}
}//变址
void ChangeSeat(Complex *DataInput)
{int nextValue, nextM, i, k, j = 0;Complex temp;nextValue = FFT_N / 2;                    //变址运算,即把自然顺序变成倒位序,采用雷德算法nextM = FFT_N - 1;for (i = 0; i < nextM; i++){if (i < j)                           //如果i<j,即进行变址{temp = DataInput[j];DataInput[j] = DataInput[i];DataInput[i] = temp;}k = nextValue;                        //求j的下一个倒位序while (k <= j)                       //如果k<=j,表示j的最高位为1{j = j - k;                      //把最高位变成0k = k / 2;                        //k/2,比较次高位,依次类推,逐个比较,直到某个位为0}j = j + k;                          //把0改为1}
}//FFT运算函数
void FFT(void)
{int L = FFT_N, B, J, K, M_of_N_FFT;int step, KB;double angle;Complex W, Temp_XX;ChangeSeat(data_of_N_FFT);                //变址 //CREATE_SIN_TABLE();for (M_of_N_FFT = 1; (L = L >> 1) != 1; ++M_of_N_FFT); //计算蝶形级数for (L = 1; L <= M_of_N_FFT; L++){step = 1 << L;                      //2^LB = step >> 1;                      //B=2^(L-1)for (J = 0; J < B; J++){//P = (1<<(M-L))*J;//P=2^(M-L) *J angle = (double)J / B;         //这里还可以优化 W.real = Cos_find(angle);        //使用C++时该函数可声明为inline W.real =  cos(angle*PI);W.imag = -Sin_find(angle);        //使用C++时该函数可声明为inline W.imag = -sin(angle*PI);for (K = J; K < FFT_N; K = K + step){KB = K + B;//Temp_XX = XX_complex(data[KB],W); 用下面两行直接计算复数乘法,省去函数调用开销 Temp_XX.real = data_of_N_FFT[KB].real * W.real - data_of_N_FFT[KB].imag*W.imag;Temp_XX.imag = W.imag*data_of_N_FFT[KB].real + data_of_N_FFT[KB].imag*W.real;data_of_N_FFT[KB].real = data_of_N_FFT[K].real - Temp_XX.real;data_of_N_FFT[KB].imag = data_of_N_FFT[K].imag - Temp_XX.imag;data_of_N_FFT[K].real = data_of_N_FFT[K].real + Temp_XX.real;data_of_N_FFT[K].imag = data_of_N_FFT[K].imag + Temp_XX.imag;}}}
}//IFFT运算函数
void IFFT(void)
{int L = FFT_N, B, J, K, M_of_N_FFT;int step, KB;double angle;Complex W, Temp_XX;ChangeSeat(data_of_N_FFT);//变址 for (M_of_N_FFT = 1; (L = L >> 1) != 1; ++M_of_N_FFT);  //计算蝶形级数for (L = 1; L <= M_of_N_FFT; L++){step = 1 << L;                      //2^LB = step >> 1;                      //B=2^(L-1)for (J = 0; J<B; J++){angle = (double)J / B;         //这里还可以优化  W.real = Cos_find(angle);       //使用C++时该函数可声明为inline W.real = cos(angle*PI);W.imag = Sin_find(angle);      //使用C++时该函数可声明为inline W.imag = sin(angle*PI);for (K = J; K < FFT_N; K = K + step){KB = K + B;//用下面两行直接计算复数乘法,省去函数调用开销 Temp_XX.real = data_of_N_FFT[KB].real * W.real - data_of_N_FFT[KB].imag*W.imag;Temp_XX.imag = W.imag*data_of_N_FFT[KB].real + data_of_N_FFT[KB].imag*W.real;data_of_N_FFT[KB].real = data_of_N_FFT[K].real - Temp_XX.real;data_of_N_FFT[KB].imag = data_of_N_FFT[K].imag - Temp_XX.imag;data_of_N_FFT[K].real = data_of_N_FFT[K].real + Temp_XX.real;data_of_N_FFT[K].imag = data_of_N_FFT[K].imag + Temp_XX.imag;}}}
}/*****************************************************************
函数原型:void Refresh_Data(int id, double wave_data)
函数功能:更新数据
输入参数:id: 标号; wave_data: 一个点的值
输出参数:无
*****************************************************************/
void Refresh_Data(int id, double wave_data)
{data_of_N_FFT[id].real = wave_data;data_of_N_FFT[id].imag = 0;
}

FFT.h

#ifndef FFT_H_
#define FFT_H_#include <math.h>#define PI             3.14159265358979323846264338327950288419716939937510    //圆周率#define FFT_N          1024        //傅里叶变换的点数 #define FFT_RESULT(x)    (sqrt(data_of_N_FFT[x].real*data_of_N_FFT[x].real+data_of_N_FFT[x].imag*data_of_N_FFT[x].imag)/ (FFT_N >> (x != 0)))
#define FFT_Hz(x, Sample_Frequency)     ((double)(x * Sample_Frequency) / FFT_N)#define IFFT_RESULT(x)  (data_of_N_FFT[x].real / FFT_N)typedef struct                       //定义复数结构体
{double real, imag;
}Complex;extern Complex data_of_N_FFT[];
extern double SIN_TABLE_of_N_FFT[];void Init_FFT(void);
void FFT(void);
void IFFT(void);
void Refresh_Data(int id, double wave_data);#endif // !FFT_H_

使用方法

初始化

在FFT.h中修改FFT的点数

由于FFT变换归一化后,除了0Hz直流分量外,整个结果表是对称的,即若点数为1024,则我们只看前512个点即可,所以这个傅里叶变换的点数可根据你的屏幕长方向上的像素数来决定,如128x64的屏幕可以考虑使用256点的FFT。

#define FFT_N            1024        //傅里叶变换的点数

初始化一遍,生成正弦表

Init_FFT();          //①初始化各项参数,此函数只需执行一次 ; 修改FFT的点数去头文件的宏定义处修改

输入数据

这里设采样频率为100Hz,产生一个0~5V,10Hz方波

void Refresh_Data(int id, double wave_data);

 #define Sample_Frequency 100for (i = 0; i < FFT_N; i++)//制造输入序列 {if (sin(2 * PI * 10 * i / Sample_Frequency) > 0)Refresh_Data(i, 5);else if (sin(2 * PI * 10 * i / Sample_Frequency) < 0)Refresh_Data(i, 0);elseRefresh_Data(i, 2.5);}

FFT 快速傅里叶变换

FFT();               //③进行 FFT计算

解算FFT结果

使用 FFT_Hz (i, Sample_Frequency) 获取该点频率
使用 FFT_RESULT (i) 获取该点模值

由于FFT结果是对称的,故只需看前FFT_N / 2个点

我这里为了看波形用C++跑的,将生成的坐标保存进out.txt中

#include <iostream>
#include <fstream>
using namespace std;
 ofstream out;out.open("out.txt");for (int i = 0; i < FFT_N / 2; ++i){out << FFT_Hz(i, Sample_Frequency) << " " << FFT_RESULT(i) << endl;}out.close();

使用python绘制FFT波形

import matplotlib.pyplot as pltx = []
y = []with open(r'D:\out.txt的路径\out.txt') as TXT_File:for line in TXT_File:tmp = line.split()x.append(float(tmp[0]))y.append(float(tmp[1]))fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(x, y)
plt.show()

IFFT 快速傅里叶逆变换

 IFFT();//进行 IFFT计算

解算IFFT结果

使用 IFFT_RESULT (i) 读取每个点的波形

我这里同样为了看波形将生成的坐标保存进out1.txt中

 ofstream out1;out1.open("out1.txt");for (int i = 0; i < FFT_N; ++i){out1 << i << " " << IFFT_RESULT(i) << endl;}out1.close();

可以看到,又转变回0~5V的方波了,故也许可以FFT后直接对特定频率的信号处理再逆变换回去,实现滤波。

C语言实现的FFT与IFFT源代码,不依赖特定平台相关推荐

  1. c语言ifft,用于ARM上的FFT与IFFT源代码-C语言

    /******************************************************************************* ** 程序名称:快速傅里叶变换(FFT ...

  2. 二维C语言,二维FFT,IFFT,c语言实现

    [VC++技术杂谈003]打印技术之打印机状态监控 在上一篇博文中我主要介绍了如何获取以及设置系统的默认打印机,本文将介绍如何对打印机状态进行实时监控,记录下所打印的文档.打印的份数以及打印时间等打印 ...

  3. matlab的fft与ifft,fft与ifft区别

    OFDM是如何利用FFT和IFFT技术实现的_信息与通信_工程科技_专业资料.1.LTE 在广义上说只有一个载波,FDD 是上行和下行的载波分配在不同的频点,TDD 是在 同一个...... Matl ...

  4. c代码实现 ifft运算_X^n+1=0上的FFT和IFFT(基2)——C语言实现

    我们一般意义上学习的FFT都是基于 的,即FFT中的单位根我们取的是 ,但是在某些情况下我们需要 上的FFT和IFFT变换. 1.直接想到的思路是把 的根替换成 的根. 解法: 的根可以使用 的2n个 ...

  5. C语言实现FFT or IFFT

    C语言实现FFT or IFFT matlab实现 仿真结果 C语言实现 仿真结果 matlab实现 close all; clear all; clc;count=2; y=[1+2i,2+3i]; ...

  6. C语言实现FFT和IFFT,并与MATLAB编写显示的结果相对比,进行验证(蝶形运算)

    本次实验中在Microsoft Visual Studio 2010环境下编写,实现FFT和IFFT,并用MATLAB编写显示的结果,两者相对比,进行验证. #include "stdafx ...

  7. Python实现FFT及IFFT

    运行环境及编译工具 Windows VS Code 编程语言及库版本 库 版本 Python 3.7.0 copy 无 numpy 1.19.2 opencv 3.4.2 PIL 8.1.0 matp ...

  8. MKL只会矩阵运算?快来看看它的FFT和IFFT!

    MKL的FFT和IFFT实现 MKL是Intel公司推出的一项数学库,其功能主要是用于加速矩阵运算等.最近的工作中接触到了MKL. 但你以为MKL除了加速处理矩阵就啥也不会了么? 非也!它甚至可以进行 ...

  9. TMS320C6455二维FFT和IFFT实现

    目录 FFT原理简介 DSPLib配置 图像数据生成 DSPLib中的FFT和IFFT 二维FFT和IFFT实现 图像分析工具(Image Analyzer) 测试结果 相关资源链接 参考资料: Ra ...

最新文章

  1. Python Day Eleven
  2. ActivityRouter
  3. 离散数学及其应用上的一个问题
  4. 我犯的错误--关于数据库类型不对
  5. 如何卸载mysql重新安装win10_学以致用二十八-----win10安装mysql5.7.24及卸载
  6. 解决 Script Error 的另类思路
  7. 7.2. cvs login | logout
  8. CPUID — CPU Identification
  9. 6 万出头的北京房价,程序员如何靠自己安家?
  10. ThreadLocal到底是什么,尚硅谷docker高级
  11. 引用、取址运算符、解引用运算符——傻傻分不清楚
  12. 蓝桥杯 ADV-90 算法提高 输出日历
  13. 没事学学docker(三):配置阿里云镜像加速以及解决docker起不来的问题
  14. 浅谈JavaScript--闭包
  15. 入驻三年,Airbnb在中国做了什么?
  16. 如何找到win10系统当前使用的壁纸位置
  17. 产品| 产品白皮书(待更新)
  18. HBase进化之从NoSQL到NewSQL,凤凰涅槃成就Phoenix
  19. yiyuan编程电子书系列(目录及种子)
  20. 燃气爆炸竟然是这个四个原因?

热门文章

  1. 中国移动IM-飞信-0802上线新版本 试用手记
  2. Android二维码之创建
  3. rabbitmq 不同的消费者消费同一个队列_RabbitMQ 消费端限流、TTL、死信队列
  4. 支撑阻力指标_使用k表示聚类以创建支撑和阻力
  5. 在Java里怎将字节数转换为我们可以读懂的格式?
  6. leetcode201. 数字范围按位与
  7. leetcode1143. 最长公共子序列(动态规划)
  8. 前端开发有哪些技术栈要掌握_为什么要掌握前端开发的这四个主要概念
  9. hexo博客添加暗色模式_我如何向网站添加暗模式
  10. ux设计师怎样找同类产品_没有预算? 别找借口。 便宜的UX上的UX 2:让我们开始构建。...