开头
在解决信号问题时,可根据FFT(快速傅立叶变换)快速根据单片机ADC获取到的数据进行处理,得到信号的频率和失真度等等信息。以下是我在参加电赛时,通过MSP432Y401单片机进行配置时的FFT配置。
FFT处理数据函数
函数内部一些变量需要外部声明,也可自己根据函数进行更改,个人认为自己更改更有助于自己理解代码的含义。
一些定义:
/* Define for Samples to be captured and Sampling Frequency */
#define NUM_SAMPLES 1024 //采样点数宏定义
#define SAMP_FREQ 64000 //采样频率定义
float Data_Real[NUM_SAMPLES]; //实部
float Data_Image[NUM_SAMPLES]; //虚部
void My_FFT()
{
int i,j,k,m11,k1,ip,m,n,ff1=1;
int l11,l21;
//float l11,l21,t1,t2,pi,w1,w2,v1,v2,d,v11,v22;
float tr,ti,pi,w1,w2,v1,v2,d,v11,v22;
n=NUM_SAMPLES;j=0;m=(int)(log(NUM_SAMPLES)/log(2));
for(i=0;i<=(n-1);i++)
{
if(i>=j) goto L100;
tr=Data_Real[j];
ti=Data_Image[j];
Data_Real[j]=Data_Real[i];
Data_Image[j]=Data_Image[i];
Data_Real[i]=tr;
Data_Image[i]=ti;
L100: k=n/2;
L110: if(j<k||k==0) goto L120;
j=j-k;k=k/2;
goto L110;
L120: j=j+k;
}
for(m11=1;m11<=m;m11++) //for(m11=1;m11<=m1;m11++)
{
l11=(int)pow(2,m11);
// l11=1<<m11;
l21=l11/2;
//pi=3.14159265/l21;
v1=1.0;
v2=0.0;
pi=4.0*atan(1.0)/l21; //add计算圆周率的近似值
w1=cos(pi);
w2=-sin(pi);
for(k1=1;k1<=l21;k1++)//
{
d=ff1*v2;
for(i=(k1-1);i<=(n-1-l11+k1);i+=l11)
{
ip=i+l21;
tr=Data_Real[ip]*v1-Data_Image[ip]*d;//-
ti=Data_Image[ip]*v1+Data_Real[ip]*d;//+
Data_Real[ip]=Data_Real[i]-tr;//-
Data_Image[ip]=Data_Image[i]-ti;//-
Data_Real[i]= Data_Real[i]+tr;//+
Data_Image[i]=Data_Image[i]+ti;//+
}
v11=v1*w1-v2*w2;
v22=v2*w1+v1*w2;
v1=v11;
v2=v22;
}
}
}
处理被FFT数据处理后的数据
ADC采样后的数据通过FFT处理后我们就可以拿来使用了,可以用这些数据进行计算,得到频率、失真度等等信息。
处理函数(供参考,供修改):
/*----------数据处理----------------------------------*/
void Handle()
{
int i;
int Freq_Scle_Value;
float y,Total;
float Vmax;
float V_1KHz,V_2KHz,V_3KHz,V_4KHz,V_5KHz;
/*---------------幅度谱------------------------------*/
for(i=0;i<NUM_SAMPLES;i++)
{
y=sqrt(pow(Data_Real[i],2)+pow(Data_Image[i],2));
Data_Real[i]=y;
//Data_Real[i]=y/2.0;
}
for(i = 0;i < NUM_SAMPLES;i ++)
{
Data_Real[i] = Data_Real[i] / 377;
}
/*-----计算失真度------------------------------------*/
// if(S1_mark==1){
if(state_num == 1 || state_num == 2){
/*--------找幅度谱最大值,计算信号频率---------------------*/
Vmax=Data_Real[1];
for(i=1;i<NUM_SAMPLES/2;i++)
{
if(Vmax<=Data_Real[i]){
Vmax=Data_Real[i];
Freq_Scle_Value=i;
} //end if
}//end for
/*--------计算THD------------------------------------*/
// V_1KHz=Data_Real[2];//4,2
// V_2KHz=Data_Real[4];//8,4
// V_3KHz=Data_Real[6];//12,6
// V_4KHz=Data_Real[8];//16,8
// V_5KHz=Data_Real[10];//20,10
V_1KHz=Data_Real[Freq_Scle_Value*1];//4,2
V_2KHz=Data_Real[Freq_Scle_Value*2];//8,4
V_3KHz=Data_Real[Freq_Scle_Value*3];//12,6
V_4KHz=Data_Real[Freq_Scle_Value*4];//16,8
V_5KHz=Data_Real[Freq_Scle_Value*5];//20,10
Total=pow(V_2KHz,2)+pow(V_3KHz,2)+pow(V_4KHz,2)+pow(V_5KHz,2);
THD=sqrt(Total)/V_1KHz;
Vo_First=V_1KHz;
}
/*-----虚部清零-----------------------------*/
for(i=0;i<NUM_SAMPLES;i++)
Data_Image[i]=0.0;
/*--------通过找幅度谱最大值,计算信号频率-----------------------------*/
if(state_num == 2 | state_num == 3){
Vmax=Data_Real[1];
for(i=1;i<NUM_SAMPLES/2;i++)
{
if(Vmax<=Data_Real[i]){
Vmax=Data_Real[i];
Freq_Scle_Value=i;
} //end if
}//end for 公式:fk = fs/N *k
//Freq=(float)Freq_Scle_Value * 1.00f;//采样率128K
//Freq=(float)Freq_Scle_Value * 0.03125f;//采样率64K 2048
Freq=(float)Freq_Scle_Value * 0.0625f;
//Freq=(float)Freq_Scle_Value * 0.500f;//采样率64K 128
// Freq=(float)Freq_Scle_Value*0.2500;//32KHz
}
}
总结
FFT对于做信号题还是很有用处的,但是理解起来还是非常困难的,也有着更好的FFT数据处理代码,本文章的FFT数据处理代码仅供参考和学习。(代码本人都成功运行,并且运用到了2023年的电赛上。并且获得了奖项)希望大家可以慢慢学习,提升自己的水平。