75 QSharedPointer<FiffRawData> pFiffRawData,
83 const RowVectorXi& vecPicks,
87 dCenterfreq = dCenterfreq/(dSFreq/2.0);
88 bandwidth = bandwidth/(dSFreq/2.0);
89 dTransition = dTransition/(dSFreq/2.0);
111 QSharedPointer<FiffRawData> pFiffRawData,
113 const RowVectorXi& vecPicks,
119 SparseMatrix<double> mult;
128 float fFactor = 2.0f;
129 int iSize = fFactor * iOrder;
130 int residual = (to - from) % iSize;
131 while(residual < iOrder) {
132 fFactor = fFactor - 0.1f;
133 iSize = fFactor * iOrder;
134 residual = (to - from) % iSize;
136 if((iSize < iOrder)) {
137 qInfo() <<
"[Filter::filterData] Sliced data block size is too small. Filtering whole block at once.";
143 float quantum_sec = iSize/pFiffRawData->info.sfreq;
144 fiff_int_t quantum = ceil(quantum_sec*pFiffRawData->info.sfreq);
147 bool first_buffer =
true;
150 MatrixXd matData, matDataOverlap;
153 for(first = from; first < to; first+=quantum) {
154 last = first+quantum-1;
159 if (!pFiffRawData->read_raw_segment(matData, times, mult, first, last, sel)) {
160 qWarning(
"[Filter::filterData] Error during read_raw_segment\n");
164 qInfo() <<
"Filtering and writing block" << first <<
"to" << last;
170 first_buffer =
false;
179 outfid->write_raw_buffer(matData.block(0,iOrder/2,matData.rows(),matData.cols()-iOrder), cals);
180 }
else if(first + quantum >= to) {
181 matData.block(0,0,matData.rows(),iOrder) += matDataOverlap;
182 outfid->write_raw_buffer(matData.block(0,0,matData.rows(),matData.cols()-iOrder), cals);
184 matData.block(0,0,matData.rows(),iOrder) += matDataOverlap;
185 outfid->write_raw_buffer(matData.block(0,0,matData.rows(),matData.cols()-iOrder), cals);
188 matDataOverlap = matData.block(0,matData.cols()-iOrder,matData.rows(),iOrder);
191 outfid->finish_writing_raw();
206 const RowVectorXi& vecPicks,
211 if(matData.cols() < iOrder){
212 qWarning() << QString(
"[Filter::filterData] Filter length/order is bigger than data length. Returning.");
217 dCenterfreq = dCenterfreq/(dSFreq/2.0);
218 bandwidth = bandwidth/(dSFreq/2.0);
219 dTransition = dTransition/(dSFreq/2.0);
242 const RowVectorXi& vecPicks,
249 if(matData.cols() < iOrder){
250 qWarning() <<
"[Filter::filterData] Filter length/order is bigger than data length. Returning.";
255 MatrixXd matDataOut(matData.rows(), matData.cols()+iOrder);
256 matDataOut.setZero();
257 MatrixXd sliceFiltered;
260 float fFactor = 2.0f;
261 int iSize = fFactor * iOrder;
262 int residual = matData.cols() % iSize;
263 while(residual < iOrder) {
264 fFactor = fFactor - 0.1f;
265 iSize = fFactor * iOrder;
266 residual = matData.cols() % iSize;
269 iSize = matData.cols();
274 if(matData.cols() > iSize) {
276 int numSlices = ceil(
float(matData.cols())/
float(iSize));
278 for (
int i = 0; i < numSlices; i++) {
279 if(i == numSlices-1) {
281 iSize = matData.cols() - (iSize * (numSlices -1));
285 sliceFiltered =
filterDataBlock(matData.block(0,from,matData.rows(),iSize),
292 matDataOut.block(0,0,matData.rows(),sliceFiltered.cols()) += sliceFiltered;
294 matDataOut.block(0,from,matData.rows(),sliceFiltered.cols()) += sliceFiltered;
309 return matDataOut.block(0,iOrder/2,matDataOut.rows(),matData.cols());
316 const RowVectorXi& vecPicks,
323 if(matData.cols() < iOrder){
324 qWarning() << QString(
"[Filter::filterDataBlock] Filter length/order is bigger than data length. Returning.");
333 RowVectorXi vecPicksNew = vecPicks;
334 if(vecPicksNew.cols() == 0) {
335 vecPicksNew = RowVectorXi::LinSpaced(matData.rows(), 0, matData.rows());
339 QList<FilterObject> timeData;
343 for(qint32 i = 0; i < vecPicksNew.cols(); ++i) {
345 data.
iRow = vecPicksNew[i];
346 data.
vecData = matData.row(vecPicksNew[i]);
347 timeData.append(data);
351 MatrixXd matDataOut(matData.rows(), matData.cols()+iOrder);
352 matDataOut.setZero();
353 matDataOut.block(0, iOrder/2, matData.rows(), matData.cols()) = matData;
356 QFuture<void> future = QtConcurrent::map(timeData,
358 future.waitForFinished();
360 for(
int i = 0; i < timeData.size(); ++i) {
366 RowVectorXd tempData;
368 for(
int r = 0; r < timeData.size(); r++) {
370 matDataOut.row(timeData.at(r).iRow) = timeData.at(r).vecData;
396 const RowVectorXi& vecPicks,
402 if(matData.cols() < iOrder){
403 qWarning() << QString(
"[Filter::filterData] Filter length/order is bigger than data length. Returning.");
408 dCenterfreq = dCenterfreq/(dSFreq/2.0);
409 bandwidth = bandwidth/(dSFreq/2.0);
410 dTransition = dTransition/(dSFreq/2.0);
413 FilterKernel filter = FilterKernel(
"filter_kernel",
433 const FilterKernel& filterKernel,
434 const RowVectorXi& vecPicks,
442 if(matData.cols() < iOrder){
443 qWarning() <<
"[Filter::filterData] Filter length/order is bigger than data length. Returning.";
448 if(m_matOverlapBack.cols() != iOrder || m_matOverlapBack.rows() < matData.rows()) {
449 m_matOverlapBack.resize(matData.rows(), iOrder);
450 m_matOverlapBack.setZero();
453 if(m_matOverlapFront.cols() != iOrder || m_matOverlapFront.rows() < matData.rows()) {
454 m_matOverlapFront.resize(matData.rows(), iOrder);
455 m_matOverlapFront.setZero();
459 MatrixXd matDataOut(matData.rows(), matData.cols()+iOrder);
460 matDataOut.setZero();
461 MatrixXd sliceFiltered;
464 float fFactor = 2.0f;
465 int iSize = fFactor * iOrder;
466 int residual = matData.cols() % iSize;
467 while(residual < iOrder) {
468 fFactor = fFactor - 0.1f;
469 iSize = fFactor * iOrder;
470 residual = matData.cols() % iSize;
473 iSize = matData.cols();
478 if(matData.cols() > iSize) {
480 int numSlices = ceil(
float(matData.cols())/
float(iSize));
482 for (
int i = 0; i < numSlices; i++) {
483 if(i == numSlices-1) {
485 iSize = matData.cols() - (iSize * (numSlices -1));
489 sliceFiltered =
filterDataBlock(matData.block(0,from,matData.rows(),iSize),
495 matDataOut.block(0,0,matData.rows(),sliceFiltered.cols()) += sliceFiltered;
497 matDataOut.block(0,from,matData.rows(),sliceFiltered.cols()) += sliceFiltered;
500 if(bFilterEnd && (i == 0)) {
501 matDataOut.block(0,0,matDataOut.rows(),iOrder) += m_matOverlapBack;
502 }
else if (!bFilterEnd && (i == numSlices-1)) {
503 matDataOut.block(0,matDataOut.cols()-iOrder,matDataOut.rows(),iOrder) += m_matOverlapFront;
515 matDataOut.block(0,0,matDataOut.rows(),iOrder) += m_matOverlapBack;
517 matDataOut.block(0,matDataOut.cols()-iOrder,matDataOut.rows(),iOrder) += m_matOverlapFront;
522 m_matOverlapBack = matDataOut.block(0,matDataOut.cols()-iOrder,matDataOut.rows(),iOrder);
523 m_matOverlapFront = matDataOut.block(0,0,matDataOut.rows(),iOrder);
528 return matDataOut.block(0,0,matDataOut.rows(),matData.cols());
536 m_matOverlapBack.resize(0,0);
537 m_matOverlapFront.resize(0,0);
543 const MatrixXi& matEvents,
548 float fTBaselineFromS,
550 const QMap<QString,double>& mapReject,
552 const QStringList& lExcludeChs,
553 const RowVectorXi& picks)
560 MatrixXi selected = MatrixXi::Zero(1, matEvents.rows());
561 for (p = 0; p < matEvents.rows(); ++p)
563 if (matEvents(p,1) == 0 && matEvents(p,2) == eventType)
565 selected(0,count) = p;
569 selected.conservativeResize(1, count);
571 qInfo(
"[RTPROCESSINGLIB::computeFilteredAverage] %d matching events found",count);
575 RowVectorXi picksNew = picks;
576 if(picks.cols() <= 0) {
577 picksNew.resize(raw.
info.
chs.size());
578 for(
int i = 0; i < raw.
info.
chs.size(); ++i) {
588 std::unique_ptr<MNEEpochData> epoch;
591 for (p = 0; p < count; ++p) {
593 event_samp = matEvents(selected(p),0);
594 from = event_samp + fTMinS*raw.
info.
sfreq;
595 to = event_samp + floor(fTMaxS*raw.
info.
sfreq + 0.5);
597 epoch = std::make_unique<MNEEpochData>();
599 if(raw.
read_raw_segment(epoch->epoch, timesDummy, from - iFilterDelay, to + iFilterDelay, picksNew)) {
604 times.resize(1, to-from+1);
605 for (qint32 i = 0; i < times.cols(); ++i)
606 times(0, i) = ((float)(from-event_samp+i)) / raw.
info.
sfreq;
609 epoch->event = eventType;
610 epoch->tmin = fTMinS;
611 epoch->tmax = fTMaxS;
618 if (epoch->bReject) {
623 if(!lstEpochDataList.isEmpty()) {
624 if(epoch->epoch.size() == lstEpochDataList.last()->epoch.size()) {
631 qWarning(
"[MNEEpochDataList::readEpochs] Can't read the event data segments.");
635 qInfo().noquote() <<
"[MNEEpochDataList::readEpochs] Read a total of"<< lstEpochDataList.size() <<
"epochs of type" << eventType <<
"and marked"<< dropCount <<
"for rejection.";
638 QPair<float, float> baselinePair(fTBaselineFromS, fTBaselineToS);
642 if(!mapReject.isEmpty()) {
648 lstEpochDataList.first()->epoch.cols());
FiffRawData class declaration.
Header file describing the numerical values used in fif files.
#define FIFF_FIRST_SAMPLE
MNEEpochDataList class declaration.
MNEEpochData class declaration.
Core MNE data structures (source spaces, source estimates, hemispheres).
FIFF file I/O and data structures (raw, epochs, evoked, covariance, forward).
DSPSHARED_EXPORT FIFFLIB::FiffEvoked computeFilteredAverage(const FIFFLIB::FiffRawData &raw, const Eigen::MatrixXi &matEvents, float fTMinS, float fTMaxS, qint32 eventType, bool bApplyBaseline, float fTBaselineFromS, float fTBaselineToS, const QMap< QString, double > &mapReject, const UTILSLIB::FilterKernel &filterKernel, const QStringList &lExcludeChs=QStringList(), const Eigen::RowVectorXi &vecPicks=Eigen::RowVectorXi())
DSPSHARED_EXPORT Eigen::MatrixXd filterData(const Eigen::MatrixXd &matData, int type, double dCenterfreq, double dBandwidth, double dTransition, double dSFreq, int iOrder=1024, int designMethod=UTILSLIB::FilterKernel::m_designMethods.indexOf(UTILSLIB::FilterParameter("Cosine")), const Eigen::RowVectorXi &vecPicks=Eigen::RowVectorXi(), bool bUseThreads=true, bool bKeepOverhead=false)
DSPSHARED_EXPORT Eigen::MatrixXd filterDataBlock(const Eigen::MatrixXd &matData, const Eigen::RowVectorXi &vecPicks, const UTILSLIB::FilterKernel &filterKernel, bool bUseThreads=true)
DSPSHARED_EXPORT void filterChannel(FilterObject &channelDataTime)
DSPSHARED_EXPORT bool filterFile(QIODevice &pIODevice, QSharedPointer< FIFFLIB::FiffRawData > pFiffRawData, int type, double dCenterfreq, double dBandwidth, double dTransition, double dSFreq, int iOrder=4096, int designMethod=UTILSLIB::FilterKernel::m_designMethods.indexOf(UTILSLIB::FilterParameter("Cosine")), const Eigen::RowVectorXi &vecPicks=Eigen::RowVectorXi(), bool bUseThreads=true)
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
The FilterKernel class provides methods to create/design a FIR filter kernel.
void applyFftFilter(Eigen::RowVectorXd &vecData, bool bKeepOverhead=false)
void prepareFilter(int iDataSize)
int getFilterOrder() const
Lightweight filter configuration holding kernel coefficients and overlap-add state for one channel.
UTILSLIB::FilterKernel filterKernel
Eigen::RowVectorXd vecData
Eigen::MatrixXd calculate(const Eigen::MatrixXd &matData, int type, double dCenterfreq, double dBandwidth, double dTransition, double dSFreq, int iOrder=1024, int designMethod=UTILSLIB::FilterKernel::m_designMethods.indexOf(UTILSLIB::FilterParameter("Cosine")), const Eigen::RowVectorXi &vecPicks=Eigen::RowVectorXi(), bool bFilterEnd=true, bool bUseThreads=true, bool bKeepOverhead=false)
FIFF raw measurement data.
bool read_raw_segment(Eigen::MatrixXd &data, Eigen::MatrixXd ×, fiff_int_t from=-1, fiff_int_t to=-1, const Eigen::RowVectorXi &sel=defaultRowVectorXi, bool do_debug=false) const
QSharedPointer< FiffStream > SPtr
static FiffStream::SPtr start_writing_raw(QIODevice &p_IODevice, const FiffInfo &info, Eigen::RowVectorXd &cals, Eigen::MatrixXi sel=defaultMatrixXi, bool bResetRange=true)
QSharedPointer< MNEEpochData > SPtr
FIFFLIB::FiffEvoked average(const FIFFLIB::FiffInfo &p_info, FIFFLIB::fiff_int_t first, FIFFLIB::fiff_int_t last, Eigen::VectorXi sel=FIFFLIB::defaultVectorXi, bool proj=false)
void applyBaselineCorrection(const QPair< float, float > &baseline)
static bool checkForArtifact(const Eigen::MatrixXd &data, const FIFFLIB::FiffInfo &pFiffInfo, const QMap< QString, double > &mapReject, const QStringList &lExcludeChs=QStringList())