//////////////////////////////////////////////////////////////////////
//  Call to setup filter parameters
// SampleRate in Hz
// FLowcut is low cutoff frequency of filter in Hz
// FHicut is high cutoff frequency of filter in Hz
// Offset is the CW tone offset frequency
// cutoff frequencies range from -SampleRate/2 to +SampleRate/2
//  HiCut must be greater than LowCut
//		example to make 2700Hz USB filter:
//	SetupParameters( 100, 2800, 0, 48000);
//////////////////////////////////////////////////////////////////////
void CFastFIR::SetupParameters( TYPEREAL FLoCut, TYPEREAL FHiCut,
								TYPEREAL Offset, TYPEREAL SampleRate)
{
int i;
	if( (FLoCut==m_FLoCut) && (FHiCut==m_FHiCut) &&
		(Offset==m_Offset) && (SampleRate==m_SampleRate) )
	{
		return;		//return if no changes
	}
	m_FLoCut = FLoCut;
	m_FHiCut = FHiCut;
	m_Offset = Offset;
	m_SampleRate = SampleRate;

	FLoCut += Offset;
	FHiCut += Offset;
	//sanity check on filter parameters
	if( (FLoCut >= FHiCut) ||
		(FLoCut >= SampleRate/2.0) ||
		(FLoCut <= -SampleRate/2.0) ||
		(FHiCut >= SampleRate/2.0) ||
		(FHiCut <= -SampleRate/2.0) )
	{
		fprintf(stderr, "Filter Parameter error:\n");
		return;
	}

	//calculate some normalized filter parameters
	TYPEREAL nFL = FLoCut/SampleRate;
	TYPEREAL nFH = FHiCut/SampleRate;
	TYPEREAL nFc = (nFH-nFL)/2.0;		//prototype LP filter cutoff
	TYPEREAL nFs = K_2PI*(nFH+nFL)/2.0;		//2 PI times required frequency shift (FHiCut+FLoCut)/2
	TYPEREAL fCenter = 0.5*(TYPEREAL)(CONV_FIR_SIZE-1);	//floating point center index of FIR filter

	for(i=0; i<CONV_FFT_SIZE; i++)		//zero pad entire coefficient buffer to FFT size
	{
		m_pFilterCoef[i].re = 0.0;
		m_pFilterCoef[i].im = 0.0;
	}

	//create LP FIR windowed sinc, sin(x)/x complex LP filter coefficients
	for(i=0; i<CONV_FIR_SIZE; i++)
	{
		TYPEREAL x = (TYPEREAL)i - fCenter;
		TYPEREAL z;
		if( (TYPEREAL)i == fCenter )	//deal with odd size filter singularity where sin(0)/0==1
			z = 2.0 * nFc;
		else
			z = (TYPEREAL)MSIN(K_2PI*x*nFc)/(K_PI*x) * m_pWindowTbl[i];

		//shift lowpass filter coefficients in frequency by (hicut+lowcut)/2 to form bandpass filter anywhere in range
		// (also scales by 1/FFTsize since inverse FFT routine scales by FFTsize)
		m_pFilterCoef[i].re  =  z * MCOS(nFs * x)/(TYPEREAL)CONV_FFT_SIZE;
		m_pFilterCoef[i].im = z * MSIN(nFs * x)/(TYPEREAL)CONV_FFT_SIZE;
	}

	//convert FIR coefficients to frequency domain by taking forward FFT
	m_Fft.FwdFFT(m_pFilterCoef);

}
Exemple #2
0
///////////////////////////////////////////////////////////////////////////
// function to convert LP filter coefficients into complex hilbert bandpass
// filter coefficients.
// Hbpreal(n)= 2*Hlp(n)*MCOS( 2PI*FreqOffset*(n-(N-1)/2)/samplerate );
// Hbpimaj(n)= 2*Hlp(n)*MSIN( 2PI*FreqOffset*(n-(N-1)/2)/samplerate );
void CFir::GenerateHBFilter( TYPEREAL FreqOffset)
{
int n;
	for(n=0; n<m_NumTaps; n++)
	{
		// apply complex frequency shift transform to low pass filter coefficients
		m_ICoef[n] = 2.0 * m_Coef[n] * MCOS( (K_2PI*FreqOffset/m_SampleRate)*((TYPEREAL)n - ( (TYPEREAL)(m_NumTaps-1)/2.0 ) ) );
		m_QCoef[n] = 2.0 * m_Coef[n] * MSIN( (K_2PI*FreqOffset/m_SampleRate)*((TYPEREAL)n - ( (TYPEREAL)(m_NumTaps-1)/2.0 ) ) );
	}
	//make a 2x length array for FIR flat calculation efficiency
	for (n = 0; n < m_NumTaps; n++)
	{
		m_ICoef[n+m_NumTaps] = m_ICoef[n];
		m_QCoef[n+m_NumTaps] = m_QCoef[n];
	}
#if 0		//debug hack to write m_Coef's to a file for analysis
	QDir::setCurrent("d:/");
	QFile File;
	File.setFileName("hbpcoef.txt");
	if(File.open(QIODevice::WriteOnly))
	{
		qDebug()<<"file Opened OK";
		char Buf[256];
		for( n=0; n<m_NumTaps; n++)
		{
			sprintf( Buf, "%19.12g %19.12g\r\n", m_ICoef[n], m_QCoef[n]);
			File.write(Buf);
		}
	}
	else
		qDebug()<<"file Failed to Open";
	qDebug()<<"HBP taps="<<m_NumTaps << m_SampleRate;
#endif
}
CFastFIR::CFastFIR()
{
int i;
	m_pWindowTbl = NULL;
	m_pFFTBuf = NULL;
	m_pFFTOverlapBuf = NULL;
	m_pFilterCoef = NULL;
	//allocate internal buffer space on Heap
	m_pWindowTbl = new TYPEREAL[CONV_FIR_SIZE];
	m_pFilterCoef = new TYPECPX[CONV_FFT_SIZE];
	m_pFFTBuf = new TYPECPX[CONV_FFT_SIZE];
	m_pFFTOverlapBuf = new TYPECPX[CONV_FIR_SIZE];

	if(!m_pWindowTbl || !m_pFilterCoef || !m_pFFTBuf || !m_pFFTOverlapBuf)
	{
		//major poblems if memory fails here
		return;
	}
	m_InBufInPos = (CONV_FIR_SIZE - 1);
	for( i=0; i<CONV_FFT_SIZE; i++)
	{
		m_pFFTBuf[i].re = 0.0;
		m_pFFTBuf[i].im = 0.0;
	}
#if 1
	//create Blackman-Nuttall window function for windowed sinc low pass filter design
	for( i=0; i<CONV_FIR_SIZE; i++)
	{
		m_pWindowTbl[i] = (0.3635819
			- 0.4891775*MCOS( (K_2PI*i)/(CONV_FIR_SIZE-1) )
			+ 0.1365995*MCOS( (2.0*K_2PI*i)/(CONV_FIR_SIZE-1) )
			- 0.0106411*MCOS( (3.0*K_2PI*i)/(CONV_FIR_SIZE-1) ) );
		m_pFFTOverlapBuf[i].re = 0.0;
		m_pFFTOverlapBuf[i].im = 0.0;
	}
#endif
#if 0
	//create Blackman-Harris window function for windowed sinc low pass filter design
	for( i=0; i<CONV_FIR_SIZE; i++)
	{
		m_pWindowTbl[i] = (0.35875
			- 0.48829*MCOS( (K_2PI*i)/(CONV_FIR_SIZE-1) )
			+ 0.14128*MCOS( (2.0*K_2PI*i)/(CONV_FIR_SIZE-1) )
			- 0.01168*MCOS( (3.0*K_2PI*i)/(CONV_FIR_SIZE-1) ) );
		m_pFFTOverlapBuf[i].re = 0.0;
		m_pFFTOverlapBuf[i].im = 0.0;
	}
#endif
#if 0
	//create Nuttall window function for windowed sinc low pass filter design
	for( i=0; i<CONV_FIR_SIZE; i++)
	{
		m_pWindowTbl[i] = (0.355768
			- 0.487396*MCOS( (K_2PI*i)/(CONV_FIR_SIZE-1) )
			+ 0.144232*MCOS( (2.0*K_2PI*i)/(CONV_FIR_SIZE-1) )
			- 0.012604*MCOS( (3.0*K_2PI*i)/(CONV_FIR_SIZE-1) ) );
		m_pFFTOverlapBuf[i].re = 0.0;
		m_pFFTOverlapBuf[i].im = 0.0;
	}
#endif
	m_Fft.SetFFTParams(CONV_FFT_SIZE, false, 0.0, 1.0);
	m_FLoCut = -1.0;
	m_FHiCut = 1.0;
	m_Offset = 1.0;
	m_SampleRate = 1.0;
}