QPair<int,double> ConnectivityMeasures::calcCrossCorrelation(const RowVectorXd& vecFirst, const RowVectorXd& vecSecond) { Eigen::FFT<double> fft; int N = std::max(vecFirst.cols(), vecSecond.cols()); //Compute the FFT size as the "next power of 2" of the input vector's length (max) int b = ceil(log2(2.0 * N - 1)); int fftsize = pow(2,b); // int end = fftsize - 1; // int maxlag = N - 1; //Zero Padd RowVectorXd xCorrInputVecFirst = RowVectorXd::Zero(fftsize); xCorrInputVecFirst.head(vecFirst.cols()) = vecFirst; RowVectorXd xCorrInputVecSecond = RowVectorXd::Zero(fftsize); xCorrInputVecSecond.head(vecSecond.cols()) = vecSecond; //FFT for freq domain to both vectors RowVectorXcd freqvec; RowVectorXcd freqvec2; fft.fwd(freqvec, xCorrInputVecFirst); fft.fwd(freqvec2, xCorrInputVecSecond); //Create conjugate complex freqvec2.conjugate(); //Main step of cross corr for (int i = 0; i < fftsize; i++) { freqvec[i] = freqvec[i] * freqvec2[i]; } RowVectorXd result; fft.inv(result, freqvec); //Will get rid of extra zero padding RowVectorXd result2 = result;//.segment(maxlag, N); QPair<int,int> minMaxRange; int idx = 0; result2.minCoeff(&idx); minMaxRange.first = idx; result2.maxCoeff(&idx); minMaxRange.second = idx; // std::cout<<"result2(minMaxRange.first)"<<result2(minMaxRange.first)<<std::endl; // std::cout<<"result2(minMaxRange.second)"<<result2(minMaxRange.second)<<std::endl; // std::cout<<"b"<<b<<std::endl; // std::cout<<"fftsize"<<fftsize<<std::endl; // std::cout<<"end"<<end<<std::endl; // std::cout<<"maxlag"<<maxlag<<std::endl; //Return val int resultIndex = minMaxRange.second; double maxValue = result2(resultIndex); return QPair<int,double>(resultIndex, maxValue); }
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()); }
RowVectorXd FilterData::applyConvFilter(const RowVectorXd& data, bool keepOverhead, CompensateEdgeEffects compensateEdgeEffects) const { 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; } //Do zero padding or mirroring depending on user input RowVectorXd t_dataZeroPad = RowVectorXd::Zero(2*m_dCoeffA.cols() + data.cols()); RowVectorXd t_filteredTime = RowVectorXd::Zero(2*m_dCoeffA.cols() + data.cols()); 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.segment(m_dCoeffA.cols(), data.cols()) = data; break; default: t_dataZeroPad.segment(m_dCoeffA.cols(), data.cols()) = data; break; } //Do the convolution for(int i=m_dCoeffA.cols(); i<t_filteredTime.cols(); i++) t_filteredTime(i-m_dCoeffA.cols()) = t_dataZeroPad.segment(i-m_dCoeffA.cols(),m_dCoeffA.cols()) * m_dCoeffA.transpose(); //Return filtered data if(!keepOverhead) return t_filteredTime.segment(m_dCoeffA.cols()/2, data.cols()); return t_filteredTime.head(data.cols()+m_dCoeffA.cols()); }
MatrixXd RtFilter::filterChannelsConcurrently(const MatrixXd& matDataIn, int iMaxFilterLength, const QVector<int>& lFilterChannelList, const QList<FilterData>& lFilterData) { //Initialise the overlay matrix if(m_matOverlap.cols() != iMaxFilterLength || m_matOverlap.rows() < matDataIn.rows()) { m_matOverlap.resize(matDataIn.rows(), iMaxFilterLength); m_matOverlap.setZero(); } if(m_matDelay.cols() != iMaxFilterLength/2 || m_matOverlap.rows() < matDataIn.rows()) { m_matDelay.resize(matDataIn.rows(), iMaxFilterLength/2); m_matDelay.setZero(); } //Resize output matrix to match input matrix MatrixXd matDataOut(matDataIn.rows(), matDataIn.cols()); //Generate QList structure which can be handled by the QConcurrent framework QList<QPair<QList<FilterData>,QPair<int,RowVectorXd> > > timeData; QList<int> notFilterChannelIndex; //Only select channels specified in lFilterChannelList for(qint32 i = 0; i < matDataIn.rows(); ++i) { int pos = lFilterChannelList.indexOf(i); if(pos != -1 && pos < matDataIn.rows()) { timeData.append(QPair<QList<FilterData>,QPair<int,RowVectorXd> >(lFilterData,QPair<int,RowVectorXd>(pos,matDataIn.row(pos)))); } else { notFilterChannelIndex.append(i); } } //Do the concurrent filtering if(!timeData.isEmpty()) { QFuture<void> future = QtConcurrent::map(timeData, doFilterPerChannelRTMSA); future.waitForFinished(); //Do the overlap add method and store in matDataOut int iFilteredNumberCols = timeData.at(0).second.second.cols(); for(int r = 0; r < timeData.size(); r++) { //Get the currently filtered data. This data has a delay of filterLength/2 in front and back. RowVectorXd tempData = timeData.at(r).second.second; //Perform the actual overlap add by adding the last filterlength data to the newly filtered one tempData.head(iMaxFilterLength) += m_matOverlap.row(timeData.at(r).second.first); //Write the newly calulated filtered data to the filter data matrix. Keep in mind that the current block also effect last part of the last block (begin at dataIndex-iFilterDelay). int start = 0; matDataOut.row(timeData.at(r).second.first).segment(start,iFilteredNumberCols-iMaxFilterLength) = tempData.head(iFilteredNumberCols-iMaxFilterLength); //Refresh the m_matOverlap with the new calculated filtered data. m_matOverlap.row(timeData.at(r).second.first) = timeData.at(r).second.second.tail(iMaxFilterLength); } } //Fill filtered data with raw data if the channel was not filtered for(int i = 0; i < notFilterChannelIndex.size(); ++i) { matDataOut.row(notFilterChannelIndex.at(i)) << m_matDelay.row(notFilterChannelIndex.at(i)), matDataIn.row(notFilterChannelIndex.at(i)).head(matDataIn.cols() - iMaxFilterLength/2); //matDataOut.row(notFilterChannelIndex.at(i)).segment(0, matDataIn.row(notFilterChannelIndex.at(i)).cols()) = matDataIn.row(notFilterChannelIndex.at(i)); } m_matDelay = matDataIn.block(0, matDataIn.cols()-iMaxFilterLength/2, matDataIn.rows(), iMaxFilterLength/2); return matDataOut; }