v2.0.0
Loading...
Searching...
No Matches
rt_averaging.cpp
Go to the documentation of this file.
1//=============================================================================================================
12
13//=============================================================================================================
14// INCLUDES
15//=============================================================================================================
16
17#include "rt_averaging.h"
18
20
21#include <utils/ioutils.h>
22#include "rt_detect_trigger.h"
23#include <math/numerics.h>
24
25//=============================================================================================================
26// QT INCLUDES
27//=============================================================================================================
28
29#include <QDebug>
30
31//=============================================================================================================
32// EIGEN INCLUDES
33//=============================================================================================================
34
35//=============================================================================================================
36// USED NAMESPACES
37//=============================================================================================================
38
39using namespace RTPROCESSINGLIB;
40using namespace FIFFLIB;
41using namespace UTILSLIB;
42using namespace Eigen;
43using namespace MNELIB;
44
45//=============================================================================================================
46// DEFINE MEMBER METHODS RtAveragingWorker
47//=============================================================================================================
48
50 quint32 iPreStimSamples,
51 quint32 iPostStimSamples,
52 quint32 iBaselineFromMSecs,
53 quint32 iBaselineToMSecs,
54 quint32 iTriggerIndex,
55 FiffInfo::SPtr pFiffInfo)
56: QObject()
57, m_iNumAverages(numAverages)
58, m_iPreStimSamples(iPreStimSamples)
59, m_iPostStimSamples(iPostStimSamples)
60, m_pFiffInfo(pFiffInfo)
63, m_iNewTriggerIndex(iTriggerIndex)
65, m_pairBaselineSec(qMakePair(float(iBaselineFromMSecs),float(iBaselineToMSecs)))
67{
68 m_mapThresholds["eog"] = 300e-6;
69
70 m_stimEvokedSet.info = *m_pFiffInfo.data();
71
74
75 if(m_iNumAverages <= 0) {
76 qDebug() << "RtAveragingWorker::RtAveragingWorker - Number of averages <= 0. Setting to 1 as default.";
78 }
79}
80
81//=============================================================================================================
82
83void RtAveragingWorker::doWork(const MatrixXd& rawSegment)
84{
85 if(this->thread()->isInterruptionRequested()) {
86 return;
87 }
88
90 reset();
91 }
92
93 doAveraging(rawSegment);
94}
95
96//=============================================================================================================
97
99{
100 if(numAve <= 0) {
101 qDebug() << "[RtAveragingWorker::setAverageNumber] Number of averages <= 0 are not allowed. Returning.";
102 return;
103 }
104
105 if(numAve < m_iNumAverages) {
106 int iDiff = m_iNumAverages - numAve;
107
108 //Do averaging for each trigger type
109 QMutableMapIterator<double,QList<Eigen::MatrixXd> > idx(m_mapStimAve);
110
111 while(idx.hasNext()) {
112 idx.next();
113
114 if(idx.value().size() > iDiff) {
115 //Pop data from buffer
116 for(int i = 0; i < iDiff; ++i) {
117 idx.value().pop_front();
118 }
119 }
120 }
121 }
122
123 m_iNumAverages = numAve;
124}
125
126//=============================================================================================================
127
128void RtAveragingWorker::setPreStim(qint32 samples, qint32 secs)
129{
130 Q_UNUSED(secs);
131
132 m_iNewPreStimSamples = samples;
133}
134
135//=============================================================================================================
136
137void RtAveragingWorker::setPostStim(qint32 samples, qint32 secs)
138{
139 Q_UNUSED(secs);
140
141 m_iNewPostStimSamples = samples;
142}
143
144//=============================================================================================================
145
147{
148 m_iNewTriggerIndex = idx;
149}
150
151//=============================================================================================================
152
153void RtAveragingWorker::setArtifactReduction(const QMap<QString, double> &mapThresholds)
154{
155 if(mapThresholds["Active"] == 0.0) {
156 m_bActivateThreshold = false;
157 } else {
159 }
160
161 m_mapThresholds = mapThresholds;
162}
163
164//=============================================================================================================
165
167{
168 m_bDoBaselineCorrection = activate;
169
171 for(int i = 0; i < m_stimEvokedSet.evoked.size(); ++i) {
172 m_stimEvokedSet.evoked[i].baseline = qMakePair(-1.0f, -1.0f);
173 }
174 } else {
175 for(int i = 0; i < m_stimEvokedSet.evoked.size(); ++i) {
176 m_stimEvokedSet.evoked[i].baseline = m_pairBaselineSec;
177 }
178 }
179}
180
181//=============================================================================================================
182
184 int fromMSec)
185{
186 m_pairBaselineSec.first = float(fromMSec)/1000.0f;
187 m_pairBaselineSamp.first = float(fromSamp);
188
189 for(int i = 0; i < m_stimEvokedSet.evoked.size(); ++i) {
190 m_stimEvokedSet.evoked[i].baseline.first = float(fromMSec)/1000.0f;
191 }
192}
193
194//=============================================================================================================
195
197 int toMSec)
198{
199 m_pairBaselineSec.second = float(toMSec)/1000.0f;
200 m_pairBaselineSamp.second = float(toSamp);
201
202 for(int i = 0; i < m_stimEvokedSet.evoked.size(); ++i) {
203 m_stimEvokedSet.evoked[i].baseline.second = float(toMSec)/1000.0f;
204 }
205}
206
207//=============================================================================================================
208
209void RtAveragingWorker::doAveraging(const MatrixXd& rawSegment)
210{
211 //Detect trigger
212 QList<QPair<int,double> > lDetectedTriggers = RTPROCESSINGLIB::detectTriggerFlanksMax(rawSegment, m_iTriggerChIndex, 0, m_fTriggerThreshold, true);
213
214 //TODO: This does not permit the same trigger type twice in one data block
215 for(int i = 0; i < lDetectedTriggers.size(); ++i) {
216 if(!m_mapFillingBackBuffer.contains(lDetectedTriggers.at(i).second)) {
217 double dTriggerType = lDetectedTriggers.at(i).second;
218
219 //qDebug()<<"Adding dTriggerType"<<dTriggerType;
220
221 m_mapFillingBackBuffer[dTriggerType] = false;
222 m_mapMatDataPostIdx[dTriggerType] = 0;
223 m_mapDataPost[dTriggerType].resize(m_pFiffInfo->chs.size(), m_iPostStimSamples);
224 m_mapDataPost[dTriggerType].setZero();
225 }
226 }
227
228 //Fill front / pre stim buffer even if no triggers have been located at all yet
229 if(m_mapFillingBackBuffer.isEmpty()) {
230 fillFrontBuffer(rawSegment, -1.0);
231 }
232
233 //Do averaging for each trigger type
234 QMutableMapIterator<double,bool> idx(m_mapFillingBackBuffer);
235 QStringList lResponsibleTriggerTypes;
236
237 while(idx.hasNext()) {
238 idx.next();
239
240 double dTriggerType = idx.key();
241
242 //Fill front / pre stim buffer
243 if(lDetectedTriggers.isEmpty()) {
244 fillFrontBuffer(rawSegment, -1.0);
245 }
246
247 //Fill back buffer and decide when to do the data packing of the different buffers
248 if(m_mapFillingBackBuffer[dTriggerType]) {
249 if(m_mapMatDataPostIdx[dTriggerType] != m_iPostStimSamples) {
250 fillBackBuffer(rawSegment, dTriggerType);
251 }
252
253 if(m_mapMatDataPostIdx[dTriggerType] == m_iPostStimSamples) {
254 m_mapMatDataPostIdx[dTriggerType] = 0;
255 m_mapFillingBackBuffer[dTriggerType] = false;
256 emitEvoked(dTriggerType, lResponsibleTriggerTypes);
257 }
258 } else {
259 if(lDetectedTriggers.isEmpty()) {
260 //Fill front / pre stim buffer
261 fillFrontBuffer(rawSegment, dTriggerType);
262 } else {
263 for(int i = 0; i < lDetectedTriggers.size(); ++i) {
264 if(dTriggerType == lDetectedTriggers.at(i).second) {
265 int iTriggerPos = lDetectedTriggers.at(i).first;
266
267 //Do front buffer stuff
268 MatrixXd tempMat;
269
270 if(iTriggerPos >= m_iPreStimSamples) {
271 tempMat = rawSegment.block(0,
272 iTriggerPos - m_iPreStimSamples,
273 rawSegment.rows(),
275 } else {
276 tempMat = rawSegment.block(0,
277 0,
278 rawSegment.rows(),
279 iTriggerPos);
280 }
281
282 fillFrontBuffer(tempMat, dTriggerType);
283
284 //Do back buffer stuff
285 if(rawSegment.cols() - iTriggerPos >= m_mapDataPost[dTriggerType].cols()) {
286 m_mapDataPost[dTriggerType] = rawSegment.block(0,
287 iTriggerPos,
288 m_mapDataPost[dTriggerType].rows(),
289 m_mapDataPost[dTriggerType].cols());
290 emitEvoked(dTriggerType, lResponsibleTriggerTypes);
291 m_mapMatDataPostIdx[dTriggerType] = 0;
292 m_mapFillingBackBuffer[dTriggerType] = false;
293 } else {
294 m_mapDataPost[dTriggerType].block(0,
295 0,
296 m_mapDataPost[dTriggerType].rows(),
297 rawSegment.cols() - iTriggerPos) = rawSegment.block(0,
298 iTriggerPos,
299 rawSegment.rows(),
300 rawSegment.cols() - iTriggerPos);
301 m_mapMatDataPostIdx[dTriggerType] = rawSegment.cols() - iTriggerPos;
302 m_mapFillingBackBuffer[dTriggerType] = true;
303 }
304
305 //qDebug()<<"Trigger type "<<dTriggerType<<" found at "<<iTriggerPos;
306 }
307 }
308 }
309 }
310 }
311
312 //qDebug()<<"RtAveragingWorker::doAveraging() - time for procesing"<<time.elapsed();
313}
314
315//=============================================================================================================
316
317void RtAveragingWorker::emitEvoked(double dTriggerType, QStringList& lResponsibleTriggerTypes)
318{
319 //Merge the different buffers
320 mergeData(dTriggerType);
321
322 //Calculate the final average/evoked data
323 generateEvoked(dTriggerType);
324
325 //List of all trigger types which lead to the recent emit of a new evoked set. */
326 if(!lResponsibleTriggerTypes.contains(QString::number(dTriggerType))) {
327 lResponsibleTriggerTypes << QString::number(dTriggerType);
328 }
329
330 if(m_stimEvokedSet.evoked.size() > 0) {
331 emit resultReady(m_stimEvokedSet, lResponsibleTriggerTypes);
332 }
333
334// qDebug()<<"RtAveragingWorker::emitEvoked() - dTriggerType:" << dTriggerType;
335// qDebug()<<"RtAveragingWorker::emitEvoked() - m_mapStimAve[dTriggerType].size():" << m_mapStimAve[dTriggerType].size();
336}
337
338//=============================================================================================================
339
340void RtAveragingWorker::fillBackBuffer(const MatrixXd &data, double dTriggerType)
341{
342 int iResidualCols = data.cols();
343 if(m_mapMatDataPostIdx[dTriggerType] + data.cols() > m_iPostStimSamples) {
344 iResidualCols = m_iPostStimSamples - m_mapMatDataPostIdx[dTriggerType];
345 m_mapDataPost[dTriggerType].block(0,m_mapMatDataPostIdx[dTriggerType],m_mapDataPost[dTriggerType].rows(),iResidualCols) = data.block(0,0,data.rows(),iResidualCols);
346 } else {
347 m_mapDataPost[dTriggerType].block(0,m_mapMatDataPostIdx[dTriggerType],m_mapDataPost[dTriggerType].rows(),iResidualCols) = data;
348 }
349
350 m_mapMatDataPostIdx[dTriggerType] += iResidualCols;
351}
352
353//=============================================================================================================
354
355void RtAveragingWorker::fillFrontBuffer(const MatrixXd &data, double dTriggerType)
356{
357 //Init m_mapDataPre
358 if(!m_mapDataPre.contains(dTriggerType)) {
359 if(dTriggerType != -1.0) {
360 m_mapDataPre[dTriggerType] = m_mapDataPre[-1.0];
361 } else {
362 m_mapDataPre[-1.0].resize(m_pFiffInfo->chs.size(), m_iPreStimSamples);
363 m_mapDataPre[-1.0].setZero();
364 }
365 }
366
367 if(m_mapDataPre[dTriggerType].cols() <= data.cols()) {
368 if(m_iPreStimSamples > 0 && data.cols() >= m_iPreStimSamples) {
369 m_mapDataPre[dTriggerType] = data.block(0,
370 data.cols() - m_iPreStimSamples,
371 data.rows(),
373 }
374 } else {
375 int residual = m_mapDataPre[dTriggerType].cols() - data.cols();
376
377 //Copy shift data
378 m_mapDataPre[dTriggerType].block(0,
379 0,
380 m_mapDataPre[dTriggerType].rows(),
381 residual) = m_mapDataPre[dTriggerType].block(0,
382 m_mapDataPre[dTriggerType].cols() - residual,
383 m_mapDataPre[dTriggerType].rows(),
384 residual);
385
386 //Copy new data in
387 m_mapDataPre[dTriggerType].block(0,
388 residual,
389 m_mapDataPre[dTriggerType].rows(),
390 data.cols()) = data;
391 }
392}
393
394//=============================================================================================================
395
396void RtAveragingWorker::mergeData(double dTriggerType)
397{
398 if(m_mapDataPre[dTriggerType].rows() != m_mapDataPost[dTriggerType].rows()) {
399 qDebug() << "[RtAveragingWorker::mergeData] Rows of m_mapDataPre (" << m_mapDataPre[dTriggerType].rows() << ") and m_mapDataPost (" << m_mapDataPost[dTriggerType].rows() << ") are not the same. Returning.";
400 return;
401 }
402
403 MatrixXd mergedData(m_mapDataPre[dTriggerType].rows(), m_mapDataPre[dTriggerType].cols() + m_mapDataPost[dTriggerType].cols());
404
405 mergedData << m_mapDataPre[dTriggerType], m_mapDataPost[dTriggerType];
406
407 //Perform artifact threshold
408 bool bArtifactDetected = false;
409
411 qDebug() << "[RtAveragingWorker::mergeData] Doing artifact reduction for" << m_mapThresholds;
412
413 bArtifactDetected = MNEEpochDataList::checkForArtifact(mergedData,
416 }
417
418 if(!bArtifactDetected) {
419 //Add cut data to average buffer
420 m_mapStimAve[dTriggerType].append(mergedData);
421
422 //Pop data from buffer
423 int iDiff = m_mapStimAve[dTriggerType].size() - m_iNumAverages;
424 if(iDiff > 0) {
425 for(int i = 0; i < iDiff; ++i) {
426 m_mapStimAve[dTriggerType].pop_front();
427 }
428 }
429 }
430}
431
432//=============================================================================================================
433
434void RtAveragingWorker::generateEvoked(double dTriggerType)
435{
436 if(m_mapStimAve[dTriggerType].isEmpty()) {
437 qDebug() << "[RtAveragingWorker::generateEvoked] m_mapStimAve is empty for type" << dTriggerType << "Returning.";
438 return;
439 }
440
441 //Init evoked
442 m_stimEvokedSet.info = *m_pFiffInfo.data();
443 FiffEvoked evoked;
444 evoked.setInfo(*m_pFiffInfo.data());
445 int iEvokedIdx = -1;
446
447 for(int i = 0; i < m_stimEvokedSet.evoked.size(); ++i) {
448 if(m_stimEvokedSet.evoked.at(i).comment == QString::number(dTriggerType)) {
449 evoked = m_stimEvokedSet.evoked.at(i);
450 iEvokedIdx = i;
451 break;
452 }
453 }
454
455 //If the evoked is not yet present add it here
456 if(iEvokedIdx == -1) {
459 evoked.times = RowVectorXf::LinSpaced(m_iPreStimSamples + m_iPostStimSamples,
462 evoked.times[m_iPreStimSamples] = 0.0;
463 evoked.first = 0;
465 evoked.comment = QString::number(dTriggerType);
466 }
467
468 // Generate final evoked
469 MatrixXd finalAverage = MatrixXd::Zero(m_mapStimAve[dTriggerType].first().rows(), m_iPreStimSamples+m_iPostStimSamples);
470
471 for(int i = 0; i < m_mapStimAve[dTriggerType].size(); ++i) {
472 finalAverage += m_mapStimAve[dTriggerType].at(i);
473 }
474
475 if(!m_mapStimAve[dTriggerType].isEmpty()) {
476 finalAverage = finalAverage/m_mapStimAve[dTriggerType].size();
477 }
478
480 finalAverage = Numerics::rescale(finalAverage, evoked.times, m_pairBaselineSec, QString("mean"));
481 }
482
483 evoked.data = finalAverage;
484
485 evoked.nave = m_mapStimAve[dTriggerType].size();
486
487 //Add new data to evoked data set
488 if(iEvokedIdx != -1) {
489 //Evoked data is already present
490 m_stimEvokedSet.evoked[iEvokedIdx] = evoked;
491 } else {
492 //Evoked data is not present yet
493 m_stimEvokedSet.evoked.append(evoked);
494 }
495}
496
497//=============================================================================================================
498
500{
501 //Reset
505
506 //Clear all evoked data information
507 m_stimEvokedSet.evoked.clear();
508
509 //Clear all maps
510 m_mapStimAve.clear();
511 m_mapDataPre.clear();
512 m_mapDataPre[-1.0] = MatrixXd::Zero(m_pFiffInfo->chs.size(), m_iPreStimSamples);
513 m_mapDataPost.clear();
514 m_mapMatDataPostIdx.clear();
516}
517
518//=============================================================================================================
519// DEFINE MEMBER METHODS RtAveraging
520//=============================================================================================================
521
522RtAveraging::RtAveraging(quint32 numAverages,
523 quint32 iPreStimSamples,
524 quint32 iPostStimSamples,
525 quint32 iBaselineFromSecs,
526 quint32 iBaselineToSecs,
527 quint32 iTriggerIndex,
528 FiffInfo::SPtr pFiffInfo,
529 QObject *parent)
530: QObject(parent)
531{
532 qRegisterMetaType<Eigen::MatrixXd>("Eigen::MatrixXd");
533
534 RtAveragingWorker *worker = new RtAveragingWorker(numAverages,
535 iPreStimSamples,
536 iPostStimSamples,
537 iBaselineFromSecs,
538 iBaselineToSecs,
539 iTriggerIndex,
540 pFiffInfo);
541 worker->moveToThread(&m_workerThread);
542
543 connect(&m_workerThread, &QThread::finished,
544 worker, &QObject::deleteLater);
545
546 connect(this, &RtAveraging::operate,
548
549 connect(worker, &RtAveragingWorker::resultReady,
550 this, &RtAveraging::handleResults, Qt::DirectConnection);
551
569 worker, &RtAveragingWorker::reset);
570
571 m_workerThread.start();
572}
573
574//=============================================================================================================
575
580
581//=============================================================================================================
582
583void RtAveraging::append(const MatrixXd &data)
584{
585 emit operate(data);
586}
587
588//=============================================================================================================
589
591 const QStringList &lResponsibleTriggerTypes)
592{
593 emit evokedStim(evokedStimSet,
594 lResponsibleTriggerTypes);
595}
596
597//=============================================================================================================
598
599void RtAveraging::restart(quint32 numAverages,
600 quint32 iPreStimSamples,
601 quint32 iPostStimSamples,
602 quint32 iBaselineFromSecs,
603 quint32 iBaselineToSecs,
604 quint32 iTriggerIndex,
605 FiffInfo::SPtr pFiffInfo)
606{
607 stop();
608
609 RtAveragingWorker *worker = new RtAveragingWorker(numAverages,
610 iPreStimSamples,
611 iPostStimSamples,
612 iBaselineFromSecs,
613 iBaselineToSecs,
614 iTriggerIndex,
615 pFiffInfo);
616 worker->moveToThread(&m_workerThread);
617
618 connect(&m_workerThread, &QThread::finished,
619 worker, &QObject::deleteLater);
620
621 connect(this, &RtAveraging::operate,
623
624 connect(worker, &RtAveragingWorker::resultReady,
625 this, &RtAveraging::handleResults, Qt::DirectConnection);
626
644 worker, &RtAveragingWorker::reset);
645
646 m_workerThread.start();
647}
648
649//=============================================================================================================
650
652{
653 m_workerThread.requestInterruption();
654 m_workerThread.quit();
655 m_workerThread.wait();
656}
657
658//=============================================================================================================
659
661{
662 emit averageNumberChanged(numAve);
663}
664
665//=============================================================================================================
666
667void RtAveraging::setPreStim(qint32 samples,
668 qint32 secs)
669{
670 Q_UNUSED(secs);
671
672 emit averagePreStimChanged(samples,
673 secs);
674}
675
676//=============================================================================================================
677
678void RtAveraging::setPostStim(qint32 samples,
679 qint32 secs)
680{
681 Q_UNUSED(secs);
682
683 emit averagePostStimChanged(samples,
684 secs);
685}
686
687//=============================================================================================================
688
690{
692}
693
694//=============================================================================================================
695
696void RtAveraging::setArtifactReduction(const QMap<QString,double>& mapThresholds)
697{
698 emit averageArtifactReductionChanged(mapThresholds);
699}
700
701//=============================================================================================================
702
704{
705 emit averageBaselineActiveChanged(activate);
706}
707
708//=============================================================================================================
709
711 int fromMSec)
712{
713 emit averageBaselineFromChanged(fromSamp,
714 fromMSec);
715}
716
717//=============================================================================================================
718
720 int toMSec)
721{
722 emit averageBaselineToChanged(toSamp,
723 toMSec);
724}
725
726//=============================================================================================================
727
729{
731}
Header-only Eigen matrix text I/O — round-trips dense matrices to whitespace-separated ASCII for cros...
Ordered list of MNELIB::MNEEpochData objects sharing a common FIFFLIB::FiffInfo.
General numerical helpers: GCD, log2, histogram binning, baseline rescaling, sparsity tests.
Real-time stimulus-locked averaging worker producing running evoked responses.
Threshold and edge-based trigger detection on streaming stim channels.
Core MNE data structures (source spaces, source estimates, hemispheres).
FIFF file I/O, in-memory data structures and high-level readers/writers.
DSPSHARED_EXPORT QMap< int, QList< QPair< int, double > > > detectTriggerFlanksMax(const Eigen::MatrixXd &data, const QList< int > &lTriggerChannels, int iOffsetIndex, double dThreshold, bool bRemoveOffset, int iBurstLengthSamp=100)
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
Background worker thread that accumulates and averages epochs in real time.
void emitEvoked(double dTriggerType, QStringList &lResponsibleTriggerTypes)
void setArtifactReduction(const QMap< QString, double > &mapThresholds)
void fillFrontBuffer(const Eigen::MatrixXd &data, double dTriggerType)
FIFFLIB::FiffInfo::SPtr m_pFiffInfo
QPair< float, float > m_pairBaselineSec
QMap< double, bool > m_mapFillingBackBuffer
RtAveragingWorker(quint32 numAverages, quint32 iPreStimSamples, quint32 iPostStimSamples, quint32 iBaselineFromMSecs, quint32 iBaselineToMSecs, quint32 iTriggerIndex, FIFFLIB::FiffInfo::SPtr pFiffInfo)
QPair< float, float > m_pairBaselineSamp
void setBaselineTo(int toSamp, int toMSec)
FIFFLIB::FiffEvokedSet m_stimEvokedSet
void doAveraging(const Eigen::MatrixXd &rawSegment)
QMap< double, Eigen::MatrixXd > m_mapDataPre
QMap< double, QList< Eigen::MatrixXd > > m_mapStimAve
QMap< double, qint32 > m_mapMatDataPostIdx
void doWork(const Eigen::MatrixXd &matData)
QMap< double, Eigen::MatrixXd > m_mapDataPost
void setPostStim(qint32 samples, qint32 secs)
QMap< QString, double > m_mapThresholds
void resultReady(const FIFFLIB::FiffEvokedSet &evokedStimSet, const QStringList &lResponsibleTriggerTypes)
void fillBackBuffer(const Eigen::MatrixXd &data, double dTriggerType)
void setBaselineFrom(int fromSamp, int fromMSec)
void setPreStim(qint32 samples, qint32 secs)
void mergeData(double dTriggerType)
void generateEvoked(double dTriggerType)
void averageBaselineToChanged(int toSamp, int toMSec)
void setBaselineFrom(int fromSamp, int fromMSec)
void averageBaselineActiveChanged(bool activate)
RtAveraging(quint32 numAverages, quint32 iPreStimSamples, quint32 iPostStimSamples, quint32 iBaselineFromSecs, quint32 iBaselineToSecs, quint32 iTriggerIndex, FIFFLIB::FiffInfo::SPtr pFiffInfo, QObject *parent=0)
void setPreStim(qint32 samples, qint32 secs)
void averagePostStimChanged(qint32 samples, qint32 secs)
void setBaselineTo(int toSamp, int toMSec)
void averageNumberChanged(qint32 numAve)
void averagePreStimChanged(qint32 samples, qint32 secs)
void setAverageNumber(qint32 numAve)
void append(const Eigen::MatrixXd &data)
void averageArtifactReductionChanged(const QMap< QString, double > &mapThresholds)
void handleResults(const FIFFLIB::FiffEvokedSet &evokedStimSet, const QStringList &lResponsibleTriggerTypes)
void setPostStim(qint32 samples, qint32 secs)
void setTriggerChIndx(qint32 idx)
void setBaselineActive(bool activate)
void setArtifactReduction(const QMap< QString, double > &mapThresholds)
void evokedStim(const FIFFLIB::FiffEvokedSet &evokedStimSet, const QStringList &lResponsibleTriggerTypes)
void averageBaselineFromChanged(int fromSamp, int fromMSec)
void averageTriggerChIdxChanged(qint32 idx)
void restart(quint32 numAverages, quint32 iPreStimSamples, quint32 iPostStimSamples, quint32 iBaselineFromSecs, quint32 iBaselineToSecs, quint32 iTriggerIndex, FIFFLIB::FiffInfo::SPtr pFiffInfo)
void operate(const Eigen::MatrixXd &matData)
Single averaged evoked response: time axis, data, baseline, channel info and averaging metadata.
Definition fiff_evoked.h:75
Eigen::RowVectorXf times
Eigen::MatrixXd data
void setInfo(const FiffInfo &p_info, bool proj=true)
QPair< float, float > baseline
Set of FiffEvoked instances sharing one FiffInfo, plus channel-picking and compensation helpers.
QSharedPointer< FiffInfo > SPtr
Definition fiff_info.h:90
static Eigen::MatrixXd rescale(const Eigen::MatrixXd &data, const Eigen::RowVectorXf &times, const QPair< float, float > &baseline, QString mode)
static bool checkForArtifact(const Eigen::MatrixXd &data, const FIFFLIB::FiffInfo &pFiffInfo, const QMap< QString, double > &mapReject, const QStringList &lExcludeChs=QStringList())