52 QSharedPointer<FiffRawData> pFiffRawData,
60 const RowVectorXi& vecPicks,
64 dCenterfreq = dCenterfreq/(dSFreq/2.0);
65 bandwidth = bandwidth/(dSFreq/2.0);
66 dTransition = dTransition/(dSFreq/2.0);
88 QSharedPointer<FiffRawData> pFiffRawData,
90 const RowVectorXi& vecPicks,
96 SparseMatrix<double> mult;
101 fiff_int_t from = pFiffRawData->first_samp;
102 fiff_int_t to = pFiffRawData->last_samp;
105 float fFactor = 2.0f;
106 int iSize = fFactor * iOrder;
107 int residual = (to - from) % iSize;
108 while(residual < iOrder) {
109 fFactor = fFactor - 0.1f;
110 iSize = fFactor * iOrder;
111 residual = (to - from) % iSize;
113 if((iSize < iOrder)) {
114 qInfo() <<
"[Filter::filterData] Sliced data block size is too small. Filtering whole block at once.";
120 float quantum_sec = iSize/pFiffRawData->info.sfreq;
121 fiff_int_t quantum = ceil(
static_cast<double>(quantum_sec)*pFiffRawData->info.sfreq);
124 bool first_buffer =
true;
126 fiff_int_t first, last;
127 MatrixXd matData, matDataOverlap;
130 for(first = from; first < to; first+=quantum) {
131 last = first+quantum-1;
136 if (!pFiffRawData->read_raw_segment(matData, times, mult, first, last, sel)) {
137 qWarning(
"[Filter::filterData] Error during read_raw_segment\n");
141 qInfo() <<
"Filtering and writing block" << first <<
"to" << last;
147 first_buffer =
false;
156 outfid->write_raw_buffer(matData.block(0,iOrder/2,matData.rows(),matData.cols()-iOrder), cals);
157 }
else if(first + quantum >= to) {
158 matData.block(0,0,matData.rows(),iOrder) += matDataOverlap;
159 outfid->write_raw_buffer(matData.block(0,0,matData.rows(),matData.cols()-iOrder), cals);
161 matData.block(0,0,matData.rows(),iOrder) += matDataOverlap;
162 outfid->write_raw_buffer(matData.block(0,0,matData.rows(),matData.cols()-iOrder), cals);
165 matDataOverlap = matData.block(0,matData.cols()-iOrder,matData.rows(),iOrder);
168 outfid->finish_writing_raw();
183 const RowVectorXi& vecPicks,
188 if(matData.cols() < iOrder){
189 qWarning() << QString(
"[Filter::filterData] Filter length/order is bigger than data length. Returning.");
194 dCenterfreq = dCenterfreq/(dSFreq/2.0);
195 bandwidth = bandwidth/(dSFreq/2.0);
196 dTransition = dTransition/(dSFreq/2.0);
219 const RowVectorXi& vecPicks,
226 if(matData.cols() < iOrder){
227 qWarning() <<
"[Filter::filterData] Filter length/order is bigger than data length. Returning.";
232 MatrixXd matDataOut(matData.rows(), matData.cols()+iOrder);
233 matDataOut.setZero();
234 MatrixXd sliceFiltered;
237 float fFactor = 2.0f;
238 int iSize = fFactor * iOrder;
239 int residual = matData.cols() % iSize;
240 while(residual < iOrder) {
241 fFactor = fFactor - 0.1f;
242 iSize = fFactor * iOrder;
243 residual = matData.cols() % iSize;
246 iSize = matData.cols();
251 if(matData.cols() > iSize) {
253 int numSlices = ceil(
float(matData.cols())/
float(iSize));
255 for (
int i = 0; i < numSlices; i++) {
256 if(i == numSlices-1) {
258 iSize = matData.cols() - (iSize * (numSlices -1));
262 sliceFiltered =
filterDataBlock(matData.block(0,from,matData.rows(),iSize),
269 matDataOut.block(0,0,matData.rows(),sliceFiltered.cols()) += sliceFiltered;
271 matDataOut.block(0,from,matData.rows(),sliceFiltered.cols()) += sliceFiltered;
286 return matDataOut.block(0,iOrder/2,matDataOut.rows(),matData.cols());
293 const RowVectorXi& vecPicks,
300 if(matData.cols() < iOrder){
301 qWarning() << QString(
"[Filter::filterDataBlock] Filter length/order is bigger than data length. Returning.");
310 RowVectorXi vecPicksNew = vecPicks;
311 if(vecPicksNew.cols() == 0) {
312 vecPicksNew = RowVectorXi::LinSpaced(matData.rows(), 0, matData.rows());
316 QList<FilterObject> timeData;
320 for(qint32 i = 0; i < vecPicksNew.cols(); ++i) {
322 data.
iRow = vecPicksNew[i];
323 data.
vecData = matData.row(vecPicksNew[i]);
324 timeData.append(data);
328 MatrixXd matDataOut(matData.rows(), matData.cols()+iOrder);
329 matDataOut.setZero();
330 matDataOut.block(0, iOrder/2, matData.rows(), matData.cols()) = matData;
333 QFuture<void> future = QtConcurrent::map(timeData,
335 future.waitForFinished();
337 for(
int i = 0; i < timeData.size(); ++i) {
343 RowVectorXd tempData;
345 for(
int r = 0; r < timeData.size(); r++) {
347 matDataOut.row(timeData.at(r).iRow) = timeData.at(r).vecData;
373 const RowVectorXi& vecPicks,
379 if(matData.cols() < iOrder){
380 qWarning() << QString(
"[Filter::filterData] Filter length/order is bigger than data length. Returning.");
385 dCenterfreq = dCenterfreq/(dSFreq/2.0);
386 bandwidth = bandwidth/(dSFreq/2.0);
387 dTransition = dTransition/(dSFreq/2.0);
390 FilterKernel filter = FilterKernel(
"filter_kernel",
410 const FilterKernel& filterKernel,
411 const RowVectorXi& vecPicks,
419 if(matData.cols() < iOrder){
420 qWarning() <<
"[Filter::filterData] Filter length/order is bigger than data length. Returning.";
425 if(m_matOverlapBack.cols() != iOrder || m_matOverlapBack.rows() < matData.rows()) {
426 m_matOverlapBack.resize(matData.rows(), iOrder);
427 m_matOverlapBack.setZero();
430 if(m_matOverlapFront.cols() != iOrder || m_matOverlapFront.rows() < matData.rows()) {
431 m_matOverlapFront.resize(matData.rows(), iOrder);
432 m_matOverlapFront.setZero();
436 MatrixXd matDataOut(matData.rows(), matData.cols()+iOrder);
437 matDataOut.setZero();
438 MatrixXd sliceFiltered;
441 float fFactor = 2.0f;
442 int iSize = fFactor * iOrder;
443 int residual = matData.cols() % iSize;
444 while(residual < iOrder) {
445 fFactor = fFactor - 0.1f;
446 iSize = fFactor * iOrder;
447 residual = matData.cols() % iSize;
450 iSize = matData.cols();
455 if(matData.cols() > iSize) {
457 int numSlices = ceil(
float(matData.cols())/
float(iSize));
459 for (
int i = 0; i < numSlices; i++) {
460 if(i == numSlices-1) {
462 iSize = matData.cols() - (iSize * (numSlices -1));
466 sliceFiltered =
filterDataBlock(matData.block(0,from,matData.rows(),iSize),
472 matDataOut.block(0,0,matData.rows(),sliceFiltered.cols()) += sliceFiltered;
474 matDataOut.block(0,from,matData.rows(),sliceFiltered.cols()) += sliceFiltered;
477 if(bFilterEnd && (i == 0)) {
478 matDataOut.block(0,0,matDataOut.rows(),iOrder) += m_matOverlapBack;
479 }
else if (!bFilterEnd && (i == numSlices-1)) {
480 matDataOut.block(0,matDataOut.cols()-iOrder,matDataOut.rows(),iOrder) += m_matOverlapFront;
492 matDataOut.block(0,0,matDataOut.rows(),iOrder) += m_matOverlapBack;
494 matDataOut.block(0,matDataOut.cols()-iOrder,matDataOut.rows(),iOrder) += m_matOverlapFront;
499 m_matOverlapBack = matDataOut.block(0,matDataOut.cols()-iOrder,matDataOut.rows(),iOrder);
500 m_matOverlapFront = matDataOut.block(0,0,matDataOut.rows(),iOrder);
505 return matDataOut.block(0,0,matDataOut.rows(),matData.cols());
513 m_matOverlapBack.resize(0,0);
514 m_matOverlapFront.resize(0,0);
520 const MatrixXi& matEvents,
525 float fTBaselineFromS,
527 const QMap<QString,double>& mapReject,
529 const QStringList& lExcludeChs,
530 const RowVectorXi& picks)
537 MatrixXi selected = MatrixXi::Zero(1, matEvents.rows());
538 for (p = 0; p < matEvents.rows(); ++p)
540 if (matEvents(p,1) == 0 && matEvents(p,2) == eventType)
542 selected(0,count) = p;
546 selected.conservativeResize(1, count);
548 qInfo(
"[RTPROCESSINGLIB::computeFilteredAverage] %d matching events found",count);
552 RowVectorXi picksNew = picks;
553 if(picks.cols() <= 0) {
554 picksNew.resize(raw.
info.
chs.size());
555 for(
int i = 0; i < raw.
info.
chs.size(); ++i) {
560 fiff_int_t event_samp, from, to;
561 fiff_int_t dropCount = 0;
565 std::unique_ptr<MNEEpochData> epoch;
568 for (p = 0; p < count; ++p) {
570 event_samp = matEvents(selected(p),0);
571 from = event_samp + fTMinS*raw.
info.
sfreq;
572 to = event_samp + floor(fTMaxS*raw.
info.
sfreq + 0.5);
574 epoch = std::make_unique<MNEEpochData>();
576 if(raw.
read_raw_segment(epoch->epoch, timesDummy, from - iFilterDelay, to + iFilterDelay, picksNew)) {
581 times.resize(1, to-from+1);
582 for (qint32 i = 0; i < times.cols(); ++i)
583 times(0, i) = ((float)(from-event_samp+i)) / raw.
info.
sfreq;
586 epoch->event = eventType;
587 epoch->tmin = fTMinS;
588 epoch->tmax = fTMaxS;
595 if (epoch->bReject) {
600 if(!lstEpochDataList.isEmpty()) {
601 if(epoch->epoch.size() == lstEpochDataList.last()->epoch.size()) {
608 qWarning(
"[MNEEpochDataList::readEpochs] Can't read the event data segments.");
612 qInfo().noquote() <<
"[MNEEpochDataList::readEpochs] Read a total of"<< lstEpochDataList.size() <<
"epochs of type" << eventType <<
"and marked"<< dropCount <<
"for rejection.";
615 QPair<float, float> baselinePair(fTBaselineFromS, fTBaselineToS);
619 if(!mapReject.isEmpty()) {
625 lstEpochDataList.first()->epoch.cols());
Single epoch (one trial slice of preprocessed sensor data) with timing and rejection metadata.
Ordered list of MNELIB::MNEEpochData objects sharing a common FIFFLIB::FiffInfo.
FIFF continuous raw recording: FiffInfo plus a directory of FIFF_DATA_BUFFER tags for random-access s...
FIFF tag-kind, block-kind and type-code numerical definitions, authoritative for FIFFLIB.
#define FIFF_FIRST_SAMPLE
Real-time FIR / IIR filtering of streaming MEG / EEG data blocks.
Core MNE data structures (source spaces, source estimates, hemispheres).
FIFF file I/O, in-memory data structures and high-level readers/writers.
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)
Single averaged evoked response: time axis, data, baseline, channel info and averaging metadata.
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
Ordered list of MNEEpochData objects sharing a common measurement info.
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) const
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())