搜索
bottom↓
回复: 26

单片机fft和VC的fft计算结果不一样

[复制链接]

出0入0汤圆

发表于 2009-9-22 19:47:23 | 显示全部楼层 |阅读模式
恳请高手帮帮忙。
我用atmega16做32个点的fft。
在vc上算得的数据和单片机算的的数据部不全一样,只有一半是一样的,
已经非常仔细地校对过程序,定义的数据类型都一致,
恳请高手赐教,为何单片机和计算机的fft结果不一致

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2009-9-22 19:57:48 | 显示全部楼层
程序贴出来,不然神仙都难帮你。

出0入0汤圆

 楼主| 发表于 2009-9-22 20:29:58 | 显示全部楼层
/******************************************
//测试系统
//芯片:ATmega16L
//频率:8MHz内频
//电压:3.3V
//软件:ICCAVR
*******************************************/

#include "config.h"
#include "LCD.h"
#include "GUI.h"
#define  PI2  64       
#define  N     64
//uint  adcbuf[N]; //信号实部(8位ad转换结果)
uint   fftbuf[N];
int  wamp[N];
const char  costab[PI2]={
                     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[PI2]={
                        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[N]={
                     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
                                 
                                                                  };
                                                                 
uint  sqrt2(uint  data)//开方
{
uint  s=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[],int  y[],uchar  n)
{//x[]为实部,y[]为虚部(全为0),n为点数
int  tr=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[j];
   x[j]=x;
   x=tr;
   ti=y[j];
   y[j]=y;
   y=ti;
  }//交换x<->x[j],y<->y[j]
  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[qn]+y*sintab[qn])>>7;//由于正余弦表放大128倍,此处缩小128倍
    ti=(y*costab[qn]-x*sintab[qn])>>7;
    p=x[a];
    q=y[a];
        //蝶形运算
    x[a]=(p+tr)>>1;//防止数据溢出
     y[a]=(q+ti)>>1;
     x=(p-tr)>>1;
     y=(q-ti)>>1;
   }
  }
}
}

void getamp(int  x[],int y[],int  wamp[],uint  len)//这里显示虚部+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[1],0);
        //  disdata(25,140,fftbuf[1],0);
             fft((int*)adcbuf,(int*)fftbuf,N);                              //fft 变换
         
          getamp((int*)adcbuf,(int*)fftbuf,(int*)fftbuf,N/2); //求模
         
          
          
  }

出0入0汤圆

发表于 2009-9-22 22:10:13 | 显示全部楼层
单片机int是16bit pc是32bit的

出0入0汤圆

发表于 2009-9-22 22:14:20 | 显示全部楼层
单片机int是16 bit

出0入0汤圆

 楼主| 发表于 2009-9-23 09:47:52 | 显示全部楼层
我把单片机的int型换成long行,unsigned int型换成unsigned long,结果还是不行啊,求高手帮助

出0入0汤圆

 楼主| 发表于 2009-9-23 10:05:33 | 显示全部楼层
结果一致了,单片机的int型是16位的,char型是8位的,计算机的int型是32位的,char型是16位的

出0入0汤圆

发表于 2009-9-28 13:48:07 | 显示全部楼层
/****************************************************
x:输入数据实部,输出数据实部(有符号数)
y:输入数据虚部,输出数据虚部(有符号数)
n:点数
*************************************************/
//void fft(int x[],int y[],int n,uchar sign)
void fft(int x[],int  y[],uchar  n)
{//x[]为实部,y[]为虚部(全为0),n为点数
int  tr=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[j];
   x[j]=x;
   x=tr;  
   ti=y[j];
   y[j]=y;
   y=ti;
  }//交换x<->x[j],y<->y[j]
  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[qn]+y*sintab[qn])>>7; //这里为什么是+?
    ti=(y*costab[qn]-x*sintab[qn])>>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[a];
    q=y[a];
//蝶形运算
    x[a]=(p+tr)>>1;//防止数据溢出
     y[a]=(q+ti)>>1;
     x=(p-tr)>>1;
     y=(q-ti)>>1;
   }
  }  
}
}

出0入0汤圆

发表于 2009-9-30 17:31:21 | 显示全部楼层
明白了。

FFT 旋转角度是负方向,而正弦表里面的值是正方向。

出0入0汤圆

发表于 2010-1-30 21:23:12 | 显示全部楼层
不太明白这个qn=(PI2/n)*c;,PI2 = 64,n = 64,那不是qn=(64/64)*c?

出0入0汤圆

发表于 2010-11-1 14:06:37 | 显示全部楼层
VC的char是16位的?我仿真的时候怎么是8位的?

出0入0汤圆

发表于 2010-11-1 14:11:48 | 显示全部楼层
果然是因为位数的问题,
用单片机做傅立叶变换,高手呀,呵呵

出0入0汤圆

发表于 2010-11-1 14:12:59 | 显示全部楼层
有用就mark!

出0入0汤圆

发表于 2010-11-1 18:19:18 | 显示全部楼层
VC的char肯定是8位的……wchar才是16位的TCHAR根据编译选项或UNICODE宏决定是8位或16位

出0入0汤圆

发表于 2010-11-1 19:55:13 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-11-1 22:18:25 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-11-2 00:39:29 | 显示全部楼层
~

出0入0汤圆

发表于 2010-11-2 01:51:54 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-11-22 16:20:47 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-3-13 14:09:02 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-3-13 14:20:16 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-3-23 16:54:50 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-3-23 19:04:33 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-3-23 20:59:37 | 显示全部楼层
主要是乘法器的问题吧··一个是8位的一个是32位的···以前做算法也遇到过··只不过单片机FFT够呛啊···

出0入0汤圆

发表于 2012-7-25 17:18:10 | 显示全部楼层
留着用到的时候

出0入0汤圆

发表于 2012-11-16 16:07:55 | 显示全部楼层
mark,用得着

出0入0汤圆

发表于 2013-4-13 15:50:02 | 显示全部楼层
最近也在用Atmega16做FFT运算
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-24 03:29

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表