Openwrt_Widora: 一种定点FFT计算方法的实现

为了在自编的一个播放器上显示频谱效果,学习了一下快速傅里叶变换,做了一个定点的FFT程序。定点FFT程序主要应用到了浮点数的定点处理和复数的运算,为此自编了一个fft_math模块。

FFT具体原理参考了《数字信号处理 第2版》(Richard G. Lyons), 在第5章节中对FFT有详尽的解释和演示。

这里需要注意的是:
1. 在Openwrt_widora编译环境下左右移位均为数学移位!也正好利用这一特点来加快计算速度。
2. 由于最大整数位的限制(设置为int64_t), 计算精度/数据范围/采样点数3者之间需要进行协调控制,不然会造成计算溢出。
3. 具体定点FFT由函数mat_egiFFFT()来实现,可看其中具体说明。
4. 考虑到不同情况下的应用,fft_math模块中分别提供了浮点型和整型的波幅计算函数。比如,对于PCM S16格式的音频数据,可用整型函数mat_uintCompAmp()来得到整型的波幅值。

5. 同样, 测试程序test_fft.c提供浮点型和整型2种采样点输入样本。注意比较不同频率其波幅值和实际计算输出的波幅值。

6. 所附程序在 Openwrt_Widora编译环境下通过。

最后应用到MP3播放器上的效果还是不错的。

 

-----------------  参考源代码 ---------------

fft_math.h  

/*------------------------  fft_math.h  ---------------------------
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.

Midas Zhou
-------------------------------------------------------------------*/
#ifndef __FFT_MATH_H__
#define __FFT_MATH_H__

#include <inttypes.h>

#define MATH_PI 3.1415926535897932
#define MATH_DIVEXP   	11  /* An odd number!!  exponent of 2, as for divisor of fixed point number */

/* EGI fixed point / complex number */
typedef struct {
int64_t         num;	/* divident */
int	        div;	/* divisor, 2 exponent taken 16*/
} EGI_FVAL;

typedef struct {
EGI_FVAL       real;	/* real part */
EGI_FVAL       imag;	/* imaginery part */
} EGI_FCOMPLEX;


/* TODO: adjustable exponent value  MAT_FVAL(a,exp) */
/* shitf MATH_DIVEXP bitS each time, if 15,  64-15-15-15-15-1 */

/* create a fix value */
/* (a) is float */
#define MAT_FVAL(a) ( (EGI_FVAL){ (a)*(1U<<MATH_DIVEXP), MATH_DIVEXP} )
/* (a) is INT, suppose left bit_shift is also arithmatic !!! */
#define MAT_FVAL_INT(a) ( (EGI_FVAL){ a<<MATH_DIVEXP, MATH_DIVEXP} )

/* create a complex: r--real, i--imaginery */
/* (r) is float */
#define MAT_FCPVAL(r,i)	 ( (EGI_FCOMPLEX){ MAT_FVAL(r), MAT_FVAL(i) } )
/* (r) is INT, suppose left bit_shift is also arithmatic !!! */
#define MAT_FCPVAL_INT(r,i)  ( (EGI_FCOMPLEX){ MAT_FVAL_INT(r), MAT_FVAL(i) } )

/* complex phase angle factor
 @n:	m*(2*PI)/N  nth phase angle
 @N:	Total parts of a circle(2*PI).
*/
#define MAT_CPANGLE(n, N)  ( MAT_FCPVAL( cos(2.0*n*MATH_PI/N), -sin(2.0*n*MATH_PI/N) ) )

/* complex and FFT functions */
void 			mat_FixPrint(EGI_FVAL a);
void 			mat_CompPrint(EGI_FCOMPLEX a);
inline float 	        mat_floatFix(EGI_FVAL a);
inline EGI_FVAL 	mat_FixAdd(EGI_FVAL a, EGI_FVAL b);
inline EGI_FVAL 	mat_FixSub(EGI_FVAL a, EGI_FVAL b);
inline EGI_FVAL         mat_FixMult(EGI_FVAL a, EGI_FVAL b);
inline EGI_FVAL 	mat_FixDiv(EGI_FVAL a, EGI_FVAL b);
inline EGI_FCOMPLEX 	mat_CompAdd(EGI_FCOMPLEX a, EGI_FCOMPLEX b);
inline EGI_FCOMPLEX 	mat_CompSub(EGI_FCOMPLEX a, EGI_FCOMPLEX b);
inline EGI_FCOMPLEX 	mat_CompMult(EGI_FCOMPLEX a, EGI_FCOMPLEX b);
inline EGI_FCOMPLEX 	mat_CompDiv(EGI_FCOMPLEX a, EGI_FCOMPLEX b);
float 			mat_floatCompAmp( EGI_FCOMPLEX a );
unsigned int 		mat_uint32Log2(uint32_t np);
unsigned int 		mat_uintCompAmp( EGI_FCOMPLEX a );
uint64_t 		mat_uintCompSAmp( EGI_FCOMPLEX a );
EGI_FCOMPLEX 		*mat_CompFFTAng(uint16_t np);
int 			mat_egiFFFT( uint16_t np, const EGI_FCOMPLEX *wang,
                                     const float *x, const int *nx, EGI_FCOMPLEX *ffx);

/* other math functions */
uint64_t 		mat_fp16_sqrtu32(uint32_t x);
unsigned int 	        tm_diffus(struct timeval t_start, struct timeval t_end);



#endif

 fft_math.c

 

/*----------------------  fft_math.c  --------------------------------
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.

Midas Zhou
--------------------------------------------------------------------*/
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <math.h>
#include <inttypes.h>
#include <stdlib.h>
#include "fft_math.h"

/* ------------------------  PIXED_POINT FUNCTION  ------------------------

1. After calculatoin, a Fix point value must reset its exponent 'div' to the
   default value as '15'

2. Limitation analysis:
   1st grade precision: 0.00003

--------------------------------------------------------------------------*/

/*---------------------------
	Print function
---------------------------*/
void mat_FixPrint(EGI_FVAL a)
{
	printf("Float: %.8f   ", mat_floatFix(a) );
	printf("[num:%"PRId64", div:%d]",a.num, a.div);
}

/*-------------------------------------------------------
	Convert fixed point to float value
--------------------------------------------------------*/
inline float mat_floatFix(EGI_FVAL a)
{

//	return (float)1.0*a.num/(1u<<a.div);
	return 1.0*(a.num>>a.div);

}

/*-------------------------------------------------------
	Addup of two fixed point value: a+b
NOTE: Divisors of two EGI_FVAL must be the same!
--------------------------------------------------------*/
inline EGI_FVAL mat_FixAdd(EGI_FVAL a, EGI_FVAL b)
{
	return (EGI_FVAL){ a.num+b.num, a.div };
}

/*-------------------------------------------------------
	Subtraction of two fixed point value: a+b
NOTE: Divisors of two EGI_FVAL must be the same!
--------------------------------------------------------*/
inline EGI_FVAL mat_FixSub(EGI_FVAL a, EGI_FVAL b)
{
	return (EGI_FVAL){ a.num-b.num, a.div };
}

/*-------------------------------------------------------
	Mutliplication of two fixed point value: a+b
NOTE: Divisors of two EGI_FVAL must be the same!
--------------------------------------------------------*/
inline EGI_FVAL mat_FixMult(EGI_FVAL a, EGI_FVAL b)
{
	int64_t c;

	c=a.num*b.num;		/* !!!! Limit: (16num+16div)bit*(16num+16div)bit, for DIVEXP=15 */
	c>>=a.div;	        /* Right shifting is supposed to be arithmatic */
	return (EGI_FVAL){c, a.div};
}

/*-------------------------------------------------------
	Division of two fixed point value: a/b
NOTE: Divisors of two EGI_FVALV must be the same!
--------------------------------------------------------*/
inline EGI_FVAL mat_FixDiv(EGI_FVAL a, EGI_FVAL b)
{

	/* Min value for 0 */
	if(b.num==0)
		b.num=1;

	return (EGI_FVAL){  (a.num<<a.div)/b.num, a.div }; /* suppose left shif is arithmatic! */

}


/*--------------------   PIXED_POINT COMPLEX FUNCTION  ----------------*/


/*-------------------------------
	Print function
--------------------------------*/
void mat_CompPrint(EGI_FCOMPLEX a)
{
	printf(" Float: %.8f %+.8fj   ", mat_floatFix(a.real), mat_floatFix(a.imag));
	printf(" Real[num:%"PRId64", div:%d],Imag[num:%"PRId64", div:%d] ",
			a.real.num, a.real.div, a.imag.num, a.imag.div);

}


/*-------------------------------------------------------
		Addup two complex: a+b
NOTE: Divisors of two EGI_FVAL must be the same!
--------------------------------------------------------*/
inline EGI_FCOMPLEX mat_CompAdd(EGI_FCOMPLEX a, EGI_FCOMPLEX b)
{
	return (EGI_FCOMPLEX){
			     {( a.real.num+b.real.num),  a.real.div },
			     {( a.imag.num+b.imag.num),  a.imag.div }
			   };
}

/*-------------------------------------------------------
	Subtraction of two complex: a-b
NOTE: Divisors of two EGI_FCOMPLEX must be the same!
--------------------------------------------------------*/
inline EGI_FCOMPLEX mat_CompSub(EGI_FCOMPLEX a, EGI_FCOMPLEX b)
{
	return (EGI_FCOMPLEX){
			     {a.real.num-b.real.num,  a.real.div },
			     {a.imag.num-b.imag.num,  a.imag.div }
			   };
}

/*-------------------------------------------------------
	Multiplication of two complex: a*b
NOTE: Divisors of two EGI_FCOMPLEX must be the same!
--------------------------------------------------------*/
inline EGI_FCOMPLEX mat_CompMult(EGI_FCOMPLEX a, EGI_FCOMPLEX b)
{
	EGI_FVAL	real;
	EGI_FVAL	imag;

	real=mat_FixSub(
		mat_FixMult(a.real, b.real),
		mat_FixMult(a.imag, b.imag)
	     );

	imag=mat_FixAdd(
		mat_FixMult(a.real, b.imag),
		mat_FixMult(a.imag, b.real)
	     );

	return (EGI_FCOMPLEX){real, imag};
}

/*-------------------------------------------------------
	Division of two complex: a/b
NOTE: Divisors of two EGI_FCOMPLEX must be the same!
  ar+jai/(br+jbi)=(ar+jai)(br-jbi)/(br^2+bi^2)
--------------------------------------------------------*/
inline EGI_FCOMPLEX mat_CompDiv(EGI_FCOMPLEX a, EGI_FCOMPLEX b)
{
	EGI_FCOMPLEX	d,ad;
	EGI_FVAL	den;

	/* d=br-j(bi) */
	d.real=b.real;
	d.imag.num=-b.imag.num;
	d.imag.div=b.imag.div;

	/* a*d */
	ad=mat_CompMult(a,d);

	/* rb*rb+ib*ib */
	den=mat_FixAdd( mat_FixMult(b.real, b.real),
			mat_FixMult(b.imag, b.imag) );

	/*  ad/den */
	ad.real=mat_FixDiv(ad.real, den); /* 0 will reset to 1.0/2^15 in FixDiv() */
	ad.imag=mat_FixDiv(ad.imag, den);

	return ad;
}


/*---------------------------------------------------------
work out the amplitude(modulus) of a complex, in float type.
Check also: int mat_intCompAmp( EGI_FCOMPLEX a )

Limit:  a.real MAX. 2^16. (for DIVEXP=15)
---------------------------------------------------------*/
float mat_floatCompAmp( EGI_FCOMPLEX a )
{
	EGI_FVAL c; /* ar^2+ai^2 */
	uint64_t uamp;

	/* Limit here as in mat_FixMult(): (16+16)bit*(16+16)bit */
	c=mat_FixAdd(	mat_FixMult(a.real, a.real),
			mat_FixMult(a.imag, a.imag)
		    );

#if 0 /* 1. use float method sqrt */
	return sqrt(mat_floatFix(c));

#else  /* 2. use fixed point method sqrtu32(Max.1<<29) */
	uamp=mat_fp16_sqrtu32( c.num>>(47+(15-MATH_DIVEXP)-29 +1))<<((47+(15-MATH_DIVEXP)-29)/2-MATH_DIVEXP/2);

	/* if float */
	return 1.0*uamp/(1<<16);
#endif

}


/*--------------------------------------
	Return log2 of np
@np:	>0
--------------------------------------*/
unsigned int mat_uint32Log2(uint32_t np)
{
	int i;
	for(i=0; i<32; i++) {
        	if( (np<<i) & (1<<31) ){
			return 31-i;
        	}
	}

	return 0;
}


/*---------------------------------------------------------
work out the amplitude(modulus) of a complex, in INT type.

check also: float mat_floatCompAmp( EGI_FCOMPLEX a )
---------------------------------------------------------*/
unsigned int mat_uintCompAmp( EGI_FCOMPLEX a )
{
	EGI_FVAL c; /* ar^2+ai^2 */
	uint64_t uamp;

	/* Limit here as in mat_FixMult(): (16+16)bit*(16+16)bit */
	c=mat_FixAdd(	mat_FixMult(a.real, a.real),
			mat_FixMult(a.imag, a.imag)
		    );

#if 0 /* 1. use float method sqrt */
	return sqrt(mat_floatFix(c));

#else  /* 2. use fixed point method sqrtu32(Max.1<<29) */

	uamp=mat_fp16_sqrtu32( c.num>>(47+(15-MATH_DIVEXP)-29 +1))<<((47+(15-MATH_DIVEXP)-29)/2-MATH_DIVEXP/2);

	return uamp>>16;
#endif

}

/*---------------------------------------------------
Return square of the amplitude(modulus) of a complex
check also: float mat_floatCompAmp( EGI_FCOMPLEX a )

----------------------------------------------------*/
uint64_t mat_uintCompSAmp( EGI_FCOMPLEX a )
{
        EGI_FVAL c; /* ar^2+ai^2 */

        /* Limit here as in mat_FixMult(): (16+16)bit*(16+16)bit (for DIVEXP=15) */
        c=mat_FixAdd(   mat_FixMult(a.real, a.real),
                        mat_FixMult(a.imag, a.imag)
                    );

	return c.num>>MATH_DIVEXP;
}


/*----------------------------------------------------
        Generate complex phase angle array for FFT
@np	Phanse angle numbers as per FFT point numbers
	np will be normalized first to powers of 2

!!! DO NOT FORGET TO FREE IT !!!

Return:
	a pointer to EGI_FCOMPLEX	OK

	NULL				fails
----------------------------------------------------*/
EGI_FCOMPLEX *mat_CompFFTAng(uint16_t np)
{
	int i;
	int exp=0;
	int nn;

	EGI_FCOMPLEX *wang;

	/* get exponent number of 2 */
        for(i=0; i<16; i++) {
                if( (np<<i) & (1<<15) ){
                        exp=16-i-1;
                        break;
                }
        }

        /* reset nn to be powers of 2 */
        nn=1<<exp;

	/* calloc wang */
	wang=calloc(nn, sizeof(EGI_FCOMPLEX));
	if(wang==NULL) {
		printf("%s,Fail to calloc wang!\n",__func__);
		return NULL;
	}

	/* generate phase angle */
        for(i=0;i<nn;i++) {
                wang[i]=MAT_CPANGLE(i, nn);
                //mat_CompPrint(wang[i]);
                //printf("\n");
        }

	return wang;
}


/*-------------------------------------------------------------------------------------
Fixed point Fast Fourier Transform

@np:    Total number of data for FFT, will be ajusted to a number of 2 powers;
        np=1, result is 0!
@wang   complex phase angle factor, according to normalized np.
@x:     Pointer to array of input float data x[].
@nx:	Pointer to araay of input INT data nx[].  NOTE: if x==NULL, use nx[] then.
@ffx:   Pointer to array of FFT result ouput in form of x+jy.

Note:
0. If input x[] is NULL, then use nx[].
1. Input number of points will be ajusted to a number of powers of 2.
2. Actual amplitude is FFT_A/(NN/2), where FFT_A is ffx[] result amplitude(modulus).
3. Use real and imaginery part of ffx[] to get phase angle(relative to cosine!!!):
   atan(ffx[].real/ffx[].imag),
4. !!!--- Cal overflow ---!!!
   Expected amplitude:      MSB. 1<<N 	( 1<<(N+1)-1 )
   expected sampling point: 1<<M
   Taken: N+M-1=16  to incorporate with mat_floatCompAmp()
         OR N+M-1=16+(15-MATH_DIVEXP) --> N+M=17+(15-MATH_DIVEXP) [ MATH_DIVEXP MUST be odd!]

   Example:     when MATH_DIVEXP = 15   LIMIT: Amp_Max*(np/2) is 17bits;
                we may take Amp_Max: (1<<(12+1))-1;  FFT point number: 1<<5:
		  (NOTE: 12 is the highes significant bit for amplitude )

                when MATH_DIVEXP = 11   LIMIT: Amp_Max*(np/2) is 22bits;
                we may take Amp_Max: (1<<(11+1))-1;  FFT point number: 1<<10:

                Ok, with reduced precision as you decrease MATH_DIVEXP !!!!!
5. So,you have to balance between data precision, data scope and number of sample points(np)
   ,which also decides Min. analysis frequency.

Return:
        0       OK
        <0      Fail
---------------------------------------------------------------------------------------*/
int mat_egiFFFT( uint16_t np, const EGI_FCOMPLEX *wang,
					 const float *x, const int *nx,EGI_FCOMPLEX *ffx)
{
        int i,j,s;
        int kx,kp;
        int exp=0;              /* 2^exp=nn */
        int nn;                 /* number of data for FFT analysis, a number of 2 powers */
        EGI_FCOMPLEX *ffodd;    /* for FFT STAGE 1,3,5.. , store intermediate result */
        EGI_FCOMPLEX *ffeven;   /* for FFT STAGE 0,2,4.. , store intermediate result */
        int *ffnin;             /* normal order mapped index */
	int fftmp;

        /* check input data */
        if( np==0 || wang==NULL || ( x==NULL && nx==NULL ) || ffx==NULL) {
                printf("%s: Invalid input data!\n",__func__);
                return -1;
        }

        /* get exponent number of 2 */
        for(i=0; i<16; i++) {
                if( (np<<i) & (1<<15) ){
                        exp=16-i-1;
                        break;
                }
        }

        /* reset nn to be powers of 2 */
        nn=1<<exp;

        /* allocate vars !!!!! This is time consuming !!!!!! */
        ffodd=calloc(nn, sizeof(EGI_FCOMPLEX));
        if(ffodd==NULL) {
                printf("%s: Fail to alloc ffodd[] \n",__func__);
                return -1;
        }
        ffeven=calloc(nn, sizeof(EGI_FCOMPLEX));
        if(ffeven==NULL) {
                printf("%s: Fail to alloc ffeven[] \n",__func__);
                free(ffodd);
                return -1;
        }
        ffnin=calloc(nn, sizeof(int));
        if(ffnin==NULL) {
                printf("%s: Fail to alloc ffnin[] \n",__func__);
                free(ffodd); free(ffeven);
                return -1;
        }

        ///    FFT    
        /* 1. map normal order index to  input x[] index */
        for(i=0; i<nn; i++)
        {
                ffnin[i]=0;
                for(j=0; j<exp; j++) {
                        /*  move i(j) to i(0), then left shift (exp-j) bits and assign to ffnin[i](exp-j) */
                        ffnin[i] += ((i>>j)&1) << (exp-j-1);
                }
                //printf("ffnin[%d]=%d\n", i, ffnin[i]);
        }

       /*  2. store x() to ffeven[], index as mapped according to ffnin[] */
	if(x)  {	/* use float type x[] */
	        for(i=0; i<nn; i++)
        	        ffeven[i]=MAT_FCPVAL(x[ffnin[i]], 0.0);
	} else {        /* use INT type nx[] */
	        for(i=0; i<nn; i++) {
        	        //ffeven[i]=MAT_FCPVAL_INT(nx[ffnin[i]], 0.0);
			ffeven[i].real.num=nx[ffnin[i]]<<MATH_DIVEXP; /* suppose left bit_shift is also arithmatic! */
			ffeven[i].real.div=MATH_DIVEXP;
			ffeven[i].imag.num=0;
			ffeven[i].imag.div=MATH_DIVEXP;
		}

	}

        /* 3. stage 2^1 -> 2^2 -> 2^3 -> 2^4....->NN point DFT */
        for(s=1; s<exp+1; s++) {
            for(i=0; i<nn; i++) {   /* i as normal order index */
                /* get coupling x order index: ffeven order index -> x order index */
                kx=((i+ (1<<(s-1))) & ((1<<s)-1)) + ((i>>s)<<s); /* (i+2^(s-1)) % (2^s) + (i/2^s)*2^s) */

                /* get complex phase angle index */
                kp= (i<<(exp-s)) & ((1<<exp)-1); // k=(i*1)%8

                if( s & 1 ) {   /* odd stage */
                        if(i < kx )
                                ffodd[i]=mat_CompAdd( ffeven[i], mat_CompMult(ffeven[kx], wang[kp]) );
                        else      /* i > kx */
                                ffodd[i]=mat_CompAdd( ffeven[kx], mat_CompMult(ffeven[i], wang[kp]) );
                }
                else {          /* even stage */
                        if(i < kx) {
                                ffeven[i]=mat_CompAdd( ffodd[i], mat_CompMult(ffodd[kx], wang[kp]) );
                                //printf(" stage 2: ffeven[%d]=ffodd[%d]+ffodd[%d]*wang[%d]\n", i,i,kx,kp);
                        }
                        else {  /* i > kx */
                                ffeven[i]=mat_CompAdd( ffodd[kx], mat_CompMult(ffodd[i], wang[kp]) );
                                //printf(" stage 2: ffeven[%d]=ffodd[%d]+ffodd[%d]*wang[%d]\n", i,kx,i,kp);
                        }
                } /* end of odd and even stage cal. */
            } /* end for(i) */
        } /* end for(s) */


        /* 4. pass result */
        if(exp&1) {     /* 4.1 result in odd array */
                for(i=0; i<nn; i++) {
                        ffx[i]=ffodd[i];
                }
        } else {      /* 4.2 result in even array */
                for(i=0; i<nn; i++) {
                        ffx[i]=ffeven[i];
                }
        }

	/* free resources */
	free(ffodd);
	free(ffeven);
	free(ffnin);

	return 0;
}


/*----------------------------------------------------------------------------------
Fix point square root for uint32_t, the result is <<16 shifted, so you need to shift
>>16 back after call to get the right answer.

Limit input x <= 2^29    //4294967296(2^32)   4.2949673*10^9


Original Source refert to:
	http://read.pudn.com/downloads286/sourcecode/embedded/1291109/sqrt.c__.htm
------------------------------------------------------------------------------------*/
uint64_t mat_fp16_sqrtu32(uint32_t x)
{
	uint64_t x0=x;
	x0<<=32;
	uint64_t x1;
	uint32_t s=1;
	uint64_t g0,g1;

	if(x<=1)return x;

	x1=x0-1;
	if(x1>4294967296-1) {
		s+=16;
		x1>>=32;
	}
	if(x1>65535) {
		s+=8;
		x1>>=16;
	}
	if(x1>255) {
		s+=4;
		x1>>=8;
	}
	if(x1>15) {
		s+=2;
		x1>>=4;
	}
	if(x1>3) {
		s+=1;
	}

	g0=1<<s;
	g1=(g0+(x0>>s))>>1;

	while(g1<g0) {
		g0=g1;
		g1=(g0+x0/g0)>>1;
	}

	return g0; /* after call, right shift >>16 to get right answer */
}


/*------------------------------------------------------------------
return time difference in us, as an unsigned value.
t_start:        start time
t_end:          end time
------------------------------------------------------------------*/
unsigned int tm_diffus(struct timeval t_start, struct timeval t_end)
{
        int ds=t_end.tv_sec-t_start.tv_sec;
        int dus=t_end.tv_usec-t_start.tv_usec;

        int td=ds*1000000+dus;

        return ( td>0 ? td : -td );
}

  测试程序 test_fft.c

/*------------------------------------------------------------------
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.

An example to test  EGI Fixed Point Fast Fourier Transform function.

Midas Zhou
------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include "fft_math.h"
#include <math.h>
#include <inttypes.h>

#define FLOAT_INPUT	1	/* 1 -- input/out in float, or 0 -- in INT */

int main(void)
{
	int i,k;

	struct timeval tm_start,tm_end;
	/* nexp+aexp MAX 21 */
	int 		nexp=11;  	/* exponent of 2,  for Element number */
	int 		aexp=10;  	/* exponent of 2,  MSB for Max. amplitude, Max amp=2^12-1 */
	uint16_t 	np=1<<nexp;
	float 		famp;
	unsigned int   	namp;
	unsigned int   	nsamp;

	float 		*x;	    	/* input float */
	int   		*nx;	    	/* input INT */
	EGI_FCOMPLEX 	*ffx;  		/* result */
	EGI_FCOMPLEX 	*wang; 		/* unit phase angle factor */

	/* allocate vars */
	x=calloc(np, sizeof(float));
	if(x==NULL)
        	return -1;
	nx=calloc(np, sizeof(int));
	if(nx==NULL)
        	return -1;
	ffx=calloc(np, sizeof(EGI_FCOMPLEX));
	if(ffx==NULL)
		return -1;

	/* generate NN points samples */

#if FLOAT_INPUT  /* --- float type x[] --- */
	for(i=0; i<np; i++) {
		x[i]=10.5*cos(2.0*MATH_PI*1000*i/8000) +0.5*cos(2.0*MATH_PI*2000*i/8000+3.0*MATH_PI/4.0) \
		     +1.0*((1<<aexp))*cos(2.0*MATH_PI*3000*i/8000+MATH_PI/4.0);  /* Amplitud Max. abt.(1<<12)+(1<<10) */
		printf(" x[%d]: %f\n", i, x[i]);
	}
#else		/* --- INT type nx[] --- */
	for(i=0; i<np; i++) {
		nx[i]= (int)( 333*cos(2.0*MATH_PI*1000*i/16000) )
		      +(int)( 444*cos(2.0*MATH_PI*2000*i/16000+3.0*MATH_PI/4.0) )
		      +(int)( 555*cos(2.0*MATH_PI*3000*i/16000-1.0*MATH_PI/4.0) )
		      +(int)( ((1<<(aexp+1))-1)*cos(2.0*MATH_PI*5000*i/16000+MATH_PI/4.0) );
		printf(" nx[%d]: %d\n", i, nx[i]);
	}
#endif

	/* prepare phase angle */
	wang=mat_CompFFTAng(np);


k=0;
do {    /* ---------------------- LOOP TEST FFT ---------------------- */
k++;

	gettimeofday(&tm_start, NULL);

	/* call fix_FFT */
#if FLOAT_INPUT /* float x[] */
	mat_egiFFFT(np, wang, x, NULL, ffx);
#else /* int nx[] */
	mat_egiFFFT(np, wang, NULL, nx, ffx);
#endif

	gettimeofday(&tm_end, NULL);

	/* print result */
	#if 1
	if( (k&(64-1))==0 )
	  for(i=0; i<np; i++) {
		#if FLOAT_INPUT  /* --- get float modulus --- */
		 famp=mat_floatCompAmp(ffx[i])/(np/2);   /* np MUST be powers of 2 */
		 if( famp > 0.001 || famp < -0.001 ) {
			printf("ffx[%d] ",i);
			mat_CompPrint(ffx[i]);
		 	printf(" Amp=%f ", famp);
			printf("\n");
		}
	        #else		/* --- get int moduls --- */
		 namp=mat_uintCompAmp(ffx[i])/(np/2);   /* np MUST be powers of 2 */
		 if( namp > 0 ) {
			printf("ffx[%d] ",i);
			mat_CompPrint(ffx[i]);
		 	printf(" Amp=%d ", namp);
			if(nexp>1)
				nsamp=mat_uintCompSAmp(ffx[i])>>(2*(nexp-1)); // /(np/2)/(np/2) );
			else
				nsamp=mat_uintCompSAmp(ffx[i]);
			printf(" SAmp=%d\n", nsamp);
			printf("\n");
		}
	        #endif
  	}
	#endif

	/* print results every 64 rounds */
	if( (k&(64-1))==0 )
	   printf(" --- K=%d  time cost: %d us\n", k, tm_diffus(tm_start,tm_end));

} while(1);  /* ------------------  END LOOP TEST  ----------------- */



	/* free resources */
	free(wang);
	free(x);
	free(nx);
	free(ffx);

return 0;
}


 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Midas-Zhou

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值