v2.0.0
Loading...
Searching...
No Matches
rt_filter.cpp
Go to the documentation of this file.
1//=============================================================================================================
12
13//=============================================================================================================
14// INCLUDES
15//=============================================================================================================
16
17#include "rt_filter.h"
18
19#include <fiff/fiff_raw_data.h>
20#include <fiff/fiff_file.h>
21#include <mne/mne_epoch_data.h>
23
24//=============================================================================================================
25// QT INCLUDES
26//=============================================================================================================
27
28#include <QDebug>
29
30//=============================================================================================================
31// EIGEN INCLUDES
32//=============================================================================================================
33
34#include <Eigen/Dense>
35#include <Eigen/Core>
36
37//=============================================================================================================
38// USED NAMESPACES
39//=============================================================================================================
40
41using namespace RTPROCESSINGLIB;
42using namespace Eigen;
43using namespace FIFFLIB;
44using namespace UTILSLIB;
45using namespace MNELIB;
46
47//=============================================================================================================
48// DEFINE GLOBAL RTPROCESSINGLIB METHODS
49//=============================================================================================================
50
51bool RTPROCESSINGLIB::filterFile(QIODevice &pIODevice,
52 QSharedPointer<FiffRawData> pFiffRawData,
53 int type,
54 double dCenterfreq,
55 double bandwidth,
56 double dTransition,
57 double dSFreq,
58 int iOrder,
59 int designMethod,
60 const RowVectorXi& vecPicks,
61 bool bUseThreads)
62{
63 // Normalize cut off frequencies to nyquist
64 dCenterfreq = dCenterfreq/(dSFreq/2.0);
65 bandwidth = bandwidth/(dSFreq/2.0);
66 dTransition = dTransition/(dSFreq/2.0);
67
68 // create filter
69 FilterKernel filter = FilterKernel("filter_kernel",
70 type,
71 iOrder,
72 dCenterfreq,
73 bandwidth,
74 dTransition,
75 dSFreq,
76 designMethod);
77
78 return filterFile(pIODevice,
79 pFiffRawData,
80 filter,
81 vecPicks,
82 bUseThreads);
83}
84
85//=============================================================================================================
86
87bool RTPROCESSINGLIB::filterFile(QIODevice &pIODevice,
88 QSharedPointer<FiffRawData> pFiffRawData,
89 const FilterKernel& filterKernel,
90 const RowVectorXi& vecPicks,
91 bool bUseThreads)
92{
93 int iOrder = filterKernel.getFilterOrder();
94
95 RowVectorXd cals;
96 SparseMatrix<double> mult;
97 RowVectorXi sel;
98 FiffStream::SPtr outfid = FiffStream::start_writing_raw(pIODevice, pFiffRawData->info, cals);
99
100 //Setup reading parameters
101 fiff_int_t from = pFiffRawData->first_samp;
102 fiff_int_t to = pFiffRawData->last_samp;
103
104 // slice input data into data junks with proper length so that the slices are always >= the filter order
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;
112
113 if((iSize < iOrder)) {
114 qInfo() << "[Filter::filterData] Sliced data block size is too small. Filtering whole block at once.";
115 iSize = to - from;
116 break;
117 }
118 }
119
120 float quantum_sec = iSize/pFiffRawData->info.sfreq;
121 fiff_int_t quantum = ceil(static_cast<double>(quantum_sec)*pFiffRawData->info.sfreq);
122
123 // Read, filter and write the data
124 bool first_buffer = true;
125
126 fiff_int_t first, last;
127 MatrixXd matData, matDataOverlap;
128 MatrixXd times;
129
130 for(first = from; first < to; first+=quantum) {
131 last = first+quantum-1;
132 if (last > to) {
133 last = to;
134 }
135
136 if (!pFiffRawData->read_raw_segment(matData, times, mult, first, last, sel)) {
137 qWarning("[Filter::filterData] Error during read_raw_segment\n");
138 return false;
139 }
140
141 qInfo() << "Filtering and writing block" << first << "to" << last;
142
143 if (first_buffer) {
144 if (first > 0) {
145 outfid->write_int(FIFF_FIRST_SAMPLE,&first);
146 }
147 first_buffer = false;
148 }
149
150 matData = filterDataBlock(matData,
151 vecPicks,
152 filterKernel,
153 bUseThreads);
154
155 if(first == from) {
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);
160 } else {
161 matData.block(0,0,matData.rows(),iOrder) += matDataOverlap;
162 outfid->write_raw_buffer(matData.block(0,0,matData.rows(),matData.cols()-iOrder), cals);
163 }
164
165 matDataOverlap = matData.block(0,matData.cols()-iOrder,matData.rows(),iOrder);
166 }
167
168 outfid->finish_writing_raw();
169
170 return true;
171}
172
173//=============================================================================================================
174
175MatrixXd RTPROCESSINGLIB::filterData(const MatrixXd& matData,
176 int type,
177 double dCenterfreq,
178 double bandwidth,
179 double dTransition,
180 double dSFreq,
181 int iOrder,
182 int designMethod,
183 const RowVectorXi& vecPicks,
184 bool bUseThreads,
185 bool bKeepOverhead)
186{
187 // Check for size of data
188 if(matData.cols() < iOrder){
189 qWarning() << QString("[Filter::filterData] Filter length/order is bigger than data length. Returning.");
190 return matData;
191 }
192
193 // Normalize cut off frequencies to nyquist
194 dCenterfreq = dCenterfreq/(dSFreq/2.0);
195 bandwidth = bandwidth/(dSFreq/2.0);
196 dTransition = dTransition/(dSFreq/2.0);
197
198 // create filter
199 FilterKernel filter = FilterKernel("filter_kernel",
200 type,
201 iOrder,
202 dCenterfreq,
203 bandwidth,
204 dTransition,
205 dSFreq,
206 designMethod);
207
208 return filterData(matData,
209 filter,
210 vecPicks,
211 bUseThreads,
212 bKeepOverhead);
213}
214
215//=============================================================================================================
216
217MatrixXd RTPROCESSINGLIB::filterData(const MatrixXd& matData,
218 const FilterKernel& filterKernel,
219 const RowVectorXi& vecPicks,
220 bool bUseThreads,
221 bool bKeepOverhead)
222{
223 int iOrder = filterKernel.getFilterOrder();
224
225 // Check for size of data
226 if(matData.cols() < iOrder){
227 qWarning() << "[Filter::filterData] Filter length/order is bigger than data length. Returning.";
228 return matData;
229 }
230
231 // Create output matrix with size of input matrix
232 MatrixXd matDataOut(matData.rows(), matData.cols()+iOrder);
233 matDataOut.setZero();
234 MatrixXd sliceFiltered;
235
236 // slice input data into data junks with proper length so that the slices are always >= the filter order
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;
244
245 if(iSize < iOrder) {
246 iSize = matData.cols();
247 break;
248 }
249 }
250
251 if(matData.cols() > iSize) {
252 int from = 0;
253 int numSlices = ceil(float(matData.cols())/float(iSize)); //calculate number of data slices
254
255 for (int i = 0; i < numSlices; i++) {
256 if(i == numSlices-1) {
257 //catch the last one that might be shorter than the other blocks
258 iSize = matData.cols() - (iSize * (numSlices -1));
259 }
260
261 // Filter the data block. This will return data with a fitler delay of iOrder/2 in front and back
262 sliceFiltered = filterDataBlock(matData.block(0,from,matData.rows(),iSize),
263 vecPicks,
264 filterKernel,
265 bUseThreads);
266
267 // Perform overlap add
268 if(i == 0) {
269 matDataOut.block(0,0,matData.rows(),sliceFiltered.cols()) += sliceFiltered;
270 } else {
271 matDataOut.block(0,from,matData.rows(),sliceFiltered.cols()) += sliceFiltered;
272 }
273
274 from += iSize;
275 }
276 } else {
277 matDataOut = filterDataBlock(matData,
278 vecPicks,
279 filterKernel,
280 bUseThreads);
281 }
282
283 if(bKeepOverhead) {
284 return matDataOut;
285 } else {
286 return matDataOut.block(0,iOrder/2,matDataOut.rows(),matData.cols());
287 }
288}
289
290//=============================================================================================================
291
292MatrixXd RTPROCESSINGLIB::filterDataBlock(const MatrixXd& matData,
293 const RowVectorXi& vecPicks,
294 const FilterKernel& filterKernel,
295 bool bUseThreads)
296{
297 int iOrder = filterKernel.getFilterOrder();
298
299 // Check for size of data
300 if(matData.cols() < iOrder){
301 qWarning() << QString("[Filter::filterDataBlock] Filter length/order is bigger than data length. Returning.");
302 return matData;
303 }
304
305 // Setup filters to the correct length, so we do not have to do this everytime we call the FFT filter function
306 FilterKernel filterKernelSetup = filterKernel;
307 filterKernelSetup.prepareFilter(matData.cols());
308
309 // Do the concurrent filtering
310 RowVectorXi vecPicksNew = vecPicks;
311 if(vecPicksNew.cols() == 0) {
312 vecPicksNew = RowVectorXi::LinSpaced(matData.rows(), 0, matData.rows());
313 }
314
315 // Generate QList structure which can be handled by the QConcurrent framework
316 QList<FilterObject> timeData;
317
318 // Only select channels specified in vecPicksNew
319 FilterObject data;
320 for(qint32 i = 0; i < vecPicksNew.cols(); ++i) {
321 data.filterKernel = filterKernelSetup;
322 data.iRow = vecPicksNew[i];
323 data.vecData = matData.row(vecPicksNew[i]);
324 timeData.append(data);
325 }
326
327 // Copy in data from last data block. This is necessary in order to also delay channels which are not filtered
328 MatrixXd matDataOut(matData.rows(), matData.cols()+iOrder);
329 matDataOut.setZero();
330 matDataOut.block(0, iOrder/2, matData.rows(), matData.cols()) = matData;
331
332 if(bUseThreads) {
333 QFuture<void> future = QtConcurrent::map(timeData,
335 future.waitForFinished();
336 } else {
337 for(int i = 0; i < timeData.size(); ++i) {
338 filterChannel(timeData[i]);
339 }
340 }
341
342 // Do the overlap add method and store in matDataOut
343 RowVectorXd tempData;
344
345 for(int r = 0; r < timeData.size(); r++) {
346 // Write the newly calculated filtered data to the filter data matrix. This data has a delay of iOrder/2 in front and back
347 matDataOut.row(timeData.at(r).iRow) = timeData.at(r).vecData;
348 }
349
350 return matDataOut;
351}
352
353//=============================================================================================================
354
356{
357 //channelDataTime.vecData = channelDataTime.first.at(i).applyConvFilter(channelDataTime.vecData, true);
358 channelDataTime.filterKernel.applyFftFilter(channelDataTime.vecData, true); //FFT Convolution for rt is not suitable. FFT make the signal filtering non causal.
359}
360
361//=============================================================================================================
362// DEFINE MEMBER METHODS
363//=============================================================================================================
364
365MatrixXd FilterOverlapAdd::calculate(const MatrixXd& matData,
366 int type,
367 double dCenterfreq,
368 double bandwidth,
369 double dTransition,
370 double dSFreq,
371 int iOrder,
372 int designMethod,
373 const RowVectorXi& vecPicks,
374 bool bFilterEnd,
375 bool bUseThreads,
376 bool bKeepOverhead)
377{
378 // Check for size of data
379 if(matData.cols() < iOrder){
380 qWarning() << QString("[Filter::filterData] Filter length/order is bigger than data length. Returning.");
381 return matData;
382 }
383
384 // Normalize cut off frequencies to nyquist
385 dCenterfreq = dCenterfreq/(dSFreq/2.0);
386 bandwidth = bandwidth/(dSFreq/2.0);
387 dTransition = dTransition/(dSFreq/2.0);
388
389 // create filter
390 FilterKernel filter = FilterKernel("filter_kernel",
391 type,
392 iOrder,
393 dCenterfreq,
394 bandwidth,
395 dTransition,
396 dSFreq,
397 designMethod);
398
399 return calculate(matData,
400 filter,
401 vecPicks,
402 bFilterEnd,
403 bUseThreads,
404 bKeepOverhead);
405}
406
407//=============================================================================================================
408
409MatrixXd FilterOverlapAdd::calculate(const MatrixXd& matData,
410 const FilterKernel& filterKernel,
411 const RowVectorXi& vecPicks,
412 bool bFilterEnd,
413 bool bUseThreads,
414 bool bKeepOverhead)
415{
416 int iOrder = filterKernel.getFilterOrder();
417
418 // Check for size of data
419 if(matData.cols() < iOrder){
420 qWarning() << "[Filter::filterData] Filter length/order is bigger than data length. Returning.";
421 return matData;
422 }
423
424 // Init overlaps from last block
425 if(m_matOverlapBack.cols() != iOrder || m_matOverlapBack.rows() < matData.rows()) {
426 m_matOverlapBack.resize(matData.rows(), iOrder);
427 m_matOverlapBack.setZero();
428 }
429
430 if(m_matOverlapFront.cols() != iOrder || m_matOverlapFront.rows() < matData.rows()) {
431 m_matOverlapFront.resize(matData.rows(), iOrder);
432 m_matOverlapFront.setZero();
433 }
434
435 // Create output matrix with size of input matrix
436 MatrixXd matDataOut(matData.rows(), matData.cols()+iOrder);
437 matDataOut.setZero();
438 MatrixXd sliceFiltered;
439
440 // slice input data into data junks with proper length so that the slices are always >= the filter order
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;
448
449 if(iSize < iOrder) {
450 iSize = matData.cols();
451 break;
452 }
453 }
454
455 if(matData.cols() > iSize) {
456 int from = 0;
457 int numSlices = ceil(float(matData.cols())/float(iSize)); //calculate number of data slices
458
459 for (int i = 0; i < numSlices; i++) {
460 if(i == numSlices-1) {
461 //catch the last one that might be shorter than the other blocks
462 iSize = matData.cols() - (iSize * (numSlices -1));
463 }
464
465 // Filter the data block. This will return data with a fitler delay of iOrder/2 in front and back
466 sliceFiltered = filterDataBlock(matData.block(0,from,matData.rows(),iSize),
467 vecPicks,
468 filterKernel,
469 bUseThreads);
470
471 if(i == 0) {
472 matDataOut.block(0,0,matData.rows(),sliceFiltered.cols()) += sliceFiltered;
473 } else {
474 matDataOut.block(0,from,matData.rows(),sliceFiltered.cols()) += sliceFiltered;
475 }
476
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;
481 }
482
483 from += iSize;
484 }
485 } else {
486 matDataOut = filterDataBlock(matData,
487 vecPicks,
488 filterKernel,
489 bUseThreads);
490
491 if(bFilterEnd) {
492 matDataOut.block(0,0,matDataOut.rows(),iOrder) += m_matOverlapBack;
493 } else {
494 matDataOut.block(0,matDataOut.cols()-iOrder,matDataOut.rows(),iOrder) += m_matOverlapFront;
495 }
496 }
497
498 // Refresh the overlap matrix with the new calculated filtered data
499 m_matOverlapBack = matDataOut.block(0,matDataOut.cols()-iOrder,matDataOut.rows(),iOrder);
500 m_matOverlapFront = matDataOut.block(0,0,matDataOut.rows(),iOrder);
501
502 if(bKeepOverhead) {
503 return matDataOut;
504 } else {
505 return matDataOut.block(0,0,matDataOut.rows(),matData.cols());
506 }
507}
508
509//=============================================================================================================
510
512{
513 m_matOverlapBack.resize(0,0);
514 m_matOverlapFront.resize(0,0);
515}
516
517//=============================================================================================================
518
520 const MatrixXi& matEvents,
521 float fTMinS,
522 float fTMaxS,
523 qint32 eventType,
524 bool bApplyBaseline,
525 float fTBaselineFromS,
526 float fTBaselineToS,
527 const QMap<QString,double>& mapReject,
528 const FilterKernel& filterKernel,
529 const QStringList& lExcludeChs,
530 const RowVectorXi& picks)
531{
532 MNEEpochDataList lstEpochDataList;
533
534 // Select the desired events
535 qint32 count = 0;
536 qint32 p;
537 MatrixXi selected = MatrixXi::Zero(1, matEvents.rows());
538 for (p = 0; p < matEvents.rows(); ++p)
539 {
540 if (matEvents(p,1) == 0 && matEvents(p,2) == eventType)
541 {
542 selected(0,count) = p;
543 ++count;
544 }
545 }
546 selected.conservativeResize(1, count);
547 if (count > 0) {
548 qInfo("[RTPROCESSINGLIB::computeFilteredAverage] %d matching events found",count);
549 }
550
551 // If picks are empty, pick all
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) {
556 picksNew(i) = i;
557 }
558 }
559
560 fiff_int_t event_samp, from, to;
561 fiff_int_t dropCount = 0;
562 MatrixXd timesDummy;
563 MatrixXd times;
564
565 std::unique_ptr<MNEEpochData> epoch;
566 int iFilterDelay = filterKernel.getFilterOrder()/2;
567
568 for (p = 0; p < count; ++p) {
569 // Read a data segment
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);
573
574 epoch = std::make_unique<MNEEpochData>();
575
576 if(raw.read_raw_segment(epoch->epoch, timesDummy, from - iFilterDelay, to + iFilterDelay, picksNew)) {
577 // Filter the data
578 epoch->epoch = RTPROCESSINGLIB::filterData(epoch->epoch,filterKernel).block(0, iFilterDelay, epoch->epoch.rows(), to-from);
579
580 if (p == 0) {
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;
584 }
585
586 epoch->event = eventType;
587 epoch->tmin = fTMinS;
588 epoch->tmax = fTMaxS;
589
590 epoch->bReject = MNEEpochDataList::checkForArtifact(epoch->epoch,
591 raw.info,
592 mapReject,
593 lExcludeChs);
594
595 if (epoch->bReject) {
596 dropCount++;
597 }
598
599 //Check if data block has the same size as the previous one
600 if(!lstEpochDataList.isEmpty()) {
601 if(epoch->epoch.size() == lstEpochDataList.last()->epoch.size()) {
602 lstEpochDataList.append(MNEEpochData::SPtr(epoch.release()));
603 }
604 } else {
605 lstEpochDataList.append(MNEEpochData::SPtr(epoch.release()));
606 }
607 } else {
608 qWarning("[MNEEpochDataList::readEpochs] Can't read the event data segments.");
609 }
610 }
611
612 qInfo().noquote() << "[MNEEpochDataList::readEpochs] Read a total of"<< lstEpochDataList.size() <<"epochs of type" << eventType << "and marked"<< dropCount <<"for rejection.";
613
614 if(bApplyBaseline) {
615 QPair<float, float> baselinePair(fTBaselineFromS, fTBaselineToS);
616 lstEpochDataList.applyBaselineCorrection(baselinePair);
617 }
618
619 if(!mapReject.isEmpty()) {
620 lstEpochDataList.dropRejected();
621 }
622
623 return lstEpochDataList.average(raw.info,
624 0,
625 lstEpochDataList.first()->epoch.cols());
626}
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
Definition fiff_file.h:454
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)
Lightweight filter configuration holding kernel coefficients and overlap-add state for one channel.
Definition rt_filter.h:73
UTILSLIB::FilterKernel filterKernel
Definition rt_filter.h:74
Eigen::RowVectorXd vecData
Definition rt_filter.h:76
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.
Definition fiff_evoked.h:75
QList< FiffChInfo > chs
FiffInfo info
bool read_raw_segment(Eigen::MatrixXd &data, Eigen::MatrixXd &times, 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())