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 if (!outfid) {
100 return false;
101 }
102
103 //Setup reading parameters
104 fiff_int_t from = pFiffRawData->first_samp;
105 fiff_int_t to = pFiffRawData->last_samp;
106
107 // slice input data into data junks with proper length so that the slices are always >= the filter order
108 float fFactor = 2.0f;
109 int iSize = fFactor * iOrder;
110 int residual = (to - from) % iSize;
111 while (residual < iOrder) {
112 fFactor = fFactor - 0.1f;
113 iSize = fFactor * iOrder;
114 residual = (to - from) % iSize;
115
116 if ((iSize < iOrder)) {
117 qInfo() << "[Filter::filterData] Sliced data block size is too small. Filtering whole block at once.";
118 iSize = to - from;
119 break;
120 }
121 }
122
123 float quantum_sec = iSize / pFiffRawData->info.sfreq;
124 fiff_int_t quantum = ceil(static_cast<double>(quantum_sec) * pFiffRawData->info.sfreq);
125
126 // Read, filter and write the data
127 bool first_buffer = true;
128
129 fiff_int_t first, last;
130 MatrixXd matData, matDataOverlap;
131 MatrixXd times;
132
133 for (first = from; first < to; first += quantum) {
134 last = first + quantum - 1;
135 if (last > to) {
136 last = to;
137 }
138
139 if (!pFiffRawData->read_raw_segment(matData, times, mult, first, last, sel)) {
140 qWarning("[Filter::filterData] Error during read_raw_segment\n");
141 return false;
142 }
143
144 qInfo() << "Filtering and writing block" << first << "to" << last;
145
146 if (first_buffer) {
147 if (first > 0) {
148 outfid->write_int(FIFF_FIRST_SAMPLE, &first);
149 }
150 first_buffer = false;
151 }
152
153 matData = filterDataBlock(matData,
154 vecPicks,
155 filterKernel,
156 bUseThreads);
157
158 if (first == from) {
159 outfid->write_raw_buffer(matData.block(0, iOrder / 2, matData.rows(), matData.cols() - iOrder), cals);
160 } else if (first + quantum >= to) {
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 } else {
164 matData.block(0, 0, matData.rows(), iOrder) += matDataOverlap;
165 outfid->write_raw_buffer(matData.block(0, 0, matData.rows(), matData.cols() - iOrder), cals);
166 }
167
168 matDataOverlap = matData.block(0, matData.cols() - iOrder, matData.rows(), iOrder);
169 }
170
171 outfid->finish_writing_raw();
172
173 return true;
174}
175
176//=============================================================================================================
177
178MatrixXd RTPROCESSINGLIB::filterData(const MatrixXd& matData,
179 int type,
180 double dCenterfreq,
181 double bandwidth,
182 double dTransition,
183 double dSFreq,
184 int iOrder,
185 int designMethod,
186 const RowVectorXi& vecPicks,
187 bool bUseThreads,
188 bool bKeepOverhead)
189{
190 // Check for size of data
191 if (matData.cols() < iOrder) {
192 qWarning() << QString("[Filter::filterData] Filter length/order is bigger than data length. Returning.");
193 return matData;
194 }
195
196 // Normalize cut off frequencies to nyquist
197 dCenterfreq = dCenterfreq / (dSFreq / 2.0);
198 bandwidth = bandwidth / (dSFreq / 2.0);
199 dTransition = dTransition / (dSFreq / 2.0);
200
201 // create filter
202 FilterKernel filter = FilterKernel("filter_kernel",
203 type,
204 iOrder,
205 dCenterfreq,
206 bandwidth,
207 dTransition,
208 dSFreq,
209 designMethod);
210
211 return filterData(matData,
212 filter,
213 vecPicks,
214 bUseThreads,
215 bKeepOverhead);
216}
217
218//=============================================================================================================
219
220MatrixXd RTPROCESSINGLIB::filterData(const MatrixXd& matData,
221 const FilterKernel& filterKernel,
222 const RowVectorXi& vecPicks,
223 bool bUseThreads,
224 bool bKeepOverhead)
225{
226 int iOrder = filterKernel.getFilterOrder();
227
228 // Check for size of data
229 if (matData.cols() < iOrder) {
230 qWarning() << "[Filter::filterData] Filter length/order is bigger than data length. Returning.";
231 return matData;
232 }
233
234 // Create output matrix with size of input matrix
235 MatrixXd matDataOut(matData.rows(), matData.cols() + iOrder);
236 matDataOut.setZero();
237 MatrixXd sliceFiltered;
238
239 // slice input data into data junks with proper length so that the slices are always >= the filter order
240 float fFactor = 2.0f;
241 int iSize = fFactor * iOrder;
242 int residual = matData.cols() % iSize;
243 while (residual < iOrder) {
244 fFactor = fFactor - 0.1f;
245 iSize = fFactor * iOrder;
246 residual = matData.cols() % iSize;
247
248 if (iSize < iOrder) {
249 iSize = matData.cols();
250 break;
251 }
252 }
253
254 if (matData.cols() > iSize) {
255 int from = 0;
256 int numSlices = ceil(float(matData.cols()) / float(iSize)); //calculate number of data slices
257
258 for (int i = 0; i < numSlices; i++) {
259 if (i == numSlices - 1) {
260 //catch the last one that might be shorter than the other blocks
261 iSize = matData.cols() - (iSize * (numSlices - 1));
262 }
263
264 // Filter the data block. This will return data with a fitler delay of iOrder/2 in front and back
265 sliceFiltered = filterDataBlock(matData.block(0, from, matData.rows(), iSize),
266 vecPicks,
267 filterKernel,
268 bUseThreads);
269
270 // Perform overlap add
271 if (i == 0) {
272 matDataOut.block(0, 0, matData.rows(), sliceFiltered.cols()) += sliceFiltered;
273 } else {
274 matDataOut.block(0, from, matData.rows(), sliceFiltered.cols()) += sliceFiltered;
275 }
276
277 from += iSize;
278 }
279 } else {
280 matDataOut = filterDataBlock(matData,
281 vecPicks,
282 filterKernel,
283 bUseThreads);
284 }
285
286 if (bKeepOverhead) {
287 return matDataOut;
288 } else {
289 return matDataOut.block(0, iOrder / 2, matDataOut.rows(), matData.cols());
290 }
291}
292
293//=============================================================================================================
294
295MatrixXd RTPROCESSINGLIB::filterDataBlock(const MatrixXd& matData,
296 const RowVectorXi& vecPicks,
297 const FilterKernel& filterKernel,
298 bool bUseThreads)
299{
300 int iOrder = filterKernel.getFilterOrder();
301
302 // Check for size of data
303 if (matData.cols() < iOrder) {
304 qWarning() << QString("[Filter::filterDataBlock] Filter length/order is bigger than data length. Returning.");
305 return matData;
306 }
307
308 // Setup filters to the correct length, so we do not have to do this everytime we call the FFT filter function
309 FilterKernel filterKernelSetup = filterKernel;
310 filterKernelSetup.prepareFilter(matData.cols());
311
312 // Do the concurrent filtering
313 RowVectorXi vecPicksNew = vecPicks;
314 if (vecPicksNew.cols() == 0) {
315 vecPicksNew = RowVectorXi::LinSpaced(matData.rows(), 0, matData.rows() - 1);
316 }
317
318 // Generate QList structure which can be handled by the QConcurrent framework
319 QList<FilterObject> timeData;
320
321 // Only select channels specified in vecPicksNew
322 FilterObject data;
323 for (qint32 i = 0; i < vecPicksNew.cols(); ++i) {
324 data.filterKernel = filterKernelSetup;
325 data.iRow = vecPicksNew[i];
326 data.vecData = matData.row(vecPicksNew[i]);
327 timeData.append(data);
328 }
329
330 // Copy in data from last data block. This is necessary in order to also delay channels which are not filtered
331 MatrixXd matDataOut(matData.rows(), matData.cols() + iOrder);
332 matDataOut.setZero();
333 matDataOut.block(0, iOrder / 2, matData.rows(), matData.cols()) = matData;
334
335 if (bUseThreads) {
336 QFuture<void> future = QtConcurrent::map(timeData,
338 future.waitForFinished();
339 } else {
340 for (int i = 0; i < timeData.size(); ++i) {
341 filterChannel(timeData[i]);
342 }
343 }
344
345 // Do the overlap add method and store in matDataOut
346 RowVectorXd tempData;
347
348 for (int r = 0; r < timeData.size(); r++) {
349 // Write the newly calculated filtered data to the filter data matrix. This data has a delay of iOrder/2 in front and back
350 matDataOut.row(timeData.at(r).iRow) = timeData.at(r).vecData;
351 }
352
353 return matDataOut;
354}
355
356//=============================================================================================================
357
359{
360 //channelDataTime.vecData = channelDataTime.first.at(i).applyConvFilter(channelDataTime.vecData, true);
361 channelDataTime.filterKernel.applyFftFilter(channelDataTime.vecData, true); //FFT Convolution for rt is not suitable. FFT make the signal filtering non causal.
362}
363
364//=============================================================================================================
365// DEFINE MEMBER METHODS
366//=============================================================================================================
367
368MatrixXd FilterOverlapAdd::calculate(const MatrixXd& matData,
369 int type,
370 double dCenterfreq,
371 double bandwidth,
372 double dTransition,
373 double dSFreq,
374 int iOrder,
375 int designMethod,
376 const RowVectorXi& vecPicks,
377 bool bFilterEnd,
378 bool bUseThreads,
379 bool bKeepOverhead)
380{
381 // Check for size of data
382 if (matData.cols() < iOrder) {
383 qWarning() << QString("[Filter::filterData] Filter length/order is bigger than data length. Returning.");
384 return matData;
385 }
386
387 // Normalize cut off frequencies to nyquist
388 dCenterfreq = dCenterfreq / (dSFreq / 2.0);
389 bandwidth = bandwidth / (dSFreq / 2.0);
390 dTransition = dTransition / (dSFreq / 2.0);
391
392 // create filter
393 FilterKernel filter = FilterKernel("filter_kernel",
394 type,
395 iOrder,
396 dCenterfreq,
397 bandwidth,
398 dTransition,
399 dSFreq,
400 designMethod);
401
402 return calculate(matData,
403 filter,
404 vecPicks,
405 bFilterEnd,
406 bUseThreads,
407 bKeepOverhead);
408}
409
410//=============================================================================================================
411
412MatrixXd FilterOverlapAdd::calculate(const MatrixXd& matData,
413 const FilterKernel& filterKernel,
414 const RowVectorXi& vecPicks,
415 bool bFilterEnd,
416 bool bUseThreads,
417 bool bKeepOverhead)
418{
419 int iOrder = filterKernel.getFilterOrder();
420
421 // Check for size of data
422 if (matData.cols() < iOrder) {
423 qWarning() << "[Filter::filterData] Filter length/order is bigger than data length. Returning.";
424 return matData;
425 }
426
427 // Init overlaps from last block
428 if (m_matOverlapBack.cols() != iOrder || m_matOverlapBack.rows() < matData.rows()) {
429 m_matOverlapBack.resize(matData.rows(), iOrder);
430 m_matOverlapBack.setZero();
431 }
432
433 if (m_matOverlapFront.cols() != iOrder || m_matOverlapFront.rows() < matData.rows()) {
434 m_matOverlapFront.resize(matData.rows(), iOrder);
435 m_matOverlapFront.setZero();
436 }
437
438 // Create output matrix with size of input matrix
439 MatrixXd matDataOut(matData.rows(), matData.cols() + iOrder);
440 matDataOut.setZero();
441 MatrixXd sliceFiltered;
442
443 // slice input data into data junks with proper length so that the slices are always >= the filter order
444 float fFactor = 2.0f;
445 int iSize = fFactor * iOrder;
446 int residual = matData.cols() % iSize;
447 while (residual < iOrder) {
448 fFactor = fFactor - 0.1f;
449 iSize = fFactor * iOrder;
450 residual = matData.cols() % iSize;
451
452 if (iSize < iOrder) {
453 iSize = matData.cols();
454 break;
455 }
456 }
457
458 if (matData.cols() > iSize) {
459 int from = 0;
460 int numSlices = ceil(float(matData.cols()) / float(iSize)); //calculate number of data slices
461
462 for (int i = 0; i < numSlices; i++) {
463 if (i == numSlices - 1) {
464 //catch the last one that might be shorter than the other blocks
465 iSize = matData.cols() - (iSize * (numSlices - 1));
466 }
467
468 // Filter the data block. This will return data with a fitler delay of iOrder/2 in front and back
469 sliceFiltered = filterDataBlock(matData.block(0, from, matData.rows(), iSize),
470 vecPicks,
471 filterKernel,
472 bUseThreads);
473
474 if (i == 0) {
475 matDataOut.block(0, 0, matData.rows(), sliceFiltered.cols()) += sliceFiltered;
476 } else {
477 matDataOut.block(0, from, matData.rows(), sliceFiltered.cols()) += sliceFiltered;
478 }
479
480 if (bFilterEnd && (i == 0)) {
481 matDataOut.block(0, 0, matDataOut.rows(), iOrder) += m_matOverlapBack;
482 } else if (!bFilterEnd && (i == numSlices - 1)) {
483 matDataOut.block(0, matDataOut.cols() - iOrder, matDataOut.rows(), iOrder) += m_matOverlapFront;
484 }
485
486 from += iSize;
487 }
488 } else {
489 matDataOut = filterDataBlock(matData,
490 vecPicks,
491 filterKernel,
492 bUseThreads);
493
494 if (bFilterEnd) {
495 matDataOut.block(0, 0, matDataOut.rows(), iOrder) += m_matOverlapBack;
496 } else {
497 matDataOut.block(0, matDataOut.cols() - iOrder, matDataOut.rows(), iOrder) += m_matOverlapFront;
498 }
499 }
500
501 // Refresh the overlap matrix with the new calculated filtered data
502 m_matOverlapBack = matDataOut.block(0, matDataOut.cols() - iOrder, matDataOut.rows(), iOrder);
503 m_matOverlapFront = matDataOut.block(0, 0, matDataOut.rows(), iOrder);
504
505 if (bKeepOverhead) {
506 return matDataOut;
507 } else {
508 return matDataOut.block(0, 0, matDataOut.rows(), matData.cols());
509 }
510}
511
512//=============================================================================================================
513
515{
516 m_matOverlapBack.resize(0, 0);
517 m_matOverlapFront.resize(0, 0);
518}
519
520//=============================================================================================================
521
523 const MatrixXi& matEvents,
524 float fTMinS,
525 float fTMaxS,
526 qint32 eventType,
527 bool bApplyBaseline,
528 float fTBaselineFromS,
529 float fTBaselineToS,
530 const QMap<QString, double>& mapReject,
531 const FilterKernel& filterKernel,
532 const QStringList& lExcludeChs,
533 const RowVectorXi& picks)
534{
535 MNEEpochDataList lstEpochDataList;
536
537 // Select the desired events
538 qint32 count = 0;
539 qint32 p;
540 MatrixXi selected = MatrixXi::Zero(1, matEvents.rows());
541 for (p = 0; p < matEvents.rows(); ++p) {
542 if (matEvents(p, 1) == 0 && matEvents(p, 2) == eventType) {
543 selected(0, count) = p;
544 ++count;
545 }
546 }
547 selected.conservativeResize(1, count);
548 if (count > 0) {
549 qInfo("[RTPROCESSINGLIB::computeFilteredAverage] %d matching events found", count);
550 }
551
552 // If picks are empty, pick all
553 RowVectorXi picksNew = picks;
554 if (picks.cols() <= 0) {
555 picksNew.resize(raw.info.chs.size());
556 for (int i = 0; i < raw.info.chs.size(); ++i) {
557 picksNew(i) = i;
558 }
559 }
560
561 fiff_int_t event_samp, from, to;
562 fiff_int_t dropCount = 0;
563 MatrixXd timesDummy;
564 MatrixXd times;
565
566 std::unique_ptr<MNEEpochData> epoch;
567 int iFilterDelay = filterKernel.getFilterOrder() / 2;
568
569 for (p = 0; p < count; ++p) {
570 // Read a data segment
571 event_samp = matEvents(selected(p), 0);
572 from = event_samp + fTMinS * raw.info.sfreq;
573 to = event_samp + floor(fTMaxS * raw.info.sfreq + 0.5);
574
575 epoch = std::make_unique<MNEEpochData>();
576
577 if (raw.read_raw_segment(epoch->epoch, timesDummy, from - iFilterDelay, to + iFilterDelay, picksNew)) {
578 // Filter the data
579 epoch->epoch = RTPROCESSINGLIB::filterData(epoch->epoch, filterKernel).block(0, iFilterDelay, epoch->epoch.rows(), to - from);
580
581 if (p == 0) {
582 times.resize(1, to - from + 1);
583 for (qint32 i = 0; i < times.cols(); ++i)
584 times(0, i) = ((float)(from - event_samp + i)) / raw.info.sfreq;
585 }
586
587 epoch->event = eventType;
588 epoch->tmin = fTMinS;
589 epoch->tmax = fTMaxS;
590
591 epoch->bReject = MNEEpochDataList::checkForArtifact(epoch->epoch,
592 raw.info,
593 mapReject,
594 lExcludeChs);
595
596 if (epoch->bReject) {
597 dropCount++;
598 }
599
600 //Check if data block has the same size as the previous one
601 if (!lstEpochDataList.isEmpty()) {
602 if (epoch->epoch.size() == lstEpochDataList.last()->epoch.size()) {
603 lstEpochDataList.append(MNEEpochData::SPtr(epoch.release()));
604 }
605 } else {
606 lstEpochDataList.append(MNEEpochData::SPtr(epoch.release()));
607 }
608 } else {
609 qWarning("[MNEEpochDataList::readEpochs] Can't read the event data segments.");
610 }
611 }
612
613 qInfo().noquote() << "[MNEEpochDataList::readEpochs] Read a total of" << lstEpochDataList.size() << "epochs of type" << eventType << "and marked" << dropCount << "for rejection.";
614
615 if (bApplyBaseline) {
616 QPair<float, float> baselinePair(fTBaselineFromS, fTBaselineToS);
617 lstEpochDataList.applyBaselineCorrection(baselinePair);
618 }
619
620 if (!mapReject.isEmpty()) {
621 lstEpochDataList.dropRejected();
622 }
623
624 return lstEpochDataList.average(raw.info,
625 0,
626 lstEpochDataList.first()->epoch.cols());
627}
FIFF tag-kind, block-kind and type-code numerical definitions, authoritative for FIFFLIB.
#define FIFF_FIRST_SAMPLE
Definition fiff_file.h:454
FIFF continuous raw recording: FiffInfo plus a directory of FIFF_DATA_BUFFER tags for random-access s...
Real-time FIR / IIR filtering of streaming MEG / EEG data blocks.
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.
Core MNE data structures (source spaces, source estimates, hemispheres).
FIFF file I/O, in-memory data structures and high-level readers/writers.
qint32 fiff_int_t
Definition fiff_types.h:86
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:75
UTILSLIB::FilterKernel filterKernel
Definition rt_filter.h:76
Eigen::RowVectorXd vecData
Definition rt_filter.h:78
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:77
QList< FiffChInfo > chs
Continuous FIFF raw recording: FiffInfo plus a random-access directory of FIFF_DATA_BUFFER tags.
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())