v2.0.0
Loading...
Searching...
No Matches
rtfiffrawviewmodel.cpp
Go to the documentation of this file.
1//=============================================================================================================
37
38//=============================================================================================================
39// INCLUDES
40//=============================================================================================================
41
42#include "rtfiffrawviewmodel.h"
43
44#include <fiff/fiff_types.h>
45#include <fiff/fiff_info.h>
46
47#include <utils/mnemath.h>
48#include <utils/ioutils.h>
49
50#include <rtprocessing/sphara.h>
52
53//=============================================================================================================
54// QT INCLUDES
55//=============================================================================================================
56
57#include <QBrush>
58#include <QCoreApplication>
59#include <QtConcurrent>
60#include <QFuture>
61#include <QDebug>
62
63//=============================================================================================================
64// EIGEN INCLUDES
65//=============================================================================================================
66
67//=============================================================================================================
68// STL INCLUDES
69//=============================================================================================================
70
71#include <iostream>
72
73//=============================================================================================================
74// USED NAMESPACES
75//=============================================================================================================
76
77using namespace DISPLIB;
78using namespace UTILSLIB;
79using namespace FIFFLIB;
80using namespace Eigen;
81using namespace RTPROCESSINGLIB;
82
83//=============================================================================================================
84// DEFINE MEMBER METHODS
85//=============================================================================================================
86
87EVENTSLIB::EventManager RtFiffRawViewModel::m_EventManager;
88
90: QAbstractTableModel(parent)
91, m_bProjActivated(false)
92, m_bCompActivated(false)
93, m_bSpharaActivated(false)
94, m_bIsFreezed(false)
95, m_bDrawFilterFront(true)
96, m_bPerformFiltering(false)
97, m_bTriggerDetectionActive(false)
98, m_fSps(1024.0f)
99, m_dTriggerThreshold(0.01)
100, m_iT(10)
101, m_iDownsampling(10)
102, m_iMaxSamples(1024)
103, m_iCurrentSample(0)
104, m_iCurrentStartingSample(0)
105, m_iCurrentSampleFreeze(0)
106, m_iMaxFilterLength(128)
107, m_iCurrentBlockSize(1024)
108, m_iResidual(0)
109, m_iCurrentTriggerChIndex(0)
110, m_iDistanceTimerSpacer(1000)
111, m_iDetectedTriggers(0)
112, m_sFilterChannelType("MEG")
113, m_pFiffInfo(FiffInfo::SPtr::create())
114, m_colBackground(Qt::white)
115{
116 m_EventManager.initSharedMemory(EVENTSLIB::SharedMemoryMode::READWRITE);
117}
118
119//=============================================================================================================
120
122{
123 m_EventManager.stopSharedMemory();
124}
125
126//=============================================================================================================
127//virtual functions
128int RtFiffRawViewModel::rowCount(const QModelIndex & /*parent*/) const
129{
130 if(!m_pFiffInfo->chs.isEmpty()) {
131 return m_pFiffInfo->chs.size();
132 } else {
133 return 0;
134 }
135}
136
137//=============================================================================================================
138
139int RtFiffRawViewModel::columnCount(const QModelIndex & /*parent*/) const
140{
141 return 3;
142}
143
144//=============================================================================================================
145
146QVariant RtFiffRawViewModel::data(const QModelIndex &index, int role) const
147{
148 if(role != Qt::DisplayRole && role != Qt::BackgroundRole) {
149 return QVariant();
150 }
151
152 if (role == Qt::BackgroundRole) {
153 return QVariant(QBrush(m_colBackground));
154 }
155
156 if (index.isValid()) {
157 qint32 row = m_qMapIdxRowSelection.value(index.row(),0);
158
159 //******** first column (chname) ********
160 if(index.column() == 0 && role == Qt::DisplayRole)
161 return QVariant(m_pFiffInfo->ch_names[row]);
162
163 //******** second column (data plot) ********
164 if(index.column() == 1) {
165 QVariant v;
166 RowVectorPair rowVectorPair;
167
168 switch(role) {
169 case Qt::DisplayRole: {
170 if(m_bIsFreezed) {
171 // data freeze
172 if(!m_filterKernel.isEmpty() && m_bPerformFiltering) {
173 rowVectorPair.first = m_matDataFilteredFreeze.data() + row*m_matDataFilteredFreeze.cols();
174 rowVectorPair.second = m_matDataFilteredFreeze.cols();
175 v.setValue(rowVectorPair);
176 } else {
177 rowVectorPair.first = m_matDataRawFreeze.data() + row*m_matDataRawFreeze.cols();
178 rowVectorPair.second = m_matDataRawFreeze.cols();
179 v.setValue(rowVectorPair);
180 }
181 }
182 else {
183 // data stream
184 if(!m_filterKernel.isEmpty() && m_bPerformFiltering) {
185 rowVectorPair.first = m_matDataFiltered.data() + row*m_matDataFiltered.cols();
186 rowVectorPair.second = m_matDataFiltered.cols();
187 v.setValue(rowVectorPair);
188 } else {
189 rowVectorPair.first = m_matDataRaw.data() + row*m_matDataRaw.cols();
190 rowVectorPair.second = m_matDataRaw.cols();
191 v.setValue(rowVectorPair);
192 }
193 }
194
195 return v;
196 }
197 } // end role switch
198 } // end column check
199
200 //******** third column (bad channel) ********
201 if(index.column() == 2 && role == Qt::DisplayRole) {
202 return QVariant(m_pFiffInfo->bads.contains(m_pFiffInfo->ch_names[row]));
203 } // end column check
204
205 } // end index.valid() check
206
207 return QVariant();
208}
209
210//=============================================================================================================
211
212QVariant RtFiffRawViewModel::headerData(int section, Qt::Orientation orientation, int role) const
213{
214 if(role != Qt::DisplayRole && role != Qt::TextAlignmentRole)
215 return QVariant();
216
217 if(orientation == Qt::Horizontal) {
218 switch(section) {
219 case 0: //chname column
220 return QVariant();
221 case 1: //data plot column
222 switch(role) {
223 case Qt::DisplayRole:
224 return QVariant("data plot");
225 case Qt::TextAlignmentRole:
226 return QVariant(Qt::AlignLeft);
227 }
228 return QVariant("data plot");
229 }
230 }
231 else if(orientation == Qt::Vertical) {
232 QModelIndex chname = createIndex(section,0);
233 switch(role) {
234 case Qt::DisplayRole:
235 return QVariant(data(chname).toString());
236 }
237 }
238
239 return QVariant();
240}
241
242//=============================================================================================================
243
244void RtFiffRawViewModel::initSphara()
245{
246 //Load SPHARA matrices for babymeg and vectorview
247 IOUtils::read_eigen_matrix(m_matSpharaVVGradLoaded, QCoreApplication::applicationDirPath() + QString("/../resources/mne_scan/plugins/noisereduction/SPHARA/Vectorview_SPHARA_InvEuclidean_Grad.txt"));
248 IOUtils::read_eigen_matrix(m_matSpharaVVMagLoaded, QCoreApplication::applicationDirPath() + QString("/../resources/mne_scan/plugins/noisereduction/SPHARA/Vectorview_SPHARA_InvEuclidean_Mag.txt"));
249
250 IOUtils::read_eigen_matrix(m_matSpharaBabyMEGInnerLoaded, QCoreApplication::applicationDirPath() + QString("/../resources/mne_scan/plugins/noisereduction/SPHARA/BabyMEG_SPHARA_InvEuclidean_Inner.txt"));
251 IOUtils::read_eigen_matrix(m_matSpharaBabyMEGOuterLoaded, QCoreApplication::applicationDirPath() + QString("/../resources/mne_scan/plugins/noisereduction/SPHARA/BabyMEG_SPHARA_InvEuclidean_Outer.txt"));
252
253 IOUtils::read_eigen_matrix(m_matSpharaEEGLoaded, QCoreApplication::applicationDirPath() + QString("/../resources/mne_scan/plugins/noisereduction/SPHARA/Current_SPHARA_EEG.txt"));
254
255 //Generate indices used to create the SPHARA operators for VectorView
256 m_vecIndicesFirstVV.resize(0);
257 m_vecIndicesSecondVV.resize(0);
258
259 for(int r = 0; r < m_pFiffInfo->chs.size(); ++r) {
260 //Find GRADIOMETERS
261 if(m_pFiffInfo->chs.at(r).chpos.coil_type == 3012) {
262 m_vecIndicesFirstVV.conservativeResize(m_vecIndicesFirstVV.rows()+1);
263 m_vecIndicesFirstVV(m_vecIndicesFirstVV.rows()-1) = r;
264 }
265
266 //Find Magnetometers
267 if(m_pFiffInfo->chs.at(r).chpos.coil_type == 3024) {
268 m_vecIndicesSecondVV.conservativeResize(m_vecIndicesSecondVV.rows()+1);
269 m_vecIndicesSecondVV(m_vecIndicesSecondVV.rows()-1) = r;
270 }
271 }
272
273 //Generate indices used to create the SPHARA operators for babyMEG
274 m_vecIndicesFirstBabyMEG.resize(0);
275 for(int r = 0; r < m_pFiffInfo->chs.size(); ++r) {
276 //Find INNER LAYER
277 if(m_pFiffInfo->chs.at(r).chpos.coil_type == 7002) {
278 m_vecIndicesFirstBabyMEG.conservativeResize(m_vecIndicesFirstBabyMEG.rows()+1);
279 m_vecIndicesFirstBabyMEG(m_vecIndicesFirstBabyMEG.rows()-1) = r;
280 }
281
282 //TODO: Find outer layer
283 }
284
285 //Generate indices used to create the SPHARA operators for EEG layouts
286 m_vecIndicesFirstEEG.resize(0);
287 for(int r = 0; r < m_pFiffInfo->chs.size(); ++r) {
288 //Find EEG
289 if(m_pFiffInfo->chs.at(r).kind == FIFFV_EEG_CH) {
290 m_vecIndicesFirstEEG.conservativeResize(m_vecIndicesFirstEEG.rows()+1);
291 m_vecIndicesFirstEEG(m_vecIndicesFirstEEG.rows()-1) = r;
292 }
293 }
294
295 //Create Sphara operator for the first time
296 updateSpharaOptions("BabyMEG", 270, 105);
297
298 qDebug()<<"RtFiffRawViewModel::initSphara - Read VectorView mag matrix "<<m_matSpharaVVMagLoaded.rows()<<m_matSpharaVVMagLoaded.cols()<<"and grad matrix"<<m_matSpharaVVGradLoaded.rows()<<m_matSpharaVVGradLoaded.cols();
299 qDebug()<<"RtFiffRawViewModel::initSphara - Read BabyMEG inner layer matrix "<<m_matSpharaBabyMEGInnerLoaded.rows()<<m_matSpharaBabyMEGInnerLoaded.cols()<<"and outer layer matrix"<<m_matSpharaBabyMEGOuterLoaded.rows()<<m_matSpharaBabyMEGOuterLoaded.cols();
300}
301
302//=============================================================================================================
303
304void RtFiffRawViewModel::setFiffInfo(QSharedPointer<FIFFLIB::FiffInfo> &p_pFiffInfo)
305{
306 if(p_pFiffInfo) {
307 RowVectorXi sel;// = RowVectorXi(0,0);
308 QStringList emptyExclude;
309
310 if(p_pFiffInfo->bads.size() > 0) {
311 sel = FiffInfoBase::pick_channels(p_pFiffInfo->ch_names, p_pFiffInfo->bads, emptyExclude);
312 }
313
314 m_vecBadIdcs = sel;
315
316 m_pFiffInfo = p_pFiffInfo;
317
319
320 //Resize data matrix without touching the stored values
321 m_matDataRaw.conservativeResize(m_pFiffInfo->chs.size(), m_iMaxSamples);
322 m_matDataRaw.setZero();
323
324 m_matDataFiltered.conservativeResize(m_pFiffInfo->chs.size(), m_iMaxSamples);
325 m_matDataFiltered.setZero();
326
327 m_vecLastBlockFirstValuesFiltered.conservativeResize(m_pFiffInfo->chs.size());
328 m_vecLastBlockFirstValuesFiltered.setZero();
329
330 m_vecLastBlockFirstValuesRaw.conservativeResize(m_pFiffInfo->chs.size());
331 m_vecLastBlockFirstValuesRaw.setZero();
332
333 m_matOverlap.conservativeResize(m_pFiffInfo->chs.size(), m_iMaxFilterLength);
334
335 m_matSparseProjMult = SparseMatrix<double>(m_pFiffInfo->chs.size(),m_pFiffInfo->chs.size());
336 m_matSparseCompMult = SparseMatrix<double>(m_pFiffInfo->chs.size(),m_pFiffInfo->chs.size());
337 m_matSparseSpharaMult = SparseMatrix<double>(m_pFiffInfo->chs.size(),m_pFiffInfo->chs.size());
338 m_matSparseProjCompMult = SparseMatrix<double>(m_pFiffInfo->chs.size(),m_pFiffInfo->chs.size());
339
340 m_matSparseProjMult.setIdentity();
341 m_matSparseCompMult.setIdentity();
342 m_matSparseSpharaMult.setIdentity();
343 m_matSparseProjCompMult.setIdentity();
344
345 //Create the initial Compensator projector
347
348 //Initialize filter channel names
349 int visibleInit = 20;
350 QStringList filterChannels;
351
352 if(visibleInit > m_pFiffInfo->chs.size()) {
353 while(visibleInit>m_pFiffInfo->chs.size()) {
354 visibleInit--;
355 }
356 }
357
358 for(qint32 b = 0; b < visibleInit; ++b) {
359 filterChannels.append(m_pFiffInfo->ch_names.at(b));
360 }
361
362 createFilterChannelList(filterChannels);
363
364// //Look for trigger channels and initialise detected trigger map
365// for(int i = 0; i<m_pFiffInfo->chs.size(); ++i) {
366// if(m_pFiffInfo->chs[i].kind == FIFFV_STIM_CH/* && m_pFiffInfo->chs[i].ch_name == "STI 001"*/)
367// m_lTriggerChannelIndices.append(i);
368// }
369
370 //Init the sphara operators
371 initSphara();
372 } else {
373 m_vecBadIdcs = RowVectorXi(0,0);
374 m_matProj = MatrixXd(0,0);
375 m_matComp = MatrixXd(0,0);
376 }
377}
378
379//=============================================================================================================
380
381void RtFiffRawViewModel::setSamplingInfo(float sps, int T, bool bSetZero)
382{
383 beginResetModel();
384
385 m_iT = T;
386
387 m_iMaxSamples = (qint32) ceil(sps * T);
388
389 //Resize data matrix without touching the stored values
390 m_matDataRaw.conservativeResize(m_pFiffInfo->chs.size(), m_iMaxSamples);
391 m_matDataFiltered.conservativeResize(m_pFiffInfo->chs.size(), m_iMaxSamples);
392 m_vecLastBlockFirstValuesRaw.conservativeResize(m_pFiffInfo->chs.size());
393 m_vecLastBlockFirstValuesFiltered.conservativeResize(m_pFiffInfo->chs.size());
394
395 if(bSetZero) {
396 m_matDataRaw.setZero();
397 m_matDataFiltered.setZero();
398 m_vecLastBlockFirstValuesRaw.setZero();
399 m_vecLastBlockFirstValuesFiltered.setZero();
400 }
401
402 if(m_iCurrentSample>m_iMaxSamples) {
403 m_iCurrentStartingSample += m_iCurrentSample;
404 m_iCurrentSample = 0;
405 }
406
407 endResetModel();
408}
409
410//=============================================================================================================
411
413{
414 if(!m_filterKernel.isEmpty() && m_bPerformFiltering) {
415 return m_matDataFiltered.block(0, m_iCurrentSample-m_iCurrentBlockSize, m_matDataFiltered.rows(), m_iCurrentBlockSize);
416 }
417
418 return m_matDataRaw.block(0, m_iCurrentSample-m_iCurrentBlockSize, m_matDataRaw.rows(), m_iCurrentBlockSize);
419}
420
421//=============================================================================================================
422
423void RtFiffRawViewModel::addData(const QList<MatrixXd> &data)
424{
425 //SSP
426 bool doProj = m_bProjActivated && m_matDataRaw.cols() > 0 && m_matDataRaw.rows() == m_matProj.cols() ? true : false;
427
428 //Compensator
429 bool doComp = m_bCompActivated && m_matDataRaw.cols() > 0 && m_matDataRaw.rows() == m_matComp.cols() ? true : false;
430
431 //SPHARA
432 bool doSphara = m_bSpharaActivated && m_matSparseSpharaMult.cols() > 0 && m_matDataRaw.rows() == m_matSparseSpharaMult.cols() ? true : false;
433
434 //Copy new data into the global data matrix
435 for(qint32 b = 0; b < data.size(); ++b) {
436 int nCol = data.at(b).cols();
437 int nRow = data.at(b).rows();
438
439 if(nRow != m_matDataRaw.rows()) {
440 qDebug()<<"incoming data does not match internal data row size. Returning...";
441 return;
442 }
443
444 //Reset m_iCurrentSample and start filling the data matrix from the beginning again. Also add residual amount of data to the end of the matrix.
445 if(m_iCurrentSample+nCol > m_matDataRaw.cols()) {
446 m_iResidual = nCol - ((m_iCurrentSample+nCol) % m_matDataRaw.cols());
447
448 if(m_iResidual == nCol) {
449 m_iResidual = 0;
450 }
451
452// std::cout<<"incoming data exceeds internal data cols by: "<<(m_iCurrentSample+nCol) % m_matDataRaw.cols()<<std::endl;
453// std::cout<<"m_iCurrentSample+nCol: "<<m_iCurrentSample+nCol<<std::endl;
454// std::cout<<"m_matDataRaw.cols(): "<<m_matDataRaw.cols()<<std::endl;
455// std::cout<<"nCol-m_iResidual: "<<nCol-m_iResidual<<std::endl<<std::endl;
456
457 if(doComp) {
458 if(doProj) {
459 //Comp + Proj
460 m_matDataRaw.block(0, m_iCurrentSample, nRow, m_iResidual) = m_matSparseProjCompMult * data.at(b).block(0,0,nRow,m_iResidual);
461 } else {
462 //Comp
463 m_matDataRaw.block(0, m_iCurrentSample, nRow, m_iResidual) = m_matSparseCompMult * data.at(b).block(0,0,nRow,m_iResidual);
464 }
465 } else {
466 if(doProj)
467 {
468 //Proj
469 m_matDataRaw.block(0, m_iCurrentSample, nRow, m_iResidual) = m_matSparseProjMult * data.at(b).block(0,0,nRow,m_iResidual);
470 } else {
471 //None - Raw
472 m_matDataRaw.block(0, m_iCurrentSample, nRow, m_iResidual) = data.at(b).block(0,0,nRow,m_iResidual);
473 }
474 }
475
476 m_iCurrentStartingSample += m_iCurrentSample;
477 m_iCurrentStartingSample += m_iResidual;
478
479 m_iCurrentSample = 0;
480
481 if(!m_bIsFreezed) {
482 m_vecLastBlockFirstValuesFiltered = m_matDataFiltered.col(0);
483 m_vecLastBlockFirstValuesRaw = m_matDataRaw.col(0);
484 }
485
486 //Store old detected triggers
487 m_qMapDetectedTriggerOld = m_qMapDetectedTrigger;
488
489 //Clear detected triggers
490 if(m_bTriggerDetectionActive) {
491 QMutableMapIterator<int,QList<QPair<int,double> > > i(m_qMapDetectedTrigger);
492 while (i.hasNext()) {
493 i.next();
494 i.value().clear();
495 }
496 }
497 } else {
498 m_iResidual = 0;
499 }
500
501 //std::cout<<"incoming data is ok"<<std::endl;
502
503 if(doComp) {
504 if(doProj) {
505 //Comp + Proj
506 m_matDataRaw.block(0, m_iCurrentSample, nRow, nCol) = m_matSparseProjCompMult * data.at(b);
507 } else {
508 //Comp
509 m_matDataRaw.block(0, m_iCurrentSample, nRow, nCol) = m_matSparseCompMult * data.at(b);
510 }
511 } else {
512 if(doProj) {
513 //Proj
514 m_matDataRaw.block(0, m_iCurrentSample, nRow, nCol) = m_matSparseProjMult * data.at(b);
515 } else {
516 //None - Raw
517 m_matDataRaw.block(0, m_iCurrentSample, nRow, nCol) = data.at(b);
518 }
519 }
520
521 //Filter if neccessary else set filtered data matrix to zero
522 if(!m_filterKernel.isEmpty() && m_bPerformFiltering) {
523 filterDataBlock(m_matDataRaw.block(0, m_iCurrentSample, nRow, nCol), m_iCurrentSample);
524
525 //Perform SPHARA on filtered data after actual filtering - SPHARA should be applied on the best possible data
526 if(doSphara) {
527 if(m_iCurrentSample-m_iMaxFilterLength/2 >= 0) {
528 m_matDataFiltered.block(0, m_iCurrentSample-m_iMaxFilterLength/2, nRow, nCol) = m_matSparseSpharaMult * m_matDataFiltered.block(0, m_iCurrentSample-m_iMaxFilterLength/2, nRow, nCol);
529 }
530 else {
531 if(m_iCurrentSample-m_iMaxFilterLength/2 < 0) {
532 m_matDataFiltered.block(0, 0, nRow, nCol) = m_matSparseSpharaMult * m_matDataFiltered.block(0, 0, nRow, nCol);
533 int iResidual = m_iResidual+m_iMaxFilterLength/2;
534 m_matDataFiltered.block(0, m_matDataFiltered.cols()-iResidual, nRow, iResidual) = m_matSparseSpharaMult * m_matDataFiltered.block(0, m_matDataFiltered.cols()-iResidual, nRow, iResidual);
535 }
536 }
537 }
538 } else {
539 m_matDataFiltered.block(0, m_iCurrentSample, nRow, nCol).setZero();// = m_matDataRaw.block(0, m_iCurrentSample, nRow, nCol);
540
541 //Perform SPHARA on raw data data
542 if(doSphara) {
543 m_matDataRaw.block(0, m_iCurrentSample, nRow, nCol) = m_matSparseSpharaMult * m_matDataRaw.block(0, m_iCurrentSample, nRow, nCol);
544 }
545 }
546
547 m_iCurrentSample += nCol;
548 m_iCurrentBlockSize = nCol;
549
550 //detect the trigger flanks in the trigger channels
551 if(m_bTriggerDetectionActive) {
552 int iOldDetectedTriggers = m_qMapDetectedTrigger[m_iCurrentTriggerChIndex].size();
553
554 QList<QPair<int,double> > qMapDetectedTrigger = RTPROCESSINGLIB::detectTriggerFlanksMax(data.at(b), m_iCurrentTriggerChIndex, m_iCurrentSample-nCol, m_dTriggerThreshold, true, 500);
555 //QList<QPair<int,double> > qMapDetectedTrigger = RTPROCESSINGLIB::detectTriggerFlanksGrad(data.at(b), m_iCurrentTriggerChIndex, m_iCurrentSample-nCol, m_dTriggerThreshold, false, "Rising");
556
557 //Append results to already found triggers
558 m_qMapDetectedTrigger[m_iCurrentTriggerChIndex].append(qMapDetectedTrigger);
559
560 //Compute newly counted triggers
561 int newTriggers = m_qMapDetectedTrigger[m_iCurrentTriggerChIndex].size() - iOldDetectedTriggers;
562
563 if(newTriggers!=0) {
564 m_iDetectedTriggers += newTriggers;
565 emit triggerDetected(m_iDetectedTriggers, m_qMapDetectedTrigger);
566 }
567 }
568 }
569
570 //Update data content
571 QModelIndex topLeft = this->index(0,1);
572 QModelIndex bottomRight = this->index(m_pFiffInfo->ch_names.size()-1,1);
573 QVector<int> roles; roles << Qt::DisplayRole;
574
575 emit dataChanged(topLeft, bottomRight, roles);
576}
577
578//=============================================================================================================
579
581{
582 if(row < m_qMapIdxRowSelection.size()) {
583 qint32 chRow = m_qMapIdxRowSelection[row];
584 return m_pFiffInfo->chs.at(chRow).kind;
585 }
586
587 return 0;
588}
589
590//=============================================================================================================
591
593{
594 if(row < m_qMapIdxRowSelection.size()) {
595 qint32 chRow = m_qMapIdxRowSelection[row];
596 return m_pFiffInfo->chs.at(chRow).unit;
597 }
598
599 return FIFF_UNIT_NONE;
600}
601
602//=============================================================================================================
603
605{
606 if(row < m_qMapIdxRowSelection.size()) {
607 qint32 chRow = m_qMapIdxRowSelection[row];
608 return m_pFiffInfo->chs.at(chRow).chpos.coil_type;
609 }
610
611 return FIFFV_COIL_NONE;
612}
613
614//=============================================================================================================
615
616void RtFiffRawViewModel::selectRows(const QList<qint32> &selection)
617{
618 beginResetModel();
619
620 m_qMapIdxRowSelection.clear();
621
622 qint32 count = 0;
623 for(qint32 i = 0; i < selection.size(); ++i) {
624 if(selection[i] < m_pFiffInfo->chs.size()) {
625 m_qMapIdxRowSelection.insert(count,selection[i]);
626 ++count;
627 }
628 }
629
630 emit newSelection(selection);
631
632 endResetModel();
633}
634
635//=============================================================================================================
636
637void RtFiffRawViewModel::hideRows(const QList<qint32> &selection)
638{
639 beginResetModel();
640
641 for(qint32 i = 0; i < selection.size(); ++i) {
642 if(m_qMapIdxRowSelection.contains(selection.at(i))) {
643 m_qMapIdxRowSelection.remove(selection.at(i));
644 }
645 }
646
647 emit newSelection(selection);
648
649 endResetModel();
650}
651
652//=============================================================================================================
653
655{
656 beginResetModel();
657
658 m_qMapIdxRowSelection.clear();
659
660 for(qint32 i = 0; i < m_pFiffInfo->chs.size(); ++i) {
661 m_qMapIdxRowSelection.insert(i,i);
662 }
663
664 endResetModel();
665}
666
667//=============================================================================================================
668
669void RtFiffRawViewModel::toggleFreeze(const QModelIndex &)
670{
671 m_bIsFreezed = !m_bIsFreezed;
672
673 if(m_bIsFreezed) {
674 m_matDataRawFreeze = m_matDataRaw;
675 m_matDataFilteredFreeze = m_matDataFiltered;
676 m_qMapDetectedTriggerFreeze = m_qMapDetectedTrigger;
677 m_qMapDetectedTriggerOldFreeze = m_qMapDetectedTriggerOld;
678
679 m_iCurrentSampleFreeze = m_iCurrentSample;
680 }
681
682 //Update data content
683 QModelIndex topLeft = this->index(0,1);
684 QModelIndex bottomRight = this->index(m_pFiffInfo->chs.size()-1,1);
685 QVector<int> roles; roles << Qt::DisplayRole;
686
687 emit dataChanged(topLeft, bottomRight, roles);
688}
689
690//=============================================================================================================
691
692void RtFiffRawViewModel::setScaling(const QMap< qint32,float >& p_qMapChScaling)
693{
694 beginResetModel();
695 m_qMapChScaling = p_qMapChScaling;
696 endResetModel();
697}
698
699//=============================================================================================================
700
701void RtFiffRawViewModel::updateProjection(const QList<FIFFLIB::FiffProj>& projs)
702{
703 // Update the SSP projector
704 if(m_pFiffInfo) {
705 //If a minimum of one projector is active set m_bProjActivated to true so that this model applies the ssp to the incoming data
706 m_bProjActivated = false;
707 m_pFiffInfo->projs = projs;
708
709 for(qint32 i = 0; i < this->m_pFiffInfo->projs.size(); ++i) {
710 if(this->m_pFiffInfo->projs[i].active) {
711 m_bProjActivated = true;
712 break;
713 }
714 }
715
716 this->m_pFiffInfo->make_projector(m_matProj);
717
718 qDebug() << "RtFiffRawViewModel::updateProjection - New projection calculated.";
719
720 //set columns of matrix to zero depending on bad channels indexes
721 for(qint32 j = 0; j < m_vecBadIdcs.cols(); ++j) {
722 m_matProj.col(m_vecBadIdcs[j]).setZero();
723 }
724
725// std::cout << "Bads\n" << m_vecBadIdcs << std::endl;
726// std::cout << "Proj\n";
727// std::cout << m_matProj.block(0,0,10,10) << std::endl;
728
729 //
730 // Make proj sparse
731 //
732 qint32 nchan = this->m_pFiffInfo->nchan;
733 qint32 i, k;
734
735 typedef Eigen::Triplet<double> T;
736 std::vector<T> tripletList;
737 tripletList.reserve(nchan);
738
739 tripletList.clear();
740 tripletList.reserve(m_matProj.rows()*m_matProj.cols());
741 for(i = 0; i < m_matProj.rows(); ++i) {
742 for(k = 0; k < m_matProj.cols(); ++k) {
743 if(m_matProj(i,k) != 0) {
744 tripletList.push_back(T(i, k, m_matProj(i,k)));
745 }
746 }
747 }
748
749 m_matSparseProjMult = SparseMatrix<double>(m_matProj.rows(),m_matProj.cols());
750 if(tripletList.size() > 0) {
751 m_matSparseProjMult.setFromTriplets(tripletList.begin(), tripletList.end());
752 }
753
754 //Create full multiplication matrix
755 m_matSparseProjCompMult = m_matSparseProjMult * m_matSparseCompMult;
756 }
757}
758
759//=============================================================================================================
760
762{
763 // Update the compensator
764 if(m_pFiffInfo) {
765 if(to == 0) {
766 m_bCompActivated = false;
767 } else {
768 m_bCompActivated = true;
769 }
770
771// qDebug()<<"to"<<to;
772// qDebug()<<"from"<<from;
773// qDebug()<<"m_bCompActivated"<<m_bCompActivated;
774
775 FiffCtfComp newComp;
776 this->m_pFiffInfo->make_compensator(0, to, newComp);//Do this always from 0 since we always read new raw data, we never actually perform a multiplication on already existing data
777
778 //We do not need to call this->m_pFiffInfo->set_current_comp(to);
779 //Because we will set the compensators to the coil in the same FiffInfo which is already used to write to file.
780 //Note that the data is written in raw form not in compensated form.
781 m_matComp = newComp.data->data;
782
783 //
784 // Make proj sparse
785 //
786 qint32 nchan = this->m_pFiffInfo->nchan;
787 qint32 i, k;
788
789 typedef Eigen::Triplet<double> T;
790 std::vector<T> tripletList;
791 tripletList.reserve(nchan);
792
793 tripletList.clear();
794 tripletList.reserve(m_matComp.rows()*m_matComp.cols());
795 for(i = 0; i < m_matComp.rows(); ++i) {
796 for(k = 0; k < m_matComp.cols(); ++k) {
797 if(m_matComp(i,k) != 0) {
798 tripletList.push_back(T(i, k, m_matComp(i,k)));
799 }
800 }
801 }
802
803 m_matSparseCompMult = SparseMatrix<double>(m_matComp.rows(),m_matComp.cols());
804 if(tripletList.size() > 0) {
805 m_matSparseCompMult.setFromTriplets(tripletList.begin(), tripletList.end());
806 }
807
808 //Create full multiplication matrix
809 m_matSparseProjCompMult = m_matSparseProjMult * m_matSparseCompMult;
810 }
811}
812
813//=============================================================================================================
814
816{
817 m_bSpharaActivated = state;
818}
819
820//=============================================================================================================
821
822void RtFiffRawViewModel::updateSpharaOptions(const QString& sSytemType, int nBaseFctsFirst, int nBaseFctsSecond)
823{
824 if(m_pFiffInfo) {
825 qDebug()<<"RtFiffRawViewModel::updateSpharaOptions - Creating SPHARA operator for"<<sSytemType;
826
827 MatrixXd matSpharaMultFirst = MatrixXd::Identity(m_pFiffInfo->chs.size(), m_pFiffInfo->chs.size());
828 MatrixXd matSpharaMultSecond = MatrixXd::Identity(m_pFiffInfo->chs.size(), m_pFiffInfo->chs.size());
829
830 if(sSytemType == "VectorView" && m_matSpharaVVGradLoaded.size() != 0 && m_matSpharaVVMagLoaded.size() != 0) {
831 matSpharaMultFirst = RTPROCESSINGLIB::makeSpharaProjector(m_matSpharaVVGradLoaded, m_vecIndicesFirstVV, m_pFiffInfo->nchan, nBaseFctsFirst, 1); //GRADIOMETERS
832 matSpharaMultSecond = RTPROCESSINGLIB::makeSpharaProjector(m_matSpharaVVMagLoaded, m_vecIndicesSecondVV, m_pFiffInfo->nchan, nBaseFctsSecond, 0); //Magnetometers
833 }
834
835 if(sSytemType == "BabyMEG" && m_matSpharaBabyMEGInnerLoaded.size() != 0) {
836 matSpharaMultFirst = RTPROCESSINGLIB::makeSpharaProjector(m_matSpharaBabyMEGInnerLoaded, m_vecIndicesFirstBabyMEG, m_pFiffInfo->nchan, nBaseFctsFirst, 0); //InnerLayer
837 }
838
839 if(sSytemType == "EEG" && m_matSpharaEEGLoaded.size() != 0) {
840 matSpharaMultFirst = RTPROCESSINGLIB::makeSpharaProjector(m_matSpharaEEGLoaded, m_vecIndicesFirstEEG, m_pFiffInfo->nchan, nBaseFctsFirst, 0); //InnerLayer
841 }
842
843 //Write final operator matrices to file
844// IOUtils::write_eigen_matrix(matSpharaMultFirst, QString(QCoreApplication::applicationDirPath() + "/../resources/mne_scan/plugins/noisereduction/SPHARA/matSpharaMultFirst.txt"));
845// IOUtils::write_eigen_matrix(matSpharaMultSecond, QString(QCoreApplication::applicationDirPath() + "/../resources/mne_scan/plugins/noisereduction/SPHARA/matSpharaMultSecond.txt"));
846// IOUtils::write_eigen_matrix(m_matSpharaEEGLoaded, QString(QCoreApplication::applicationDirPath() + "/../resources/mne_scan/plugins/noisereduction/SPHARA/m_matSpharaEEGLoaded.txt"));
847
848 //
849 // Make operators sparse
850 //
851 qint32 nchan = this->m_pFiffInfo->nchan;
852 qint32 i, k;
853
854 typedef Eigen::Triplet<double> T;
855 std::vector<T> tripletList;
856 tripletList.reserve(nchan);
857
858 //First operator
859 tripletList.clear();
860 tripletList.reserve(matSpharaMultFirst.rows()*matSpharaMultFirst.cols());
861 for(i = 0; i < matSpharaMultFirst.rows(); ++i) {
862 for(k = 0; k < matSpharaMultFirst.cols(); ++k) {
863 if(matSpharaMultFirst(i,k) != 0) {
864 tripletList.push_back(T(i, k, matSpharaMultFirst(i,k)));
865 }
866 }
867 }
868
869 Eigen::SparseMatrix<double> matSparseSpharaMultFirst = SparseMatrix<double>(m_pFiffInfo->chs.size(),m_pFiffInfo->chs.size());
870
871 matSparseSpharaMultFirst = SparseMatrix<double>(matSpharaMultFirst.rows(),matSpharaMultFirst.cols());
872 if(tripletList.size() > 0) {
873 matSparseSpharaMultFirst.setFromTriplets(tripletList.begin(), tripletList.end());
874 }
875
876 //Second operator
877 tripletList.clear();
878 tripletList.reserve(matSpharaMultSecond.rows()*matSpharaMultSecond.cols());
879
880 for(i = 0; i < matSpharaMultSecond.rows(); ++i) {
881 for(k = 0; k < matSpharaMultSecond.cols(); ++k) {
882 if(matSpharaMultSecond(i,k) != 0) {
883 tripletList.push_back(T(i, k, matSpharaMultSecond(i,k)));
884 }
885 }
886 }
887
888 Eigen::SparseMatrix<double>matSparseSpharaMultSecond = SparseMatrix<double>(m_pFiffInfo->chs.size(),m_pFiffInfo->chs.size());
889
890 if(tripletList.size() > 0) {
891 matSparseSpharaMultSecond.setFromTriplets(tripletList.begin(), tripletList.end());
892 }
893
894 //Create full multiplication matrix
895 m_matSparseSpharaMult = matSparseSpharaMultFirst * matSparseSpharaMultSecond;
896 }
897}
898
899//=============================================================================================================
900
902{
903 m_filterKernel = filterData;
904
905 m_iMaxFilterLength = 1;
906 for(int i=0; i<filterData.size(); ++i) {
907 if(m_iMaxFilterLength<filterData.at(i).getFilterOrder()) {
908 m_iMaxFilterLength = filterData.at(i).getFilterOrder();
909 }
910 }
911
912 m_matOverlap.conservativeResize(m_pFiffInfo->chs.size(), m_iMaxFilterLength);
913 m_matOverlap.setZero();
914
915 m_bDrawFilterFront = false;
916
917 //Filter all visible data channels at once
918 //filterDataBlock();
919}
920
921//=============================================================================================================
922
924{
925 m_bPerformFiltering = state;
926}
927
928//=============================================================================================================
929
931{
932 m_colBackground = color;
933}
934
935//=============================================================================================================
936
937void RtFiffRawViewModel::setFilterChannelType(const QString &channelType)
938{
939 m_sFilterChannelType = channelType;
940 m_filterChannelList = m_visibleChannelList;
941
942 //This version is for when all channels of a type are to be filtered (not only the visible ones).
943 //Create channel filter list independent from channelNames
944 m_filterChannelList.clear();
945
946 for(int i = 0; i<m_pFiffInfo->chs.size(); ++i) {
947 if((m_pFiffInfo->chs.at(i).kind == FIFFV_MEG_CH || m_pFiffInfo->chs.at(i).kind == FIFFV_EEG_CH ||
948 m_pFiffInfo->chs.at(i).kind == FIFFV_EOG_CH || m_pFiffInfo->chs.at(i).kind == FIFFV_ECG_CH ||
949 m_pFiffInfo->chs.at(i).kind == FIFFV_EMG_CH)/* && !m_pFiffInfo->bads.contains(m_pFiffInfo->chs.at(i).ch_name)*/) {
950 if(m_sFilterChannelType == "All") {
951 m_filterChannelList << m_pFiffInfo->chs.at(i).ch_name;
952 } else if(m_pFiffInfo->chs.at(i).ch_name.contains(m_sFilterChannelType)) {
953 m_filterChannelList << m_pFiffInfo->chs.at(i).ch_name;
954 }
955 }
956 }
957
958// if(channelType != "All") {
959// QMutableListIterator<QString> i(m_filterChannelList);
960// while(i.hasNext()) {
961// QString val = i.next();
962// if(!val.contains(channelType, Qt::CaseInsensitive)) {
963// i.remove();
964// }
965// }
966// }
967
968// m_bDrawFilterFront = false;
969
970 //Filter all visible data channels at once
971 //filterDataBlock();
972}
973
974//=============================================================================================================
975
977{
978 m_filterChannelList.clear();
979 m_visibleChannelList = channelNames;
980
981// //Create channel fiter list based on channelNames
982// for(int i = 0; i<m_pFiffInfo->chs.size(); ++i) {
983// if((m_pFiffInfo->chs.at(i).kind == FIFFV_MEG_CH || m_pFiffInfo->chs.at(i).kind == FIFFV_EEG_CH ||
984// m_pFiffInfo->chs.at(i).kind == FIFFV_EOG_CH || m_pFiffInfo->chs.at(i).kind == FIFFV_ECG_CH ||
985// m_pFiffInfo->chs.at(i).kind == FIFFV_EMG_CH) && !m_pFiffInfo->bads.contains(m_pFiffInfo->chs.at(i).ch_name)) {
986// if(m_sFilterChannelType == "All" && channelNames.contains(m_pFiffInfo->chs.at(i).ch_name))
987// m_filterChannelList << m_pFiffInfo->chs.at(i).ch_name;
988// else if(m_pFiffInfo->chs.at(i).ch_name.contains(m_sFilterChannelType) && channelNames.contains(m_pFiffInfo->chs.at(i).ch_name))
989// m_filterChannelList << m_pFiffInfo->chs.at(i).ch_name;
990// }
991// }
992
993 //Create channel filter list independent from channelNames
994 for(int i = 0; i < m_pFiffInfo->chs.size(); ++i) {
995 if((m_pFiffInfo->chs.at(i).kind == FIFFV_MEG_CH || m_pFiffInfo->chs.at(i).kind == FIFFV_EEG_CH ||
996 m_pFiffInfo->chs.at(i).kind == FIFFV_EOG_CH || m_pFiffInfo->chs.at(i).kind == FIFFV_ECG_CH ||
997 m_pFiffInfo->chs.at(i).kind == FIFFV_EMG_CH)/* && !m_pFiffInfo->bads.contains(m_pFiffInfo->chs.at(i).ch_name)*/) {
998 if(m_sFilterChannelType == "All") {
999 m_filterChannelList << m_pFiffInfo->chs.at(i).ch_name;
1000 } else if(m_pFiffInfo->chs.at(i).ch_name.contains(m_sFilterChannelType)) {
1001 m_filterChannelList << m_pFiffInfo->chs.at(i).ch_name;
1002 }
1003 }
1004 }
1005
1006// m_bDrawFilterFront = false;
1007
1008// for(int i = 0; i<m_filterChannelList.size(); ++i)
1009// std::cout<<m_filterChannelList.at(i).toStdString()<<std::endl;
1010
1011 //Filter all visible data channels at once
1012 //filterDataBlock();
1013}
1014
1015//=============================================================================================================
1016
1017void RtFiffRawViewModel::markChBad(QModelIndex ch, bool status)
1018{
1019 QList<FiffChInfo> chInfolist = m_pFiffInfo->chs;
1020
1021 if(status) {
1022 if(!m_pFiffInfo->bads.contains(chInfolist[ch.row()].ch_name))
1023 m_pFiffInfo->bads.append(chInfolist[ch.row()].ch_name);
1024 qDebug() << "RawModel:" << chInfolist[ch.row()].ch_name << "marked as bad.";
1025 } else if(m_pFiffInfo->bads.contains(chInfolist[ch.row()].ch_name)) {
1026 int index = m_pFiffInfo->bads.indexOf(chInfolist[ch.row()].ch_name);
1027 m_pFiffInfo->bads.removeAt(index);
1028 qDebug() << "RawModel:" << chInfolist[ch.row()].ch_name << "marked as good.";
1029 }
1030
1031 //Redefine channels which are to be filtered
1032 QStringList channelNames;
1033 createFilterChannelList(channelNames);
1034
1035 //Update indeices of bad channels (this vector is needed when creating new ssp operators)
1036 QStringList emptyExclude;
1037 m_vecBadIdcs = FiffInfoBase::pick_channels(m_pFiffInfo->ch_names, m_pFiffInfo->bads, emptyExclude);
1038
1039 emit dataChanged(ch,ch);
1040}
1041
1042//=============================================================================================================
1043
1044void RtFiffRawViewModel::triggerInfoChanged(const QMap<double, QColor>& colorMap, bool active, QString triggerCh, double threshold)
1045{
1046 m_qMapTriggerColor = colorMap;
1047 m_bTriggerDetectionActive = active;
1048 m_dTriggerThreshold = threshold;
1049
1050 //Find channel index and initialise detected trigger map if channel name changed
1051 if(m_sCurrentTriggerCh != triggerCh) {
1052 m_sCurrentTriggerCh = triggerCh;
1053
1054 QList<QPair<int,double> > temp;
1055 m_qMapDetectedTrigger.clear();
1056
1057 for(int i = 0; i < m_pFiffInfo->chs.size(); ++i) {
1058 if(m_pFiffInfo->chs[i].ch_name == m_sCurrentTriggerCh) {
1059 m_iCurrentTriggerChIndex = i;
1060 m_qMapDetectedTrigger.insert(i, temp);
1061 break;
1062 }
1063 }
1064 }
1065
1066 m_sCurrentTriggerCh = triggerCh;
1067}
1068
1069//=============================================================================================================
1070
1072{
1073 if(value <= 0) {
1074 m_iDistanceTimerSpacer = 1000;
1075 } else {
1076 m_iDistanceTimerSpacer = value;
1077 }
1078}
1079
1080//=============================================================================================================
1081
1083{
1084 m_iDetectedTriggers = 0;
1085}
1086
1087//=============================================================================================================
1088
1089void RtFiffRawViewModel::markChBad(QModelIndexList chlist, bool status)
1090{
1091 QList<FiffChInfo> chInfolist = m_pFiffInfo->chs;
1092
1093 for(int i = 0; i < chlist.size(); ++i) {
1094 if(status) {
1095 if(!m_pFiffInfo->bads.contains(chInfolist[chlist[i].row()].ch_name))
1096 m_pFiffInfo->bads.append(chInfolist[chlist[i].row()].ch_name);
1097 } else {
1098 if(m_pFiffInfo->bads.contains(chInfolist[chlist[i].row()].ch_name)) {
1099 int index = m_pFiffInfo->bads.indexOf(chInfolist[chlist[i].row()].ch_name);
1100 m_pFiffInfo->bads.removeAt(index);
1101 }
1102 }
1103
1104 emit dataChanged(chlist[i],chlist[i]);
1105 }
1106
1107 //Update indeices of bad channels (this vector is needed when creating new ssp operators)
1108 QStringList emptyExclude;
1109 m_vecBadIdcs = FiffInfoBase::pick_channels(m_pFiffInfo->ch_names, m_pFiffInfo->bads, emptyExclude);
1110}
1111
1112//=============================================================================================================
1113
1114void RtFiffRawViewModel::doFilterPerChannelRTMSA(QPair<QList<FilterKernel>,QPair<int,RowVectorXd> > &channelDataTime)
1115{
1116 for(int i = 0; i < channelDataTime.first.size(); ++i) {
1117 //channelDataTime.second.second = channelDataTime.first.at(i).applyConvFilter(channelDataTime.second.second, true);
1118 channelDataTime.first[i].applyFftFilter(channelDataTime.second.second, true); //FFT Convolution for rt is not suitable. FFT make the signal filtering non causal.
1119 }
1120}
1121
1122//=============================================================================================================
1123
1124void RtFiffRawViewModel::filterDataBlock()
1125{
1126 //std::cout<<"START RtFiffRawViewModel::filterDataBlock"<<std::endl;
1127
1128 if(m_filterKernel.isEmpty() || !m_bPerformFiltering) {
1129 return;
1130 }
1131
1132 //Create temporary filters with higher fft length because we are going to filter all available data at once for one time
1133 QList<FilterKernel> tempFilterList;
1134
1135 int fftLength = m_matDataRaw.row(0).cols() + 4 * m_iMaxFilterLength;
1136 int exp = ceil(MNEMath::log2(fftLength));
1137 fftLength = pow(2, exp) < 512 ? 512 : pow(2, exp);
1138
1139 for(int i = 0; i<m_filterKernel.size(); ++i) {
1140 FilterKernel tempFilter(m_filterKernel.at(i).getName(),
1141 FilterKernel::m_filterTypes.indexOf(m_filterKernel.at(i).getFilterType()),
1142 m_filterKernel.at(i).getFilterOrder(),
1143 m_filterKernel.at(i).getCenterFrequency(),
1144 m_filterKernel.at(i).getBandwidth(),
1145 m_filterKernel.at(i).getParksWidth(),
1146 m_filterKernel.at(i).getSamplingFrequency(),
1147 FilterKernel::m_designMethods.indexOf(m_filterKernel.at(i).getDesignMethod()));
1148
1149 tempFilterList.append(tempFilter);
1150 }
1151
1152 //Generate QList structure which can be handled by the QConcurrent framework
1153 QList<QPair<QList<FilterKernel>,QPair<int,RowVectorXd> > > timeData;
1154 QList<int> notFilterChannelIndex;
1155
1156 //Also append mirrored data in front and back to get rid of edge effects
1157 for(qint32 i=0; i<m_matDataRaw.rows(); ++i) {
1158 if(m_filterChannelList.contains(m_pFiffInfo->chs.at(i).ch_name)) {
1159 RowVectorXd datTemp(m_matDataRaw.row(i).cols() + 2 * m_iMaxFilterLength);
1160 datTemp << m_matDataRaw.row(i).head(m_iMaxFilterLength).reverse(), m_matDataRaw.row(i), m_matDataRaw.row(i).tail(m_iMaxFilterLength).reverse();
1161 timeData.append(QPair<QList<FilterKernel>,QPair<int,RowVectorXd> >(tempFilterList,QPair<int,RowVectorXd>(i,datTemp)));
1162 } else {
1163 notFilterChannelIndex.append(i);
1164 }
1165 }
1166
1167 //Do the concurrent filtering
1168 if(!timeData.isEmpty()) {
1169 QFuture<void> future = QtConcurrent::map(timeData,
1170 doFilterPerChannelRTMSA);
1171
1172 future.waitForFinished();
1173
1174 for(int r = 0; r < timeData.size(); ++r) {
1175 m_matDataFiltered.row(timeData.at(r).second.first) = timeData.at(r).second.second.segment(m_iMaxFilterLength+m_iMaxFilterLength/2, m_matDataRaw.cols());
1176 m_matOverlap.row(timeData.at(r).second.first) = timeData.at(r).second.second.tail(m_iMaxFilterLength);
1177 }
1178 }
1179
1180 //Fill filtered data with raw data if the channel was not filtered
1181 for(int i = 0; i < notFilterChannelIndex.size(); ++i) {
1182 m_matDataFiltered.row(notFilterChannelIndex.at(i)) = m_matDataRaw.row(notFilterChannelIndex.at(i));
1183 }
1184
1185 if(!m_bIsFreezed) {
1186 m_vecLastBlockFirstValuesFiltered = m_matDataFiltered.col(0);
1187 }
1188
1189 //std::cout<<"END RtFiffRawViewModel::filterDataBlock"<<std::endl;
1190}
1191
1192//=============================================================================================================
1193
1194void RtFiffRawViewModel::filterDataBlock(const MatrixXd &data, int iDataIndex)
1195{
1196 //std::cout<<"START RtFiffRawViewModel::filterDataBlock"<<std::endl;
1197
1198 if(iDataIndex >= m_matDataFiltered.cols() || data.cols() < m_iMaxFilterLength) {
1199 return;
1200 }
1201
1202 //Generate QList structure which can be handled by the QConcurrent framework
1203 QList<QPair<QList<FilterKernel>,QPair<int,RowVectorXd> > > timeData;
1204 QList<int> notFilterChannelIndex;
1205
1206 for(qint32 i = 0; i < data.rows(); ++i) {
1207 if(m_filterChannelList.contains(m_pFiffInfo->chs.at(i).ch_name)) {
1208 timeData.append(QPair<QList<FilterKernel>,QPair<int,RowVectorXd> >(m_filterKernel,QPair<int,RowVectorXd>(i,data.row(i))));
1209 } else {
1210 notFilterChannelIndex.append(i);
1211 }
1212 }
1213
1214 //Do the concurrent filtering
1215 if(!timeData.isEmpty()) {
1216 QFuture<void> future = QtConcurrent::map(timeData,
1217 doFilterPerChannelRTMSA);
1218
1219 future.waitForFinished();
1220
1221 //Do the overlap add method and store in m_matDataFiltered
1222 int iFilterDelay = m_iMaxFilterLength/2;
1223 int iFilteredNumberCols = timeData.at(0).second.second.cols();
1224
1225 for(int r = 0; r<timeData.size(); ++r) {
1226 if(iDataIndex+2*data.cols() > m_matDataRaw.cols()) {
1227 //Handle last data block
1228 //std::cout<<"Handle last data block"<<std::endl;
1229
1230 if(m_bDrawFilterFront) {
1231 //Get the currently filtered data. This data has a delay of filterLength/2 in front and back.
1232 RowVectorXd tempData = timeData.at(r).second.second;
1233
1234 //Perform the actual overlap add by adding the last filterlength data to the newly filtered one
1235 tempData.head(m_iMaxFilterLength) += m_matOverlap.row(timeData.at(r).second.first);
1236
1237 //Write the newly calulated filtered data to the filter data matrix. Keep in mind that the current block also effect last part of the last block (begin at dataIndex-iFilterDelay).
1238 int start = iDataIndex-iFilterDelay < 0 ? 0 : iDataIndex-iFilterDelay;
1239 m_matDataFiltered.row(timeData.at(r).second.first).segment(start,iFilteredNumberCols-m_iMaxFilterLength) = tempData.head(iFilteredNumberCols-m_iMaxFilterLength);
1240 } else {
1241 //Perform this else case everytime the filter was changed. Do not begin to plot from dataIndex-iFilterDelay because the impsulse response and m_matOverlap do not match with the new filter anymore.
1242 m_matDataFiltered.row(timeData.at(r).second.first).segment(iDataIndex-iFilterDelay,m_iMaxFilterLength) = timeData.at(r).second.second.segment(m_iMaxFilterLength,m_iMaxFilterLength);
1243 m_matDataFiltered.row(timeData.at(r).second.first).segment(iDataIndex+iFilterDelay,iFilteredNumberCols-2*m_iMaxFilterLength) = timeData.at(r).second.second.segment(m_iMaxFilterLength,iFilteredNumberCols-2*m_iMaxFilterLength);
1244 }
1245
1246 //Refresh the m_matOverlap with the new calculated filtered data.
1247 m_matOverlap.row(timeData.at(r).second.first) = timeData.at(r).second.second.tail(m_iMaxFilterLength);
1248 } else if(iDataIndex == 0) {
1249 //Handle first data block
1250 //std::cout<<"Handle first data block"<<std::endl;
1251
1252 if(m_bDrawFilterFront) {
1253 //Get the currently filtered data. This data has a delay of filterLength/2 in front and back.
1254 RowVectorXd tempData = timeData.at(r).second.second;
1255
1256 //Add newly calculate data to the tail of the current filter data matrix
1257 m_matDataFiltered.row(timeData.at(r).second.first).segment(m_matDataFiltered.cols()-iFilterDelay-m_iResidual, iFilterDelay) = tempData.head(iFilterDelay) + m_matOverlap.row(timeData.at(r).second.first).head(iFilterDelay);
1258
1259 //Perform the actual overlap add by adding the last filterlength data to the newly filtered one
1260 tempData.head(m_iMaxFilterLength) += m_matOverlap.row(timeData.at(r).second.first);
1261 m_matDataFiltered.row(timeData.at(r).second.first).head(iFilteredNumberCols-m_iMaxFilterLength-iFilterDelay) = tempData.segment(iFilterDelay,iFilteredNumberCols-m_iMaxFilterLength-iFilterDelay);
1262
1263 //Copy residual data from the front to the back. The residual is != 0 if the chosen block size cannot be evenly fit into the matrix size
1264 m_matDataFiltered.row(timeData.at(r).second.first).tail(m_iResidual) = m_matDataFiltered.row(timeData.at(r).second.first).head(m_iResidual);
1265 } else {
1266 //Perform this else case everytime the filter was changed. Do not begin to plot from dataIndex-iFilterDelay because the impsulse response and m_matOverlap do not match with the new filter anymore.
1267 m_matDataFiltered.row(timeData.at(r).second.first).head(m_iMaxFilterLength) = timeData.at(r).second.second.segment(m_iMaxFilterLength,m_iMaxFilterLength);
1268 m_matDataFiltered.row(timeData.at(r).second.first).segment(iFilterDelay,iFilteredNumberCols-2*m_iMaxFilterLength) = timeData.at(r).second.second.segment(m_iMaxFilterLength,iFilteredNumberCols-2*m_iMaxFilterLength);
1269 }
1270
1271 //Refresh the m_matOverlap with the new calculated filtered data.
1272 m_matOverlap.row(timeData.at(r).second.first) = timeData.at(r).second.second.tail(m_iMaxFilterLength);
1273 } else {
1274 //Handle middle data blocks
1275 //std::cout<<"Handle middle data block"<<std::endl;
1276
1277 if(m_bDrawFilterFront) {
1278 //Get the currently filtered data. This data has a delay of filterLength/2 in front and back.
1279 RowVectorXd tempData = timeData.at(r).second.second;
1280
1281 //Perform the actual overlap add by adding the last filterlength data to the newly filtered one
1282 tempData.head(m_iMaxFilterLength) += m_matOverlap.row(timeData.at(r).second.first);
1283
1284 //Write the newly calulated filtered data to the filter data matrix. Keep in mind that the current block also effect last part of the last block (begin at dataIndex-iFilterDelay).
1285 m_matDataFiltered.row(timeData.at(r).second.first).segment(iDataIndex-iFilterDelay,iFilteredNumberCols-m_iMaxFilterLength) = tempData.head(iFilteredNumberCols-m_iMaxFilterLength);
1286 } else {
1287 //Perform this else case everytime the filter was changed. Do not begin to plot from dataIndex-iFilterDelay because the impsulse response and m_matOverlap do not match with the new filter anymore.
1288 m_matDataFiltered.row(timeData.at(r).second.first).segment(iDataIndex-iFilterDelay,m_iMaxFilterLength).setZero();// = timeData.at(r).second.second.segment(m_iMaxFilterLength,m_iMaxFilterLength);
1289 m_matDataFiltered.row(timeData.at(r).second.first).segment(iDataIndex+iFilterDelay,iFilteredNumberCols-2*m_iMaxFilterLength) = timeData.at(r).second.second.segment(m_iMaxFilterLength,iFilteredNumberCols-2*m_iMaxFilterLength);
1290 }
1291
1292 //Refresh the m_matOverlap with the new calculated filtered data.
1293 m_matOverlap.row(timeData.at(r).second.first) = timeData.at(r).second.second.tail(m_iMaxFilterLength);
1294 }
1295 }
1296 }
1297
1298 m_bDrawFilterFront = true;
1299
1300 //Fill filtered data with raw data if the channel was not filtered
1301 for(int i = 0; i < notFilterChannelIndex.size(); ++i) {
1302 m_matDataFiltered.row(notFilterChannelIndex.at(i)).segment(iDataIndex,data.row(notFilterChannelIndex.at(i)).cols()) = data.row(notFilterChannelIndex.at(i));
1303 }
1304
1305 //std::cout<<"END RtFiffRawViewModel::filterDataBlock"<<std::endl;
1306}
1307
1308//=============================================================================================================
1309
1310void RtFiffRawViewModel::clearModel()
1311{
1312 beginResetModel();
1313
1314 m_matDataRaw.setZero();
1315 m_matDataFiltered.setZero();
1316 m_matDataRawFreeze.setZero();
1317 m_matDataFilteredFreeze.setZero();
1318 m_vecLastBlockFirstValuesFiltered.setZero();
1319 m_vecLastBlockFirstValuesRaw.setZero();
1320 m_matOverlap.setZero();
1321
1322 endResetModel();
1323}
1324
1325//=============================================================================================================
1326
1328{
1329 double dMaxValue;
1330 qint32 kind = getKind(row);
1331
1332 switch(kind) {
1333 case FIFFV_MEG_CH: {
1334 dMaxValue = 1e-11f;
1335 qint32 unit = getUnit(row);
1336 if(unit == FIFF_UNIT_T_M) { //gradiometers
1337 dMaxValue = 1e-10f;
1338 if(getScaling().contains(FIFF_UNIT_T_M))
1339 dMaxValue = getScaling()[FIFF_UNIT_T_M];
1340 }
1341 else if(unit == FIFF_UNIT_T) //magnetometers
1342 {
1343 dMaxValue = 1e-11f;
1344 if(getScaling().contains(FIFF_UNIT_T))
1345 dMaxValue = getScaling()[FIFF_UNIT_T];
1346 }
1347 break;
1348 }
1349
1350 case FIFFV_REF_MEG_CH: {
1351 dMaxValue = 1e-11f;
1352 if( getScaling().contains(FIFF_UNIT_T))
1353 dMaxValue = getScaling()[FIFF_UNIT_T];
1354 break;
1355 }
1356 case FIFFV_EEG_CH: {
1357 dMaxValue = 1e-4f;
1358 if( getScaling().contains(FIFFV_EEG_CH))
1359 dMaxValue = getScaling()[FIFFV_EEG_CH];
1360 break;
1361 }
1362 case FIFFV_EOG_CH: {
1363 dMaxValue = 1e-3f;
1364 if( getScaling().contains(FIFFV_EOG_CH))
1365 dMaxValue = getScaling()[FIFFV_EOG_CH];
1366 break;
1367 }
1368 case FIFFV_STIM_CH: {
1369 dMaxValue = 5;
1370 if( getScaling().contains(FIFFV_STIM_CH))
1371 dMaxValue = getScaling()[FIFFV_STIM_CH];
1372 break;
1373 }
1374 case FIFFV_MISC_CH: {
1375 dMaxValue = 1e-3f;
1376 if( getScaling().contains(FIFFV_MISC_CH))
1377 dMaxValue = getScaling()[FIFFV_MISC_CH];
1378 break;
1379 }
1380 default :
1381 dMaxValue = 1e-9f;
1382 break;
1383 }
1384
1385 return dMaxValue;
1386}
1387
1388//=============================================================================================================
1389
1391{
1392 m_EventManager.addEvent(iSample);
1393}
1394
1395//=============================================================================================================
1396
1397std::unique_ptr<std::vector<EVENTSLIB::Event> > RtFiffRawViewModel::getEventsToDisplay(int iBegin, int iEnd) const
1398{
1399 return m_EventManager.getEventsBetween(iBegin, iEnd);
1400}
Declaration of the Sphara class.
DetectTrigger declarations.
Declaration of the RtFiffRawViewModel Class.
FiffInfo class declaration.
#define FIFFV_EOG_CH
#define FIFFV_EEG_CH
#define FIFF_UNIT_NONE
#define FIFFV_REF_MEG_CH
#define FIFFV_MISC_CH
#define FIFFV_MEG_CH
#define FIFFV_STIM_CH
#define FIFF_UNIT_T
#define FIFFV_EMG_CH
#define FIFFV_ECG_CH
#define FIFF_UNIT_T_M
#define FIFFV_COIL_NONE
Old fiff_type declarations - replace them.
IOUtils class declaration.
MNEMath class declaration.
FIFF file I/O and data structures (raw, epochs, evoked, covariance, forward).
qint32 fiff_int_t
Definition fiff_types.h:89
2-D display widgets and visualisation helpers (charts, topography, colour maps).
QPair< const double *, qint32 > RowVectorPair
Real-time signal processing (filtering, averaging, HPI fitting, noise reduction).
Eigen::MatrixXd filterData(const Eigen::MatrixXd &matData, int type, double dCenterfreq, double dBandwidth, double dTransition, double dSFreq, int iOrder=1024, int designMethod=FilterKernel::m_designMethods.indexOf(FilterParameter("Cosine")), const Eigen::RowVectorXi &vecPicks=Eigen::RowVectorXi(), bool bUseThreads=true, bool bKeepOverhead=false)
QMap< int, QList< QPair< int, double > > > detectTriggerFlanksMax(const Eigen::MatrixXd &data, const QList< int > &lTriggerChannels, int iOffsetIndex, double dThreshold, bool bRemoveOffset, int iBurstLengthSamp=100)
Eigen::MatrixXd makeSpharaProjector(const Eigen::MatrixXd &matBaseFct, const Eigen::VectorXi &vecIndices, int iOperatorDim, int iNBaseFct, int iSkip=0)
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
Definition buildinfo.h:45
const QMap< qint32, float > & getScaling() const
void setBackgroundColor(const QColor &color)
void selectRows(const QList< qint32 > &selection)
void newSelection(const QList< qint32 > &selection)
FIFFLIB::fiff_int_t getKind(qint32 row) const
QSharedPointer< RtFiffRawViewModel > SPtr
void setSamplingInfo(float sps, int T, bool bSetZero=false)
void markChBad(QModelIndex ch, bool status)
RtFiffRawViewModel(QObject *parent=0)
void createFilterChannelList(QStringList channelNames)
std::unique_ptr< std::vector< EVENTSLIB::Event > > getEventsToDisplay(int iBegin, int iEnd) const
void setFilterChannelType(const QString &channelType)
void setFiffInfo(QSharedPointer< FIFFLIB::FiffInfo > &p_pFiffInfo)
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const
void toggleFreeze(const QModelIndex &index)
void hideRows(const QList< qint32 > &selection)
void updateSpharaOptions(const QString &sSytemType, int nBaseFctsFirst, int nBaseFctsSecond)
void setScaling(const QMap< qint32, float > &p_qMapChScaling)
virtual int columnCount(const QModelIndex &parent=QModelIndex()) const
FIFFLIB::fiff_int_t getCoil(qint32 row) const
virtual QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const
void triggerDetected(int numberDetectedTriggers, const QMap< int, QList< QPair< int, double > > > &mapDetectedTriggers)
FIFFLIB::fiff_int_t getUnit(qint32 row) const
void triggerInfoChanged(const QMap< double, QColor > &colorMap, bool active, QString triggerCh, double threshold)
void setFilter(QList< RTPROCESSINGLIB::FilterKernel > filterData)
void updateProjection(const QList< FIFFLIB::FiffProj > &projs)
virtual QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
void addData(const QList< Eigen::MatrixXd > &data)
double getMaxValueFromRawViewModel(int row) const
Central registry that creates, stores, queries, and groups Event objects across one or more data file...
CTF software compensation data.
FiffNamedMatrix::SDPtr data
FIFF measurement file information.
Definition fiff_info.h:85
static Eigen::RowVectorXi pick_channels(const QStringList &ch_names, const QStringList &include=defaultQStringList, const QStringList &exclude=defaultQStringList)
static QVector< FilterParameter > m_designMethods
static QVector< FilterParameter > m_filterTypes
static bool read_eigen_matrix(Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > &out, const QString &path)
Definition ioutils.h:471
static double log2(const T d)
Definition mnemath.h:607