⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fft.cpp

📁 信道仿真源代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// fft.cpp: implementation of the Cfft class.
//  This is a slightly modified version of Takuya OOURA's
//     original radix 4 FFT package.
//Copyright(C) 1996-1998 Takuya OOURA
//    (email: ooura@mmm.t.u-tokyo.ac.jp).
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <math.h>
#include "fft.h"

//////////////////////////////////////////////////////////////////////
// Local Defines
//////////////////////////////////////////////////////////////////////
#define SQRT_FFT_SIZE 46//sqrt(2048)
#define K_2PI (8.0*atan(1))
#define FREQ_SCALE (8000.0/2048.0)
#define SAMPLE_RATE 8000

//////////////////////////////////////////////////////////////////////
// A pure input sin wave ... Asin(wt)... will produce an fft output 
//   peak of (N*A/4)^2  where N is FFT_SIZE.
// To convert to a Power dB range:
//   PdBmax = 10*log10( (N*A/4)^2 + K_C ) + K_B
//   PdBmin = 10*log10( 0 + K_C ) + K_B
//  if (N*A/4)^2 >> K_C 
//  Then K_B = PdBmax - 20*log10( N*A/4 )
//       K_C = 10 ^ ( (PdBmin-K_B)/10 )
//  for power range of 0 to 100 dB with input(A) of 32767 and N=2048
//			K_B = -44.494132  and K_C = 2.81458e4
// To eliminate the multiply by 10, divide by 10 so for an output
//		range of 0 to 100dB the stored value is 0.0 to 10.0
//   so final constant K_B = -4.4494132
#define K_B (-4.4494132)
#define K_C (2.81458e4)

#define K_ROOT (1.0/4.0)		
#define K_ROOTGN 289.626		//(A*N/8)^(2/4) / 10

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
Cfft::Cfft()
{
	WindowTbl = new double[FFT_SIZE];
	SinCosTbl = new double[FFT_SIZE/2];
	WorkArea = new int[SQRT_FFT_SIZE+2];
	pFFTAveBuf = new double[FFT_SIZE];	//Even index's hold average
	pFFTInBuf = new double[FFT_SIZE];
	WorkArea[0] = 0;
	makewt(FFT_SIZE/4, WorkArea, SinCosTbl);
    makect(FFT_SIZE/4, WorkArea, SinCosTbl + WorkArea[0]);
	for(INT i=0; i<FFT_SIZE; i++)
	{
		pFFTAveBuf[i] = 0.0;
// Pick a data windowing function:
//		WindowTbl[i] = 1.0;										//rectangle
//		WindowTbl[i] = .54 - .46*cos( (K_2PI*i)/(FFT_SIZE-1) );	//Hamming
		WindowTbl[i] = (.5 - .5*cos( (K_2PI*i)/(FFT_SIZE-1) ));	//Hanning
	}
	m_AveSize = 1;
	m_LastAve = 1;
	m_LogMode = TRUE;
	m_LastLogMode = TRUE;
	m_Gain = 10.0;
	m_Clip = 0.0;
	m_Overload = FALSE;
}

Cfft::~Cfft()
{							// free all resources
	if(WorkArea)
	{
		delete WorkArea;
		WorkArea = NULL;
	}
	if(SinCosTbl)
	{
		delete SinCosTbl;
		SinCosTbl = NULL;
	}
	if(WindowTbl)
	{
		delete WindowTbl;
		WindowTbl = NULL;
	}
	if(pFFTAveBuf)
	{
		delete pFFTAveBuf;
		pFFTAveBuf = NULL;
	}
	if(pFFTInBuf)
	{
		delete pFFTInBuf;
		pFFTInBuf = NULL;
	}

}

void Cfft::SetFFTParams(INT ave, double gain, INT type )
{
	if( type==0 )
		m_LogMode = FALSE;
	else
		m_LogMode = TRUE;
	if( (type>=10) && (type<=99) )
		m_Clip = (double)type/10.0;
	else
		m_Clip = 0.0;
	if(ave>0)
		m_AveSize = ave;
	else
		m_AveSize = 1;
	if( (m_LastAve != ave) || (m_LastLogMode != m_LogMode) )
		ResetFFT();
	m_LastLogMode = m_LogMode;
	m_LastAve = m_AveSize;
	m_Gain = 0.1*(gain*10.0/(10.0-m_Clip));

}

void Cfft::ResetFFT()
{
	for(INT i=0; i<FFT_SIZE;i++)
		pFFTAveBuf[i] = 0.0;

}


//////////////////////////////////////////////////////////////////////
// "InBuf[]" is first multiplied by a window function and then
//  calculates an "FFT_SIZE" point FFT on "InBuf[]".
//  The result is converted to dB or 4th root and stored in pFFTAveBuf
//  If "Ave" is > 1, a LP smoothing filter 
//  is calculated on the output.
//////////////////////////////////////////////////////////////////////
void Cfft::CalcFFT(double * InBuf)
{
INT i;
	m_Overload = FALSE;
	for(i=0; i<FFT_SIZE; i++)
	{
		if( InBuf[i] > 32768.0*0.90 )	//flag overload if within 10% of max
			m_Overload = TRUE;
		pFFTInBuf[i] = WindowTbl[i] * InBuf[i];		//window the data
	}
//Calculate the FFT
	bitrv2(FFT_SIZE, WorkArea + 2, pFFTInBuf);
	cftfsub(FFT_SIZE, pFFTInBuf, SinCosTbl);
	rftfsub(FFT_SIZE, pFFTInBuf, WorkArea[1], SinCosTbl + WorkArea[0]);
}

//////////////////////////////////////////////////////////////////////
//	the range "start" to "stop" is multiplied by "gain" and copied
//   into "OutBuf[]".
// The function returns TRUE if the input is overloaded
//////////////////////////////////////////////////////////////////////
BOOL Cfft::GetFFTData(INT start, INT stop, LONG* OutBuf )
{
	for( INT i=start; i<=stop; i++ )		//copy and scale into OutBuf[]
		OutBuf[i] = (LONG)(m_Gain*pFFTAveBuf[i<<1]);
	return m_Overload;
}


// Nitty gritty fft routines by Takuya OOURA
void Cfft::rftfsub(int n, double *a, int nc, double *c)
{
double tmp;
    int j, k, kk, ks, m;
    double wkr, wki, xr, xi, yr, yi;
    
    ks = (nc << 2) / n;
    kk = 0;
    m = n >> 1;
	if(m_LogMode)
	{
		for (k = 2; k < m; k += 2 ) 
		{
			j = n - k;
			kk += ks;
			wkr = 0.5 - c[nc - kk];
			wki = c[kk];
			xr = a[k] - a[j];
			xi = a[k + 1] + a[j + 1];
			yr = wkr * xr - wki * xi;
			yi = wkr * xi + wki * xr;
			a[k] -= yr;
			xi = a[k]*a[k];
			a[k+1] -= yi;
			xi += ( a[k+1]*a[k+1]);
			a[j] += yr;
			xr = a[j]*a[j];
			a[j+1] -= yi;
			xr += (a[j+1]*a[j+1]);
			tmp = log10(xi+K_C) + K_B;
			if( (tmp -= m_Clip)<0.0 )
				pFFTAveBuf[k] = (1.0-1.0/m_AveSize)*pFFTAveBuf[k];
			else
 				pFFTAveBuf[k] = (1.0-1.0/m_AveSize)*pFFTAveBuf[k] +
									(1.0/m_AveSize)*tmp;
			tmp = log10(xr+K_C) + K_B;
			if( (tmp -= m_Clip)<0.0 )
				pFFTAveBuf[j] = (1.0-1.0/m_AveSize)*pFFTAveBuf[j];
			else
 				pFFTAveBuf[j] = (1.0-1.0/m_AveSize)*pFFTAveBuf[j] +
									(1.0/m_AveSize)*tmp;
		}
	}
	else
	{
		for (k = 2; k < m; k += 2 ) 
		{
			j = n - k;
			kk += ks;
			wkr = 0.5 - c[nc - kk];
			wki = c[kk];
			xr = a[k] - a[j];
			xi = a[k + 1] + a[j + 1];
			yr = wkr * xr - wki * xi;
			yi = wkr * xi + wki * xr;
			a[k] -= yr;
			xi = a[k]*a[k];
			a[k+1] -= yi;
			xi += ( a[k+1]*a[k+1]);
			a[j] += yr;
			xr = a[j]*a[j];
			a[j+1] -= yi;
			xr += (a[j+1]*a[j+1]);

			pFFTAveBuf[k] = (1.0-1.0/m_AveSize)*pFFTAveBuf[k] + 
					(1.0/m_AveSize)*pow(xi , K_ROOT)/K_ROOTGN;
 			pFFTAveBuf[j] = (1.0-1.0/m_AveSize)*pFFTAveBuf[j] +
					(1.0/m_AveSize)*pow(xr , K_ROOT)/K_ROOTGN;
		}
	}
	pFFTAveBuf[1024] = pFFTAveBuf[1022];
}

/* -------- initializing routines -------- */
void Cfft::makewt(int nw, int *ip, double *w)
{
    int nwh, j;
    double delta, x, y;
    
    ip[0] = nw;
    ip[1] = 1;
    if (nw > 2) {
        nwh = nw >> 1;
        delta = atan(1.0) / nwh;
        w[0] = 1;
        w[1] = 0;
        w[nwh] = cos(delta * nwh);
        w[nwh + 1] = w[nwh];
        for (j = 2; j < nwh; j += 2) {
            x = cos(delta * j);
            y = sin(delta * j);
            w[j] = x;
            w[j + 1] = y;
            w[nw - j] = y;
            w[nw - j + 1] = x;
        }
        bitrv2(nw, ip + 2, w);
    }
}


void Cfft::makect(int nc, int *ip, double *c)
{
    int nch, j;
    double delta;
    
    ip[1] = nc;
    if (nc > 1) {
        nch = nc >> 1;
        delta = atan(1.0) / nch;
        c[0] = cos(delta * nch);
        c[nch] = 0.5 * c[0];
        for (j = 1; j < nch; j++) {
            c[j] = 0.5 * cos(delta * j);
            c[nc - j] = 0.5 * sin(delta * j);
        }
    }
}


/* -------- child routines -------- */
void Cfft::bitrv2(int n, int *ip, double *a)
{
    int j, j1, k, k1, l, m, m2;
    double xr, xi;
    
    ip[0] = 0;
    l = n;
    m = 1;
    while ((m << 2) < l) {
        l >>= 1;
        for (j = 0; j < m; j++) {
            ip[m + j] = ip[j] + l;
        }
        m <<= 1;
    }
    if ((m << 2) > l) {
        for (k = 1; k < m; k++) {
            for (j = 0; j < k; j++) {
                j1 = (j << 1) + ip[k];
                k1 = (k << 1) + ip[j];
                xr = a[j1];
                xi = a[j1 + 1];
                a[j1] = a[k1];
                a[j1 + 1] = a[k1 + 1];
                a[k1] = xr;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -