FFT(DFT)-C语言源码

一、介绍;
最近在做控制中发现,信号的频谱分析是对于做控制的学生或者工作者来说举足轻重。傅立叶变换,说白了,就是将时间域信号转换成频域信号。看待数据问题的方式不同而已。
DFT(Discrete Fourier Transform)离散傅立叶变化,在实际应用中99%都是处理离散情况,所以更加需要关注。DFT的计算方式比较简单,理解起来也很容易,这里不做赘述。FFT(Fast Fourier Transform)快速傅立叶变换,目的是提高DFT的计算速度,理论上没有任何创新。
其他作者C代码地址

二、实例;
傅立叶变换、DFT、FFT的理论,需要先自行学习,然后才能看懂代码。
DFT理论介绍
FFT理论介绍
这里直接使用C语言编写的实际例子来进行对比。写的不够严谨,发现问题请指正。
原文如下;这里只针对采样点个数等于:N = 2^M情况,如果N != 2^M,在后面补0凑成2的M次幂即可。

/*Heard Files 头文件---------------------*/
#include  "typedef.h"
#include  <string.h>
#include  <math.h>
#include  <stdlib.h>

/*Mecro Define 宏定义--------------------*/
#define  N    (1<<8)
#define  FS  (1<<8)
#define  F1  ( 4)
#define  F2  (12)


/*Struct&Union 结构体&联合体-------------*/
typedef struct {
	f32  value;
	f32  frq;
	f32  real;
	f32  imag;
	f32  ampl;
} S_POINT;

typedef struct {
	f32  real;
	f32  imag;
} S_COMPLEX;



/*Gloable Veriable 全局变量--------------------*/
S_POINT    g_PointParam[N] = { 0 };
S_COMPLEX  g_FFTParam[N]  = { 0 };
u16        g_FFTNum = 0 ;

/*Internel Veriable 局部变量--------------------*/
S_COMPLEX * pW = 0;

/*Gloable Function 全局函数--------------------*/
void main(void);
void DFT(void);
void FFT(void);


/*Internel Function 内部函数--------------------*/
void  ChangePlace(void);
void  FFTCaculate(void);
void  ComplexMul(S_COMPLEX Target1 , S_COMPLEX Target2 , S_COMPLEX * pResult );
void  ComplexAdd(S_COMPLEX Target1, S_COMPLEX Target2  , S_COMPLEX * pResult );
void  ComplexSub(S_COMPLEX Target1, S_COMPLEX Target2  , S_COMPLEX * pResult );





/**************************************************
*函数名称:void main(void)
*输入:无
*输出:无
*备注:2020-02-16
**************************************************/
void main(void) 
{
	printf("start\n");

	DFT();
	FFT();
	while (1) {
		;
	}
}



/**************************************************
*函数名称:void DFT(void)
*输入:无
*输出:无
*备注:2020-02-16
**************************************************/
void DFT(void)
{
	//0.0  局部变量
	u16  i = 0;
	u16  j = 0;

	//1.0  开始标志
	printf("FDT\n");

	//2.0  参数复位
	memset(g_PointParam, 0, sizeof(S_POINT)*N);

	//1.0  输入参数
	for ( i = 0; i < N; i++) {
		g_PointParam[i].value = 10*sin( 2*PI*F1*i/FS ) + 10 * sin(2 * PI*F2*i / FS);
	}

	//2.0  计算DFT
	for (i = 0; i < N; i++) {
		g_PointParam[i].real = 0;
		g_PointParam[i].imag = 0;
		g_PointParam[i].ampl = 0;
		for (j = 0; j < N; j++) {
			g_PointParam[i].real += g_PointParam[j].value * cos(2 * PI / N*i*j);
			g_PointParam[i].imag -= g_PointParam[j].value * sin(2 * PI / N*i*j);
		}
		g_PointParam[i].ampl = sqrt(g_PointParam[i].real*g_PointParam[i].real + g_PointParam[i].imag*g_PointParam[i].imag);
		g_PointParam[i].frq  = (f32)i * FS / N;
	}

	//3.0  结果打印
	for (i = 0; i < N/2; i++) {
		printf("N= %d,Frq =%0.1f,AMP =%0.1f\n", i, g_PointParam[i].frq, g_PointParam[i].ampl);
	}
}




/**************************************************
*函数名称:void FFT(void)
*输入:无
*输出:无
*备注:2020-02-16
**************************************************/
void FFT(void)
{
	//0.0  局部变量
	u16  i = 0;
	u16  j = 0;
	f32 mReultFrq ;
	f32 mReultAmp ;

	//1.0  开始标志
	printf("FFT\n");

	//2.0  参数复位
	memset(g_FFTParam, 0, sizeof(S_COMPLEX)*N);

	//1.0  输入参数
	for (i = 0; i < N; i++) {
		g_FFTParam[i].real = 10 * sin(2 * PI*F1*i / FS) + 10 * sin(2 * PI*F2*i / FS);
		g_FFTParam[i].imag = 0 ;
	}
	pW = (S_COMPLEX *)malloc(sizeof(S_COMPLEX) * N);  // 保存 ( cos(2*pi/N*i) - j sin(2*pi/N*i) )计算值

	//2.0  计算器W值
	for (i = 0; i < N; i++) {
		pW[i].real =  cos(2 * PI / N * i);
		pW[i].imag = -sin(2 * PI / N * i);
	}

	//3.0  计算FFT蝶形层数
	g_FFTNum = log2(N);

	//4.0  原数据交换位置,推到过程与交换规则可以百度
	ChangePlace();

	//5.0  计算FFT值
	FFTCaculate();

	//6.0  输出结果
	for ( i = 0; i < N / 2; i++) {
		mReultFrq = (f32)i * FS / N;
		mReultAmp = sqrt(g_FFTParam[i].real*g_FFTParam[i].real + g_FFTParam[i].imag*g_FFTParam[i].imag);
		printf("N= %d,Frq =%0.1f,AMP =%0.1f\n", i, mReultFrq , mReultAmp);
	}
}



/**************************************************
*函数名称:void  ChangePlace(void)
*输入:无
*输出:无
*备注:2020-02-16
**************************************************/
void  ChangePlace(void)
{
	//0.0  局部变量定义
	u16 mNowNum = 0 ;
	u16 j = 0;
	u16 mChangeNum  = 0;
	S_COMPLEX mTemp = {0};

	//1.0  循环查看搜索原序列数据
	for ( mNowNum = 0 ; mNowNum < N; mNowNum++) {
		mChangeNum = 0 ;
		
		for (j = 0; j < g_FFTNum; j++) {    // 每bit位轮流判断是否为1
			if ( (mNowNum&(1 << j)) == (1 << j) ) { // 当前Bit等于1
				mChangeNum += 1 << (g_FFTNum - 1 - j);
			}
		}

		if ( mChangeNum > mNowNum ) {       // 一组数据仅交换一次
			mTemp = g_FFTParam[mChangeNum];
			g_FFTParam[mChangeNum] = g_FFTParam[mNowNum];
			g_FFTParam[mNowNum]    = mTemp;
		}
	}
}


/**************************************************
*函数名称:void  FFTCaculate(void)
*输入:无
*输出:无
*备注:2020-02-16
**************************************************/
void  FFTCaculate(void)
{
	u16  mNowLayerTick = 0; // 层数计数器
	u16  mButterflyContinuNum = 0; // 碟型连续乘法次数
	u16  mButterflyTick = 0;// 碟型计数器
	u16  mButterflyContinuTick = 0;// 碟型连续乘法计数器
	S_COMPLEX  mTemp = {0};

	//1.0  循环层次
	for (mNowLayerTick = 0; mNowLayerTick < g_FFTNum ; mNowLayerTick++) {
		mButterflyContinuNum = 1 << mNowLayerTick; // 1个碟型连续计算次数
		for (mButterflyTick = 0; mButterflyTick < N; mButterflyTick += mButterflyContinuNum * 2) { // 碟型个数循环
			for ( mButterflyContinuTick = 0 ; mButterflyContinuTick < mButterflyContinuNum ; mButterflyContinuTick ++) {// 当前碟型内部计算
				ComplexMul( g_FFTParam[ mButterflyTick + mButterflyContinuTick + mButterflyContinuNum], pW[ mButterflyContinuTick * (1<<( g_FFTNum - 1 -  mNowLayerTick))], &mTemp );
				ComplexSub( g_FFTParam[ mButterflyTick + mButterflyContinuTick ], mTemp , &g_FFTParam[mButterflyTick + mButterflyContinuTick + mButterflyContinuNum] );
				ComplexAdd( g_FFTParam[mButterflyTick + mButterflyContinuTick]  , mTemp , &g_FFTParam[mButterflyTick + mButterflyContinuTick] );	
			}
		}
	}
}



/**************************************************
*函数名称:void  ComplexMul(S_COMPLEX Target1 , S_COMPLEX Target2 , S_COMPLEX * pResult );
*输入:无
*输出:无
*备注:2020-02-16
**************************************************/
void  ComplexMul(S_COMPLEX Target1, S_COMPLEX Target2, S_COMPLEX * pResult)
{
	pResult->real = Target1.real * Target2.real - Target1.imag * Target2.imag;
	pResult->imag = Target1.real * Target2.imag + Target2.real * Target1.imag;
}

/**************************************************
*函数名称:void  ComplexAdd(S_COMPLEX Target1 , S_COMPLEX Target2 , S_COMPLEX * pResult );
*输入:无
*输出:无
*备注:2020-02-16
**************************************************/
void  ComplexAdd(S_COMPLEX Target1, S_COMPLEX Target2, S_COMPLEX * pResult)
{
	pResult->real = Target1.real + Target2.real ;
	pResult->imag = Target1.imag + Target2.imag ;
}


/**************************************************
*函数名称:void  ComplexSub(S_COMPLEX Target1 , S_COMPLEX Target2 , S_COMPLEX * pResult );
*输入:无
*输出:无
*备注:2020-02-16
**************************************************/
void  ComplexSub(S_COMPLEX Target1, S_COMPLEX Target2, S_COMPLEX * pResult)
{
	pResult->real = Target1.real - Target2.real;
	pResult->imag = Target1.imag - Target2.imag;
}

附录文件:h文件,帮助对C不熟悉的朋友。

/**********************************************
*文件名称:typedef.h
*文件内容:定义工程中的通用类型
*备    注:2020-02-16 wangli
***********************************************/
#pragma once
#ifndef  TYPE_DEF_H
#define  TYPE_DEF_H
/*Heard Files 头文件 ---------------------------------------*/
#include <stdio.h>

/*Macro Define 宏定义 ---------------------------------------*/
#define  PI  (3.1415)

/*struct&union 结构体&union等定义 --------------------------*/
typedef unsigned char   u8  ;
typedef signed char     s8  ;
typedef unsigned short  u16 ;
typedef signed short    s16 ;
typedef unsigned int    u32 ;
typedef signed int      s32 ;
typedef unsigned long   u64 ;
typedef signed long     s64 ;
typedef float           f32 ;
typedef double          f64 ;



#endif
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值