RowVectorXd FilterData::applyFFTFilter(const RowVectorXd& data, bool keepOverhead, CompensateEdgeEffects compensateEdgeEffects) const { #ifdef EIGEN_FFTW_DEFAULT fftw_make_planner_thread_safe(); #endif if(data.cols()<m_dCoeffA.cols() && compensateEdgeEffects==MirrorData) { qDebug()<<QString("Error in FilterData: Number of filter taps(%1) bigger then data size(%2). Not enough data to perform mirroring!").arg(m_dCoeffA.cols()).arg(data.cols()); return data; } // std::cout<<"m_iFFTlength: "<<m_iFFTlength<<std::endl; // std::cout<<"2*m_dCoeffA.cols() + data.cols(): "<<2*m_dCoeffA.cols() + data.cols()<<std::endl; if(2*m_dCoeffA.cols() + data.cols()>m_iFFTlength) { qDebug()<<"Error in FilterData: Number of mirroring/zeropadding size plus data size is bigger then fft length!"; return data; } //Do zero padding or mirroring depending on user input RowVectorXd t_dataZeroPad = RowVectorXd::Zero(m_iFFTlength); switch(compensateEdgeEffects) { case MirrorData: t_dataZeroPad.head(m_dCoeffA.cols()) = data.head(m_dCoeffA.cols()).reverse(); //front t_dataZeroPad.segment(m_dCoeffA.cols(), data.cols()) = data; //middle t_dataZeroPad.tail(m_dCoeffA.cols()) = data.tail(m_dCoeffA.cols()).reverse(); //back break; case ZeroPad: t_dataZeroPad.head(data.cols()) = data; break; default: t_dataZeroPad.head(data.cols()) = data; break; } //generate fft object Eigen::FFT<double> fft; fft.SetFlag(fft.HalfSpectrum); //fft-transform data sequence RowVectorXcd t_freqData; fft.fwd(t_freqData,t_dataZeroPad); //perform frequency-domain filtering RowVectorXcd t_filteredFreq = m_dFFTCoeffA.array()*t_freqData.array(); //inverse-FFT RowVectorXd t_filteredTime; fft.inv(t_filteredTime,t_filteredFreq); //Return filtered data if(!keepOverhead) return t_filteredTime.segment(m_dCoeffA.cols()/2, data.cols()); return t_filteredTime.head(data.cols()+m_dCoeffA.cols()); }
Vector<Pointf> DataSource::FFT(Getdatafun getdata, double tSample, bool frequency, int type, bool window) { int numData = int(GetCount()); VectorXd timebuf(numData); int num = 0; for (int i = 0; i < numData; ++i) { double data = Membercall(getdata)(i); if (!IsNull(data)) { timebuf[i] = Membercall(getdata)(i); num++; } } Vector<Pointf> res; if (num < 3) return res; timebuf.resize(num); double windowSum = 0; if (window) { for (int i = 0; i < numData; ++i) { double windowDat = 0.54 - 0.46*cos(2*M_PI*i/numData); windowSum += windowDat; timebuf[i] *= windowDat; // Hamming window } } else windowSum = numData; VectorXcd freqbuf; try { Eigen::FFT<double> fft; fft.SetFlag(fft.HalfSpectrum); fft.fwd(freqbuf, timebuf); } catch(...) { return res; } if (frequency) { for (int i = 0; i < int(freqbuf.size()); ++i) { double xdata = i/(tSample*numData); switch (type) { case T_PHASE: res << Pointf(xdata, std::arg(freqbuf[i])); break; case T_FFT: res << Pointf(xdata, 2*std::abs(freqbuf[i])/windowSum); break; case T_PSD: res << Pointf(xdata, 2*sqr(std::abs(freqbuf[i]))/(windowSum/tSample)); } } } else { for (int i = int(freqbuf.size()) - 1; i > 0; --i) { double xdata = (tSample*numData)/i; switch (type) { case T_PHASE: res << Pointf(xdata, std::arg(freqbuf[i])); break; case T_FFT: res << Pointf(xdata, 2*std::abs(freqbuf[i])/windowSum); break; case T_PSD: res << Pointf(xdata, 2*sqr(std::abs(freqbuf[i]))/(windowSum/tSample)); } } } return res; }
void FilterData::fftTransformCoeffs() { #ifdef EIGEN_FFTW_DEFAULT fftw_make_planner_thread_safe(); #endif //zero-pad m_dCoeffA to m_iFFTlength RowVectorXd t_coeffAzeroPad = RowVectorXd::Zero(m_iFFTlength); t_coeffAzeroPad.head(m_dCoeffA.cols()) = m_dCoeffA; //generate fft object Eigen::FFT<double> fft; fft.SetFlag(fft.HalfSpectrum); //fft-transform filter coeffs m_dFFTCoeffA = RowVectorXcd::Zero(m_iFFTlength); fft.fwd(m_dFFTCoeffA,t_coeffAzeroPad); }
CosineFilter::CosineFilter(int fftLength, float lowpass, float lowpass_width, float highpass, float highpass_width, double sFreq, TPassType type) { m_iFilterOrder = fftLength; int highpasss,lowpasss; int highpass_widths,lowpass_widths; int k,s,w; int resp_size = fftLength/2+1; //Take half because we are not interested in the conjugate complex part of the spectrum double pi4 = M_PI/4.0; float mult,add,c; RowVectorXcd filterFreqResp = RowVectorXcd::Ones(resp_size); //Transform frequencies into samples highpasss = ((resp_size-1)*highpass)/(0.5*sFreq); lowpasss = ((resp_size-1)*lowpass)/(0.5*sFreq); lowpass_widths = ((resp_size-1)*lowpass_width)/(0.5*sFreq); lowpass_widths = (lowpass_widths+1)/2; if (highpass_width > 0.0) { highpass_widths = ((resp_size-1)*highpass_width)/(0.5*sFreq); highpass_widths = (highpass_widths+1)/2; } else highpass_widths = 3; //Calculate filter freq response - use cosine //Build high pass filter if(type != LPF) { if (highpasss > highpass_widths + 1) { w = highpass_widths; mult = 1.0/w; add = 3.0; for (k = 0; k < highpasss-w+1; k++) filterFreqResp(k) = 0.0; for (k = -w+1, s = highpasss-w+1; k < w; k++, s++) { if (s >= 0 && s < resp_size) { c = cos(pi4*(k*mult+add)); filterFreqResp(s) = filterFreqResp(s).real()*c*c; } } } } //Build low pass filter if(type != HPF) { if (lowpass_widths > 0) { w = lowpass_widths; mult = 1.0/w; add = 1.0; for (k = -w+1, s = lowpasss-w+1; k < w; k++, s++) { if (s >= 0 && s < resp_size) { c = cos(pi4*(k*mult+add)); filterFreqResp(s) = filterFreqResp(s).real()*c*c; } } for (k = s; k < resp_size; k++) filterFreqResp(k) = 0.0; } else { for (k = lowpasss; k < resp_size; k++) filterFreqResp(k) = 0.0; } } m_dFFTCoeffA = filterFreqResp; //Generate windowed impulse response - invert fft coeeficients to time domain Eigen::FFT<double> fft; fft.SetFlag(fft.HalfSpectrum); //invert to time domain and fft.inv(m_dCoeffA, filterFreqResp);/* m_dCoeffA = m_dCoeffA.segment(0,1024).eval(); //window/zero-pad m_dCoeffA to m_iFFTlength RowVectorXd t_coeffAzeroPad = RowVectorXd::Zero(fftLength); t_coeffAzeroPad.head(m_dCoeffA.cols()) = m_dCoeffA; //fft-transform filter coeffs m_dFFTCoeffA = RowVectorXcd::Zero(fftLength); fft.fwd(m_dFFTCoeffA,t_coeffAzeroPad);*/ }