按时间抽取的基-2 FFT算法 C语言实现(快速傅里叶变换,蝶形算法)

这几天在网上查阅资料,研究了几天的快速傅里叶变换,彻底搞清楚了这怎么一回事。下载过几个版本的fft算法,但计算结果都不尽如人意,所以今天花了一上午时间,照自己的思路实现了fft算法,与dft对比运算结果,发现误差较小。算法依据原理可参照以下文章:FFT快速傅里叶变换(蝶形算法)详解

 以下就分享一下代码咯,思路都体现在源程序的本身结构和注释中。

点击此处直接下载所有代码

part 1,myfft.h(自定义函数声明)

#ifndef __myfft_h
#define __myfft_h

float mysin(float x);
float mycos(float x);
float myfabs(float x);
float mysqrt(float x);
int mypow(int i,int j);
int mylog(int n,int a);

void dft(const float x[],float real[],float imag[],const int n,int isign);


int rev(int i,int m);
void fft(const float real_in[],const float imag_in[],float real_out[],float imag_out[],const int n,int isign);
#endif

part 2,data.h(正弦表)

#ifndef __data_h
#define __data_h

//正弦表
const float sin_tab[360]={//0-359度正弦表
  
  0.000,0.017,0.035,0.052,0.070,0.087,0.105,0.122,0.139,0.156,
  0.174,0.191,0.208,0.225,0.242,0.259,0.276,0.292,0.309,0.326,
  0.342,0.358,0.375,0.391,0.407,0.423,0.438,0.454,0.469,0.485,
  0.500,0.515,0.530,0.545,0.559,0.574,0.588,0.602,0.616,0.629,
  0.643,0.656,0.669,0.682,0.695,0.707,0.719,0.731,0.743,0.755,
  0.766,0.777,0.788,0.799,0.809,0.819,0.829,0.839,0.848,0.857,
  0.866,0.875,0.883,0.891,0.899,0.906,0.914,0.921,0.927,0.934,
  0.940,0.946,0.951,0.956,0.961,0.966,0.970,0.974,0.978,0.982,
  0.985,0.988,0.990,0.993,0.995,0.996,0.998,0.999,0.999,1.000,
  1.000,1.000,0.999,0.999,0.998,0.996,0.995,0.993,0.990,0.988,
  0.985,0.982,0.978,0.974,0.970,0.966,0.961,0.956,0.951,0.946,
  0.940,0.934,0.927,0.921,0.914,0.906,0.899,0.891,0.883,0.875,
  0.866,0.857,0.848,0.839,0.829,0.819,0.809,0.799,0.788,0.777,
  0.766,0.755,0.743,0.731,0.719,0.707,0.695,0.682,0.669,0.656,
  0.643,0.629,0.616,0.602,0.588,0.574,0.559,0.545,0.530,0.515,
  0.500,0.485,0.469,0.454,0.438,0.423,0.407,0.391,0.375,0.358,
  0.342,0.326,0.309,0.292,0.276,0.259,0.242,0.225,0.208,0.191,
  0.174,0.156,0.139,0.122,0.105,0.087,0.070,0.052,0.035,0.017,
  +0.000,-0.017,-0.035,-0.052,-0.070,-0.087,-0.105,-0.122,-0.139,-0.156,
  -0.174,-0.191,-0.208,-0.225,-0.242,-0.259,-0.276,-0.292,-0.309,-0.326,
  -0.342,-0.358,-0.375,-0.391,-0.407,-0.423,-0.438,-0.454,-0.469,-0.485,
  -0.500,-0.515,-0.530,-0.545,-0.559,-0.574,-0.588,-0.602,-0.616,-0.629,
  -0.643,-0.656,-0.669,-0.682,-0.695,-0.707,-0.719,-0.731,-0.743,-0.755,
  -0.766,-0.777,-0.788,-0.799,-0.809,-0.819,-0.829,-0.839,-0.848,-0.857,
  -0.866,-0.875,-0.883,-0.891,-0.899,-0.906,-0.914,-0.921,-0.927,-0.934,
  -0.940,-0.946,-0.951,-0.956,-0.961,-0.966,-0.970,-0.974,-0.978,-0.982,
  -0.985,-0.988,-0.990,-0.993,-0.995,-0.996,-0.998,-0.999,-0.999,-1.000,
  -1.000,-1.000,-0.999,-0.999,-0.998,-0.996,-0.995,-0.993,-0.990,-0.988,
  -0.985,-0.982,-0.978,-0.974,-0.970,-0.966,-0.961,-0.956,-0.951,-0.946,
  -0.940,-0.934,-0.927,-0.921,-0.914,-0.906,-0.899,-0.891,-0.883,-0.875,
  -0.866,-0.857,-0.848,-0.839,-0.829,-0.819,-0.809,-0.799,-0.788,-0.777,
  -0.766,-0.755,-0.743,-0.731,-0.719,-0.707,-0.695,-0.682,-0.669,-0.656,
  -0.643,-0.629,-0.616,-0.602,-0.588,-0.574,-0.559,-0.545,-0.530,-0.515,
  -0.500,-0.485,-0.469,-0.454,-0.438,-0.423,-0.407,-0.391,-0.375,-0.358,
  -0.342,-0.326,-0.309,-0.292,-0.276,-0.259,-0.242,-0.225,-0.208,-0.191,
  -0.174,-0.156,-0.139,-0.122,-0.105,-0.087,-0.070,-0.052,-0.035,-0.017,

};

#endif

 

part 3,myfft.c(主要函数部分)

​
#include "myfft.h"
#include "data.h"
#define PI 3.1415926 


//正弦函数(查表)
float mysin(float x){
  if(x<0)
    return -mysin(-x);
  unsigned long deg=x/PI*180;
  deg%=360;
  return sin_tab[deg];
}
//余弦函数
float mycos(float x){
  return mysin(PI/2-x);
}
//绝对值函数
float myfabs(float x)
{
  return x>=0?x:-x;
}
//开方函数(牛顿迭代法)
float mysqrt(float x)
{
  float val = x;//最终
  float last;//保存上一个计算的值
  do
  {
    last = val;
    val =(val + x/val) / 2;
  }
  while(myfabs(val-last) > 0.01);   //精度控制
  return val;
}
//幂函数 
int mypow(int i,int j){
	int k=1;
	for(;j>0;j--){
		k*=i;
	}
	return k;
}
//对数函数 
int mylog(int n,int a){//x=loga(n)
	int x=0;
	while(n>>=1){
		x++;
	}
	return x;
} 



//离散时间傅里叶变换
void dft(const float x[],float real[],float imag[],const int n,int isign){
	if(isign!=1 && isign!=-1){//isign=1,正变换;isign=-1,逆变换 
		return;
	} 
    int i,j;
    float theta; 
   	for(i=0;i0){
		j+=(i & 0x01)*(0x01 << (m-1));//j+=(i%2)*mypow(2,m-1);
		i>>=1;//i/=2
		m-=1;
	} 
	return j;
}  
//快速傅里叶变换
void fft(const float real_in[],const float imag_in[],float real_out[],float imag_out[],const int n,int isign){
	if(isign!=1 && isign!=-1){//isign=1,正变换;isign=-1,逆变换 
		return;
	} 
	const int Lv=mylog(n,2);//蝶形级数 
	int L;//蝶形运算级数,用于循环
	int N;//蝶形运算数据量,用于循环 
	int distance;//蝶形运算两节点间的距离,用于循环(distance=N/2) 
	int group;//蝶形运算的组数 
	float tmpr1,tmpi1,tmpr2,tmpi2;//临时变量
	int i,j,k;
	for(i=0;i>1;
	for(;L<=Lv;L++){//蝶形循环 
		for(i=0;i>=1;
	} 
} 




​

part 4,main.c(测试部分)

#include 
#include 
#include "myfft.h"
#define Ns 128//采样点数
#define Fs 50//采样频率
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int main(int argc, char *argv[]) {
	int i;
	float xr[Ns],xi[Ns],y1r[Ns],y1i[Ns],y2r[Ns],y2i[Ns];//输入信号和输出信号的实部虚部
	float y1[Ns],y2[Ns];//傅里叶变换结果的幅度 
	for(i=0;i

以上就是所有的源程序文件,使用devc++编译器编译运行结果如下:

按时间抽取的基-2 FFT算法 C语言实现(快速傅里叶变换,蝶形算法)_第1张图片 图1 dft和fft运行结果(1).PNG 按时间抽取的基-2 FFT算法 C语言实现(快速傅里叶变换,蝶形算法)_第2张图片 图2 dft和fft运行结果(2).PNG 按时间抽取的基-2 FFT算法 C语言实现(快速傅里叶变换,蝶形算法)_第3张图片 图3 dft和fft运行结果(3).PNG 按时间抽取的基-2 FFT算法 C语言实现(快速傅里叶变换,蝶形算法)_第4张图片 图4 dft和fft运行结果(4).PNG

两组结果分别是直接使用dft公式计算结果和使用fft算法计算的结果,其中F和A分别指频率和相应的幅度,可以根据两者绘制信号的频谱。fft计算结果与dft计算结果比较接近,说明fft算法足够准确。

                                                                                                                                                                                                 2019/02/24

你可能感兴趣的:(C语言,算法)