一、介绍;
最近在做控制中发现,信号的频谱分析是对于做控制的学生或者工作者来说举足轻重。傅立叶变换,说白了,就是将时间域信号转换成频域信号。看待数据问题的方式不同而已。
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