单片机fft和VC的fft计算结果不一样
恳请高手帮帮忙。我用atmega16做32个点的fft。
在vc上算得的数据和单片机算的的数据部不全一样,只有一半是一样的,
已经非常仔细地校对过程序,定义的数据类型都一致,
恳请高手赐教,为何单片机和计算机的fft结果不一致 程序贴出来,不然神仙都难帮你。 /******************************************
//测试系统
//芯片:ATmega16L
//频率:8MHz内频
//电压:3.3V
//软件:ICCAVR
*******************************************/
#include "config.h"
#include "LCD.h"
#include "GUI.h"
#definePI264
#defineN 64
//uintadcbuf; //信号实部(8位ad转换结果)
uint fftbuf;
intwamp;
const charcostab={
127,126,125,122,117,112,105,98,
91,81,71,60,49,37,25,12,0,
-12,-25,-39,-49,-60,-71,-81,-90,
-98,-106,-112,-117,-122,-125,-126,-127,
-126,-126,-122,-117,-112, -106,-98,-90,
-81,-71,-60,-49,-37,-25,-12,0,
12,25,37,49,60,71,81,90,
98,106,112,117,122,125,126
};
const char sintab={
0,12,25,37,49,60,71,81,
90,98,106,112,117,122,125,126,
127,126,125,122,117,112,106,98,
90,81,71,60,49,37,25,12,
0,-12,-25,-37,-49,-60,-71,-81,
-90,-98,-105,-112,-117,-122,-125,-126,
-127,-126,-125,-122,-117,-112,-106,-98,
-90,-81,-71,-60,-49,-39,-25,-12
};
uint adcbuf={
4,5,34,7,67,1,6,13,
45,54,67,7,34,81,1,123,
15,5,5,87,31,1,61,13,
45,4,4,8,23,81,6,3,
4,5,34,7,67,1,6,13,
45,54,67,7,34,81,1,123,
15,5,5,87,31,1,61,13,
45,4,4,8,23,81,6,3
};
uintsqrt2(uintdata)//开方
{
uints=0,i;
for(i=0x80;i>0;i>>=1)
{
s|=i;
if(s*s>data)
s&=~i;
}
return (uint)s;
}
/****************************************************
x:输入数据实部,输出数据实部(有符号数)
y:输入数据虚部,输出数据虚部(有符号数)
n:点数
*************************************************/
//void fft(int x[],int y[],int n,uchar sign)
void fft(int x[],inty[],ucharn)
{//x[]为实部,y[]为虚部(全为0),n为点数
inttr=0;int ti=0;int p=0;int q=0;
uchar i=0;uchar j=0;uchar k=0;uchar qn=0;uchar a=0;
uchar b=0;uchar c=0;uchar cen=0;uchar zu=0;uchar ge=0;
a=n-1;
for(i=0,j=0;i<a;i++)//循环n-1次
{
if(i<j)
{
tr=x;
x=x;
x=tr;
ti=y;
y=y;
y=ti;
}//交换x<->x,y<->y
k=n/2;
while(k<(j+1))
{
j=j-k;
k=k/2;
}
j=j+k;
}//此循环把原序列变成2点奇偶序列
/****************************************/
for(i=1,j=1;i<8;i++)
{
j=2*j;//j=2^p
if(j>=n)break;
}
//2的i次方=n
cen=i; //如果n=8,则cen=3;
zu=n;
for(i=0;i<cen;i++) //层数(0,1,2)
{
zu=zu/2; //组数(4,2,1)
for(j=0;j<zu;j++) //第i 层中的第 j组
{
ge=(n/zu)/2; //一组中蝶形的个数(1,2,4)
for(k=0;k<ge;k++) //第 j 组中的第k个
{ //第 a 和第 b 个元素作蝶形运算,WNC
a=j*ge*2+k; //(0,2,4,6)(0,1,4,5)(0,1,2,3)
b=a+ge; //(ge=1,2,4)
c=k*zu; //(0,0,0,0)(0,2,0,2)(0,1,2,3)
qn=(PI2/n)*c;
//注意sign
tr=(x*costab+y*sintab)>>7;//由于正余弦表放大128倍,此处缩小128倍
ti=(y*costab-x*sintab)>>7;
p=x;
q=y;
//蝶形运算
x=(p+tr)>>1;//防止数据溢出
y=(q+ti)>>1;
x=(p-tr)>>1;
y=(q-ti)>>1;
}
}
}
}
void getamp(intx[],int y[],intwamp[],uintlen)//这里显示虚部+100后的值,与VC上的值只有一半是一样的
{
int i;
//for(i=0;i<len;i++)
//{
//wamp=sqrt2(x*x+y*y)<<2;//开方后放大
//}
for(i=0;i<len;i++)
{
disdata(1+i*16,40,y+100,0);
if(i>14&&i<30)
{
for(i=15;i<30;i++)
{
disdata(1+(i-15)*16,90,y+100,0);
}
}
if(i>29&&i<len)
{
for(i=30;i<len;i++)
{
disdata(1+(i-30)*16,140,y+100,0);
}
}
}
GUI_HLine(20, 98, 236, 0); //画竖线
GUI_HLine(20, 48, 236, 0);
}
//主程序
void main()
{ uchar i;
LCD_Init(); //LCD初始化
GUI_ClearSCR(Black); //清屏
for(i=0;i<N;i++)
{
fftbuf=0; //清信号虚部
}
// disdata(1,140,adcbuf,0);
//disdata(25,140,fftbuf,0);
fft((int*)adcbuf,(int*)fftbuf,N); //fft 变换
getamp((int*)adcbuf,(int*)fftbuf,(int*)fftbuf,N/2); //求模
} 单片机int是16bit pc是32bit的 单片机int是16 bit 我把单片机的int型换成long行,unsigned int型换成unsigned long,结果还是不行啊,求高手帮助 结果一致了,单片机的int型是16位的,char型是8位的,计算机的int型是32位的,char型是16位的 /****************************************************
x:输入数据实部,输出数据实部(有符号数)
y:输入数据虚部,输出数据虚部(有符号数)
n:点数
*************************************************/
//void fft(int x[],int y[],int n,uchar sign)
void fft(int x[],inty[],ucharn)
{//x[]为实部,y[]为虚部(全为0),n为点数
inttr=0;int ti=0;int p=0;int q=0;
uchar i=0;uchar j=0;uchar k=0;uchar qn=0;uchar a=0;
uchar b=0;uchar c=0;uchar cen=0;uchar zu=0;uchar ge=0;
a=n-1;
for(i=0,j=0;i<a;i++)//循环n-1次
{
if(i<j)
{
tr=x;
x=x;
x=tr;
ti=y;
y=y;
y=ti;
}//交换x<->x,y<->y
k=n/2;
while(k<(j+1))
{
j=j-k;
k=k/2;
}
j=j+k;
}//此循环把原序列变成2点奇偶序列
/****************************************/
for(i=1,j=1;i<8;i++)
{
j=2*j;//j=2^p
if(j>=n)break;
}
//2的i次方=n
cen=i; //如果n=8,则cen=3;
zu=n;
for(i=0;i<cen;i++) //层数(0,1,2)
{
zu=zu/2; //组数(4,2,1)
for(j=0;j<zu;j++) //第i 层中的第 j组
{
ge=(n/zu)/2; //一组中蝶形的个数(1,2,4)
for(k=0;k<ge;k++) //第 j 组中的第k个
{ //第 a 和第 b 个元素作蝶形运算,WNC
a=j*ge*2+k; //(0,2,4,6)(0,1,4,5)(0,1,2,3)
b=a+ge; //(ge=1,2,4)
c=k*zu; //(0,0,0,0)(0,2,0,2)(0,1,2,3)
qn=(PI2/n)*c;
//注意sign
tr=(x*costab+y*sintab)>>7; //这里为什么是+?
ti=(y*costab-x*sintab)>>7; //这么为什么是-?
(tr+ I*ti)=(x+I*y) * (cos(q)+ I*sin(q));
实部是tr:x*cos(q) - y*sin(q);
虚部是ti:x*sin(q) + y*cos(q);
????????????????????????????????????
p=x;
q=y;
//蝶形运算
x=(p+tr)>>1;//防止数据溢出
y=(q+ti)>>1;
x=(p-tr)>>1;
y=(q-ti)>>1;
}
}
}
} 明白了。
FFT 旋转角度是负方向,而正弦表里面的值是正方向。 不太明白这个qn=(PI2/n)*c;,PI2 = 64,n = 64,那不是qn=(64/64)*c? VC的char是16位的?我仿真的时候怎么是8位的? 果然是因为位数的问题,
用单片机做傅立叶变换,高手呀,呵呵 有用就mark! VC的char肯定是8位的……wchar才是16位的TCHAR根据编译选项或UNICODE宏决定是8位或16位 mark mark ~ mark mark mark mark mark mark 主要是乘法器的问题吧··一个是8位的一个是32位的···以前做算法也遇到过··只不过单片机FFT够呛啊··· 留着用到的时候 mark,用得着 最近也在用Atmega16做FFT运算
页:
[1]