傅里叶变换

正弦特征

正余弦拥有其他信号所不具备的性质:正弦曲线具有保真度(正弦曲线信号输入后,输出的仍是正弦曲线,只有幅度和相位可能发生变化,但是频率和波的形状仍是一样的)

原理

任何连续测量的时序或信号,都可以表示为不同频率的正弦波信号的无限叠加。
在这里插入图片描述
时域信号在经过傅立叶变换的分解之后,变为了多个不同正弦波信号的叠加,我们再去分析这些正弦波的频率。这样就成功将信号时域分析切换到频域分析

对于离散信号(在连续信号上采样得到的信号)的变换只有离散傅立叶变换(DFT)才能被适用,且对于计算机来说只有离散的和有限长度的数据才能被处理。同时计算DFT的复杂度是N^2,而进行FFT(快速傅里叶变换)的运算复杂度是N*log(N)。----> 编程实现的傅里叶变换实际是FFT。

基 2 FFT算法

离散傅里叶变换(DFT)
请添加图片描述
在这里插入图片描述
参考链接: FFT变换-北邮张建华老师
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
傅里叶变换的核心:对输入信号持续进行奇偶二分

FFT总体思路

输入X(n)(时域数据)–>> 序列倒序 -->> 蝶形运算 -->> 输出结果
注:AD采集数据的点数必须为2^n;

编程实现

参考链接: 快速傅里叶变换
Complex.h文件

#ifndef COMPLEX_H
#define COMPLEX_H

#include <math.h>

//声明复数结构体
struct Complex
{
	double real;//实部
	double imag;//虚部
}

//复数相加
Complex Complex_Add(Complex a, Complex b)
{
	Complex ret;
	ret.real = a.real + b.real;
	ret.imag = a.imag + b.imag;
	return ret;
}

//复数相减
Complex Complex_sub(Complex a, Complex b)
{
	Complex ret;
	ret.real = a.real - b.real;
	ret.imag = a.imag - b.imag;
	return ret;
}

//复数相乘
Complex Complex_Mult(Complex a, Complex b)
{
	Complex ret;
	ret.real = a.real*b.real - a.imag*b.imag;
	ret.imag = a.imag*b.real + a.real*b.imag;
	return ret;
}

//复数求模
double Complex_Model(Complex a)
{
	return sqrt(pow(a.real, 2) + pow(a.imag, 2));
}

//将时域数据转换为复数形式表示
//sample:数据转换为复数形式保存
//buf:时域原始数据
//num:原始数据个数
void Complex_Set(Complex *sample, double *buf, int num)
{
	int i;
	for(i = 0;i < num;i++)
	{
		sample[i].real = buf[i];
		sample[i].imag = 0;
	}
}

#endif

FFT.cpp文件

#include <stdio.h>
#include <stdlib.h>
#include "Complex.h"

double PI = 4.0*atan(1);//定义pi,tan(pi/4)=1增加pi的精度
//举例数组
double data[] = {1,2,3,4,5,6,7,8};

void FFTButterfly(double *source, int len)
{
	int i,j,k,l,p;
	int index;//数组下标
	int gap;//间隔
	int increment;//增量
	Complex factor;//旋转因子
	Complex tmp1;//蝶形运算中暂存
	//声明时域数据复数形式存储空间
	Complex *TimeD = (Complex *)malloc(sizeof(Complex)*len);
	//声明序列倒序存储空间 + FFT运算结果存储
	Complex *TimeDInvert = (Complex *)malloc(sizeof(Complex)*len);
	
	//时域数据转为复数形式
	Complex_Set(TimeD, data, len);
	
	//求len点的FFT分级数
	int level = log2(len);
	
	//序列倒序
	for(i = 0; i < len; i++)
	{
		k = 0;
		for(j = 0; j < level; j++)
		{
			if(((i >> j) & 1) == 1)
			{
				k += 1 << (level - j - 1);
			}
		}
		TimeDInvert[k] = TimeD[i];
	}

	//蝶形运算
	for(l = 1;l <= level;l++)
	{
		int gap = int(pow(2, (l - 1)));//间隔
		int increment = int(pow(2, (level - l)));//增量
		for(i = 0;i < increment;i++)//蝶形运算的次数
		{
			for(j = 0;j < gap;j++)//每个蝶形运算的乘法次数
			{
				index = j + 2 * gap * i;//数组下标
				p = j * increment;
				factor.real = cos(2 * PI * p / double(len));
				factor.imag = -sin(2 * PI * p / double(n));
				tmp1 = Complex_Mult(factor, TimeDInvert[index + gap]);
				TimeDInvert[index + gap] = Complex_sub(TimeDInvert[index], tmp1);
				TimeDInvert[index] = Complex_Add(TimeDInvert[index], tmp1);
			}
		}
	}

	//打印结果
	for(i = 0;i < len;i++)
	{
		printf("%.4f ",Complex_Model(TimeDInvert[i]));
		printf("%.4f + ",TimeDInvert[i].real);
		printf("%.4f j\n",TimeDInvert[i].imag);
	}

	free(TimeD);
	free(TimeDInvert);
}

int main()
{
	FFTButterfly(data, sizeof(data)/sizeof(double));
	system("pause");
	return 0;
}

Matlab运算结果
在这里插入图片描述

窗函数

FFT变换是在完美情况下(即认为被处理的信号为周期信号),但在实际情况下AD采集的数据是离散的,对离散数据进行周期扩展时,会出现数据跳变的情况(数据跳变 <–> 相位不连续,相当于引入相位调制)生成额外的频率成分,这种现象称为频谱泄露
窗函数解释: 参考链接
在这里插入图片描述
窗函数C语言实现: 参考链接

使用方法

1)时间窗多项式的样点数与AD采集的数据样本数相同。
2)将时间窗的系数与存放时域数值的数组元素一一相乘。

分帧

链接: 分帧原理
链接: C代码实现

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值