////////////////////////////////////////////////////////////////////// // 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); }
/////////////////////////////////////////////////////////////////////////// // 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 }
//////////////////////////////////////////////////////////////////// // Create a FIR high Pass filter with scaled amplitude 'Scale' // NumTaps if non-zero, forces filter design to be this number of taps // Astop = Stopband Atenuation in dB (ie 40dB is 40dB stopband attenuation) // Fpass = Highpass passband frequency in Hz // Fstop = Highpass stopband frequency in Hz // Fsamprate = Sample Rate in Hz // // Apass ------------- // / // / // / // / // Astop --------- // Fstop Fpass //////////////////////////////////////////////////////////////////// int CFir::InitHPFilter(int NumTaps, TYPEREAL Scale, TYPEREAL Astop, TYPEREAL Fpass, TYPEREAL Fstop, TYPEREAL Fsamprate) { int n; TYPEREAL Beta; //m_Mutex.lock(); m_SampleRate = Fsamprate; //create normalized frequency parameters TYPEREAL normFpass = Fpass/Fsamprate; TYPEREAL normFstop = Fstop/Fsamprate; TYPEREAL normFcut = (normFstop + normFpass)/2.0; //high pass filter 6dB cutoff //calculate Kaiser-Bessel window shape factor, Beta, from stopband attenuation if(Astop < 20.96) Beta = 0; else if(Astop >= 50.0) Beta = .1102 * (Astop - 8.71); else Beta = .5842 * MPOW( (Astop-20.96), 0.4) + .07886 * (Astop - 20.96); //Now Estimate number of filter taps required based on filter specs m_NumTaps = (Astop - 8.0) / (2.285*K_2PI*(normFpass - normFstop ) ) + 1; //clamp range of filter taps if(m_NumTaps>(MAX_NUMCOEF-1) ) m_NumTaps = MAX_NUMCOEF-1; if(m_NumTaps < 3) m_NumTaps = 3; m_NumTaps |= 1; //force to next odd number if(NumTaps) //if need to force to to a number of taps m_NumTaps = NumTaps; TYPEREAL izb = Izero(Beta); //precalculate denominator since is same for all points TYPEREAL fCenter = .5*(TYPEREAL)(m_NumTaps-1); for( n=0; n < m_NumTaps; n++) { TYPEREAL x = (TYPEREAL)n - (TYPEREAL)(m_NumTaps-1)/2.0; TYPEREAL c; // create ideal Sinc() HP filter with normFcut if( (TYPEREAL)n == fCenter ) //deal with odd size filter singularity where sin(0)/0==1 c = 1.0 - 2.0 * normFcut; else c = (TYPEREAL) (MSIN(K_PI*x)/(K_PI*x) - MSIN(K_2PI*x*normFcut)/(K_PI*x) ); //calculate Kaiser window and multiply to get coefficient x = ((TYPEREAL)n - ((TYPEREAL)m_NumTaps-1.0)/2.0 ) / (((TYPEREAL)m_NumTaps-1.0)/2.0); m_Coef[n] = Scale * c * Izero( Beta * MSQRT(1 - (x*x) ) ) / izb; } //make a 2x length array for FIR flat calculation efficiency for (n = 0; n < m_NumTaps; n++) m_Coef[n+m_NumTaps] = m_Coef[n]; //copy into complex coef buffers for (n = 0; n < m_NumTaps*2; n++) { m_ICoef[n] = m_Coef[n]; m_QCoef[n] = m_Coef[n]; } //Initialize the FIR buffers and state for(int i=0; i<m_NumTaps; i++) { m_rZBuf[i] = 0.0; m_cZBuf[i].re = 0.0; m_cZBuf[i].im = 0.0; } m_State = 0; //m_Mutex.unlock(); #if 0 //debug hack to write m_Coef to a file for analysis QDir::setCurrent("d:/"); QFile File; File.setFileName("hpcoef.txt"); if(File.open(QIODevice::WriteOnly)) { qDebug()<<"file Opened OK"; char Buf[256]; for(n=0; n<m_NumTaps; n++) { sprintf( Buf, "%g\r\n", m_Coef[n]); File.write(Buf); } } else qDebug()<<"file Failed to Open"; qDebug()<<"HP taps="<<m_NumTaps; #endif return m_NumTaps; }