打印

关于CCS软件实现FFT

[复制链接]
7002|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
jiaojinijn|  楼主 | 2014-5-13 14:14 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
沙发
ttxs_2013| | 2014-5-13 21:09 | 只看该作者
建议你 看看 ,高西全、丁玉美编写的《数字信号处理》(西安电子科技大学出版社  第三版 )书中FFT运算规律及编程思想,结合C代码,看懂了之后,你就明白了。

以下是 FFT实现的官方例程((思想都是一样的,可能在C 代码的实现有些不同),我这几天也在学,中文注释都是自己加的,蝶形运算的部分和makewave这两个地方还没想明白,你可以参考下,注释不一定完全准确,希望相互探讨下!
************************************************************************************************************************************************************************
#include "myapp.h"
#include "csedu.h"
#include "scancode.h"
#include <math.h>

#define PI 3.1415926
#define SAMPLENUMBER 128

void InitForFFT();
void MakeWave();

int INPUT[SAMPLENUMBER],DATA[SAMPLENUMBER];
float fWaveR[SAMPLENUMBER],fWaveI[SAMPLENUMBER],w[SAMPLENUMBER];
float sin_tab[SAMPLENUMBER],cos_tab[SAMPLENUMBER];

main()
{
        int i;
       
        InitForFFT();
        MakeWave();
        for ( i=0;i<SAMPLENUMBER;i++ )
        {
                fWaveR[i]=INPUT[i];
                fWaveI[i]=0.0f;
                w[i]=0.0f;
        }
        FFT(fWaveR,fWaveI);//地址传递,数组首地址传递给dataR[128],dataI[128]
        for ( i=0;i<SAMPLENUMBER;i++ )
        {
                DATA[i]=w[i];
        }
        while ( 1 );        // break point
}
      
void FFT(float dataR[SAMPLENUMBER],float dataI[SAMPLENUMBER])
{
        int x0,x1,x2,x3,x4,x5,x6,xx;
        int i,j,k,b,p,L;
        float TR,TI,temp;
       
        /********** following code invert sequence ************/
        /*位倒序算法:128点FFT可用7位二进制表示顺序数,这里依次为x6-x0(高到低)
          x0到x6依次与0x01相与,得到顺序数i用7位二进制表示,xx则是计算倒序二进制的十进制数
          dataR数组是存放顺序数的(输入),dataI数组则是存放倒序数的
          注意 i/(2,4,8,16等)相当于i二进制右移1,2,3,4位等*/
        for ( i=0;i<SAMPLENUMBER;i++ )
        {
                x0=x1=x2=x3=x4=x5=x6=0;
                x0=i&0x01; x1=(i/2)&0x01; x2=(i/4)&0x01; x3=(i/8)&0x01;x4=(i/16)&0x01; x5=(i/32)&0x01; x6=(i/64)&0x01;
                xx=x0*64+x1*32+x2*16+x3*8+x4*4+x5*2+x6;
                dataI[xx]=dataR[i];   //dataIa 数组中存放的就是位倒序后的值     
        }
        for ( i=0;i<SAMPLENUMBER;i++ )
        {
                dataR[i]=dataI[i]; dataI[i]=0; //把位倒序数组中的值逐位的赋值给原输入数组,这样就少用一个数组
        }

        /************** following code FFT *******************/
        for ( L=1;L<=7;L++ )        //第一层循环:蝶形的级数
        { /* for(1) */         
                b=1; i=L-1;
                while ( i>0 )  
                {
                        b=b*2; i--;
                } /* b= 2^(L-1) */
       //第二层循环:获得旋转因子 P,第L级有2的(L-1)个不同的旋转因子,同时要计算每一个旋转因子对应的蝶形
                for ( j=0;j<=b-1;j++ ) /* for (2) */  
                {
                        p=1; i=7-L;
                        while ( i>0 ) /* p=pow(2,7-L)*j; */
                        {
                                p=p*2; i--;
                        }
                        p=p*j;
         /*第三层循环:计算蝶形 ,第L级旋转因子的个数同每一级中每个蝶形的两个输入数据相差的点数 相同*/
                 /*实际上这里b的值每一级中都是固定的,与循环的次数并没有关系*/
                        for ( k=j;k<128;k=k+2*b ) /* for (3) */
                        {
                                TR=dataR[k]; //已经是位倒序过了
                                TI=dataI[k]; // dataI中数据都赋值为0了,这里还有什么作用?
                                temp=dataR[k+b]; // temp是蝶形中另一个输入
                         /****************************************************************/
                                dataR[k]=dataR[k]+dataR[k+b]*cos_tab[p]+dataI[k+b]*sin_tab[p];
                                dataI[k]=dataI[k]-dataR[k+b]*sin_tab[p]+dataI[k+b]*cos_tab[p];
                                dataR[k+b]=TR-dataR[k+b]*cos_tab[p]-dataI[k+b]*sin_tab[p];
                                dataI[k+b]=TI+temp*sin_tab[p]-dataI[k+b]*cos_tab[p];
                        } /* END for (3) */
                } /* END for (2) */
        } /* END for (1) */
        for ( i=0;i<SAMPLENUMBER/2;i++ )
        {
                w[i]=sqrt(dataR[i]*dataR[i]+dataI[i]*dataI[i]);
        }
} /* END FFT */
               

void InitForFFT()
{
        int i;
       
        for ( i=0;i<SAMPLENUMBER;i++ )
        {
                sin_tab[i]=sin(PI*2*i/SAMPLENUMBER);
                cos_tab[i]=cos(PI*2*i/SAMPLENUMBER);
        }
}

void MakeWave()
{
        int i;
       
        for ( i=0;i<SAMPLENUMBER;i++ )
        {
                INPUT[i]=sin(PI*2*i/SAMPLENUMBER*3)*1024;
        }
}

使用特权

评论回复
板凳
zhangmangui| | 2014-5-13 21:24 | 只看该作者
欢迎新朋友    楼上给的参考很详细  

使用特权

评论回复
地板
zhangmangui| | 2014-5-13 21:33 | 只看该作者
参考一下  函数
#include <csl.h>
#include <csl_pll.h>
#include <csl_emif.h>
#include <csl_chip.h>
#include <csl_mcbsp.h>
#include <stdio.h>
#include "fpga_offset_addr.h"
#include <math.h>

#define CESECT2 0x400000
#define R_AD9280                (CESECT2 + RE_AD9280_OFFSET)              //

#define Length 128          //FFT的点数
Uint16  *R_AD9280_Addr;

int in_x[Length];          //数据缓冲数组 128
int i = 0;
int s,m = 0;
int intnum = 0;
int flag = 0;              //采集128点的标志
double xavg;               
double x[128],pr[128],pi[128],fr[128],fi[128],mo[128];
int n,k,l,il;
PLL_Config  myConfig      = {
  0,                    //IAI: the PLL locks using the same process that was underway
                //before the idle mode was entered
  1,                            //IOB: If the PLL indicates a break in the phase lock,
                //it switches to its bypass mode and restarts the PLL phase-locking
                //sequence
  12        ,            //PLL multiply value; multiply 12 times
  0             //Divide by 2 PLL divide value; it can be either PLL divide value
                //(when PLL is enabled), or Bypass-mode divide value
                //(PLL in bypass mode, if PLL multiply value is set to 1)
};
/*SDRAM的EMIF设置*/
EMIF_Config emiffig = {
  0x221,         //EGCR  : the MEMFREQ = 00,the clock for the memory is equal to cpu frequence
                          //                  the WPE = 0 ,forbiden the writing posting when we debug the EMIF
                          //        the MEMCEN = 1,the memory clock is reflected on the CLKMEM pin
                          //        the NOHOLD = 1,HOLD requests are not recognized by the EMIF
  0xFFFF,        //EMI_RST: any write to this register resets the EMIF state machine
  0x3FFF,        //CE0_1:  CE0 space control register 1
                          //        MTYPE = 011,Synchronous DRAM(SDRAM),16-bit data bus width
  0xFFFF,   //CE0_2:  CE0 space control register 2
  0x00FF,   //CE0_3:  CE0 space control register 3
                          //        TIMEOUT = 0xFF;
  0x1FFF,        //CE1_1:  CE0 space control register 1
            //        Asynchronous, 16Bit
  0xFFFF,        //CE1_2:  CE0 space control register 2
  0x00FF,        //CE1_3:  CE0 space control register 3
  
  0x1FFF,        //CE2_1:  CE0 space control register 1
            //        Asynchronous, 16Bit
  0xFFFF,        //CE2_2:  CE0 space control register 2
  0x00FF,        //CE2_3:  CE0 space control register 3
  
  0x1FFF,        //CE3_1:  CE0 space control register 1
            //        Asynchronous, 16Bit
  0xFFFF,        //CE3_2:  CE0 space control register 2
  0x00FF,        //CE3_3:  CE0 space control register 3
  
  0x2911,   //SDC1:   SDRAM control register 1
                          //                  TRC = 8
                          //        SDSIZE = 0;SDWID = 0
                          //        RFEN = 1
                          //        TRCD = 2
                          //        TRP  = 2
  0x0410,        //SDPER : SDRAM period register
                          //                  7ns *4096
  0x07FF,    //SDINIT: SDRAM initialization register
                          //        any write to this register to init the all CE spaces,
                          //        do it after hardware reset or power up the C55x device
  0x0131        //SDC2:          SDRAM control register 2
                          //        SDACC = 0;
                          //        TMRD = 01;
                          //        TRAS = 0101;
                          //        TACTV2ACTV = 0001;                                                               
  };

void delay(Uint16 k)
{
        while(k>0)
        {
                k--;
        }
}
//--------------------------------------------------------------------
// 函数名称 : void kfft(double pr[128],double pi[128],int n,int k,double fr[128],double fi[128],int l,int il)
// 函数说明 : 基2快速傅立叶变换子程序
// 输入参数 :
// 输出参数 : 无
//--------------------------------------------------------------------
void kfft(double pr[128],double pi[128],int n,int k,double fr[128],double fi[128],int l,int il)
{
          int it,m,is,i,j,nv,l0;
    double p,q,s,vr,vi,poddr,poddi;
    for (it=0; it<=n-1; it++)
      { m=it; is=0;
        for (i=0; i<=k-1; i++)
          { j=m/2; is=2*is+(m-2*j); m=j;}
        fr[it]=pr[is]; fi[it]=pi[is];
      }
    pr[0]=1.0; pi[0]=0.0;
    p=6.283185306/(1.0*n);
    pr[1]=cos(p); pi[1]=-sin(p);
    if (l!=0) pi[1]=-pi[1];
    for (i=2; i<=n-1; i++)
      { p=pr[i-1]*pr[1]; q=pi[i-1]*pi[1];
        s=(pr[i-1]+pi[i-1])*(pr[1]+pi[1]);
        pr[i]=p-q; pi[i]=s-p-q;
      }
    for (it=0; it<=n-2; it=it+2)
      { vr=fr[it]; vi=fi[it];
        fr[it]=vr+fr[it+1]; fi[it]=vi+fi[it+1];
        fr[it+1]=vr-fr[it+1]; fi[it+1]=vi-fi[it+1];
      }
    m=n/2; nv=2;
    for (l0=k-2; l0>=0; l0--)
      { m=m/2; nv=2*nv;
        for (it=0; it<=(m-1)*nv; it=it+nv)
          for (j=0; j<=(nv/2)-1; j++)
            { p=pr[m*j]*fr[it+j+nv/2];
              q=pi[m*j]*fi[it+j+nv/2];
              s=pr[m*j]+pi[m*j];
              s=s*(fr[it+j+nv/2]+fi[it+j+nv/2]);
              poddr=p-q; poddi=s-p-q;
              fr[it+j+nv/2]=fr[it+j]-poddr;
              fi[it+j+nv/2]=fi[it+j]-poddi;
              fr[it+j]=fr[it+j]+poddr;
              fi[it+j]=fi[it+j]+poddi;
            }
      }
    if (l!=0)
      for (i=0; i<=n-1; i++)
        { fr[i]=fr[i]/(1.0*n);
          fi[i]=fi[i]/(1.0*n);
        }
    if (il!=0)
      for (i=0; i<=n-1; i++)
        { pr[i]=sqrt(fr[i]*fr[i]+fi[i]*fi[i]);
          if (fabs(fr[i])<0.000001*fabs(fi[i]))
            { if ((fi[i]*fr[i])>0) pi[i]=90.0;
              else pi[i]=-90.0;
            }
          else
            pi[i]=atan(fi[i]/fr[i])*360.0/6.283185306;
        }
   }
void main()
{
        /*初始化CSL库*/       
    CSL_init();
    /*EMIF为全EMIF接口*/
    CHIP_RSET(XBSR,0x0a01);
   
    /*设置系统的运行速度为144MHz*/
    PLL_config(&myConfig);
   
    /*初始化DSP的外部SDRAM*/
    EMIF_config(&emiffig);

        R_AD9280_Addr                =  (Uint16 *)R_AD9280;
        //--------初始化数组in_x[i] =0---------------------  
        for(i=0;i<128;i++)
   
     in_x[i] = 0;
     
     asm(" nop ");
   
        while(!flag)
        {
                in_x[m] = (*R_AD9280_Addr & 0x00ff)*5;
                   m++;   
                   intnum = m;
                if (intnum == Length)      //采集到128个点了吗?是,进行FFT分析
                {
                        intnum = 0;                       
                        xavg = 0.0;                       
                        for (s=0; s<Length; s++)
                        {
                                xavg = in_x[s] + xavg;  //归一化处理
                        }                                       
                        xavg = xavg/Length;                       
                        for (s=0; s<Length; s++)
                        {
                                x[s] = 1.0*(in_x[s] - xavg);
                                pr[s] = x[s];         //输入实部
                                pi[s] = 0;            //输入虚部
                        }                       
                        kfft(pr,pi,128,7,fr,fi,0,1);   //调用FFT分析程序                       
                        for (s=0;s<Length;s++)
                                  {        mo[s] = sqrt(fr[s]*fr[s]+fi[s]*fi[s]);} //求输出模值                       
                        m=0;
                        flag = 1;   //改变标志位
                }

        }
        while(1)
        {
                asm(" nop ");                //在此设置断点
        }
}



使用特权

评论回复
5
aresc| | 2014-5-13 23:04 | 只看该作者
sin(100*PI*t)+cos(150*PI*t) = sin(2*50*pi*t) + sin(2*75*pi*t),就是信号频率分别为50Hz、75Hz的累加的信号。
假设采样频率为fs=300 (为50、75Hz的整数倍且满足采样定理),取一个周期的采样信号x = sin(2*pi*f1*n/fs)+sin(2*pi*f2*n/fs),  0<=n<300.
然后对一个周期的信号做傅里叶变换,即300点的傅里叶变换。然后很精确的在50、75Hz处的谱线大于0,其他的为0.

f1 = 50; % signal frequency2
f2 = 75; % signal frequency1
fs = 300; % sample rate

N=300; % samples in one sampling period
n = 0:N-1;

x = sin(2*pi*f1*n/fs) + sin(2*pi*f2*n/fs);

X=fft(x); % N点FFT

plot(abs(X));

使用特权

评论回复
6
le_pataya| | 2015-2-27 21:32 | 只看该作者
zhangmangui 发表于 2014-5-13 21:33
参考一下  函数
#include
#include

想请教一下,FFT涉及的算法,倒位序变址是什么意思呢?谢谢~

使用特权

评论回复
7
zhangmangui| | 2015-2-28 10:42 | 只看该作者
le_pataya 发表于 2015-2-27 21:32
想请教一下,FFT涉及的算法,倒位序变址是什么意思呢?谢谢~

http://wenku.baidu.com/link?url= ... WWQJrsTz_lFR_pNEGea
看看能不能帮到你

使用特权

评论回复
8
le_pataya| | 2015-3-2 09:40 | 只看该作者
这个是MATLAB 和DSP是不是不一样啊?搞不清楚DSP做FFT到底要用到多少硬件?就输入信号吗

使用特权

评论回复
9
luospring123| | 2015-3-13 09:06 | 只看该作者
辛苦了, 讲的很详细,呵呵

使用特权

评论回复
10
dicktime| | 2015-4-28 12:56 | 只看该作者
zhangmangui 发表于 2014-5-13 21:24
欢迎新朋友    楼上给的参考很详细

您好版主  请问2楼FFT算法最后得到的是什么  w数组里存放的是各次谐波的幅值么?如果是的话,不是最多只能算到N/2次谐波么,但是
for ( i=0;i<SAMPLENUMBER;i++ )
         {
                 DATA=w;
        }
为什么循环次数不是SAMPLENUMBER/2

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

3

帖子

0

粉丝