51 #include <QtCore/QtPlugin>
52 #include <QtCore/QTextStream>
71 , m_qStringResourcePath(qApp->applicationDirPath()+
"/mne_x_plugins/resources/tmsi/")
72 , m_pRawMatrixBuffer_In(0)
76 m_pActionSetupProject =
new QAction(QIcon(
":/images/database.png"), tr(
"Setup project"),
this);
77 m_pActionSetupProject->setStatusTip(tr(
"Setup project"));
82 m_pActionStartRecording =
new QAction(QIcon(
":/images/record.png"), tr(
"Start recording data to fif file"),
this);
83 m_pActionStartRecording->setStatusTip(tr(
"Start recording data to fif file"));
88 m_pActionImpedance =
new QAction(QIcon(
":/images/impedances.png"), tr(
"Check impedance values"),
this);
89 m_pActionImpedance->setStatusTip(tr(
"Check impedance values"));
102 if(this->isRunning())
111 QSharedPointer<TMSI> pTMSIClone(
new TMSI());
125 m_iSamplingFreq = 1024;
126 m_iNumberOfChannels = 138;
127 m_iSamplesPerBlock = 16;
128 m_iTriggerInterval = 5000;
130 m_bUseChExponent =
true;
131 m_bUseUnitGain =
true;
132 m_bUseUnitOffset =
true;
133 m_bWriteToFile =
false;
134 m_bWriteDriverDebugToFile =
false;
135 m_bUseFiltering =
false;
137 m_bIsRunning =
false;
138 m_bBeepTrigger =
false;
139 m_bUseCommonAverage =
true;
140 m_bUseKeyboardTrigger =
false;
141 m_bCheckImpedances =
false;
146 m_sOutputFilePath = QString (
"%1Sequence_01/Subject_01/%2_%3_%4_EEG_001_raw.fif").arg(m_qStringResourcePath).arg(date.currentDate().year()).arg(date.currentDate().month()).arg(date.currentDate().day());
148 m_sElcFilePath = QString(
"./mne_x_plugins/resources/tmsi/loc_files/Lorenz-Duke128-28-11-2013.elc");
150 m_pFiffInfo = QSharedPointer<FiffInfo>(
new FiffInfo());
153 m_matOldMatrix = MatrixXf::Zero(m_iNumberOfChannels, m_iSamplesPerBlock);
173 m_pFiffInfo->clear();
178 m_pFiffInfo->nchan = m_iNumberOfChannels;
179 m_pFiffInfo->sfreq = m_iSamplingFreq;
180 m_pFiffInfo->highpass = (float)0.001;
181 m_pFiffInfo->lowpass = m_iSamplingFreq/2;
186 QVector< QVector<double> > elcLocation3D;
187 QVector< QVector<double> > elcLocation2D;
189 QStringList elcChannelNames;
192 qDebug() <<
"Error: Reading elc file.";
200 rotation_z = AngleAxisf((
float)M_PI/2, Vector3f::UnitZ());
201 QVector3D center_pos;
203 for(
int i = 0; i<elcLocation3D.size(); i++)
206 point << elcLocation3D[i][0], elcLocation3D[i][1] , elcLocation3D[i][2];
207 Vector3f point_rot = rotation_z * point;
212 elcLocation3D[i][0] = point_rot[0];
213 elcLocation3D[i][1] = point_rot[1];
214 elcLocation3D[i][2] = point_rot[2];
217 center_pos.setX(center_pos.x() + elcLocation3D[i][0]);
218 center_pos.setY(center_pos.y() + elcLocation3D[i][1]);
219 center_pos.setZ(center_pos.z() + elcLocation3D[i][2]);
222 center_pos.setX(center_pos.x()/elcLocation3D.size());
223 center_pos.setY(center_pos.y()/elcLocation3D.size());
224 center_pos.setZ(center_pos.z()/elcLocation3D.size());
229 QList<FiffDigPoint> digitizerInfo;
233 if(m_iNumberOfChannels>128)
234 numberEEGCh = 138 - (m_iNumberOfChannels-128);
236 numberEEGCh = m_iNumberOfChannels;
239 if(numberEEGCh > elcLocation3D.size())
241 qDebug()<<
"Warning: setUpFiffInfo() - Not enough positions read from the elc file. Filling missing channel names and positions with zeroes and 'unknown' strings.";
242 QVector<double> tempA(3, 0.0);
243 QVector<double> tempB(2, 0.0);
244 int size = numberEEGCh-elcLocation3D.size();
245 for(
int i = 0; i<size; i++)
247 elcLocation3D.push_back(tempA);
248 elcLocation2D.push_back(tempB);
249 elcChannelNames.append(QString(
"Unknown"));
255 int indexLE2 = elcChannelNames.indexOf(
"LE2");
256 digPoint.
kind = FIFFV_POINT_CARDINAL;
257 digPoint.
ident = FIFFV_POINT_LPA;
262 digPoint.
r[0] = elcLocation3D[indexLE2][0]*0.001;
263 digPoint.
r[1] = elcLocation3D[indexLE2][1]*0.001;
264 digPoint.
r[2] = (elcLocation3D[indexLE2][2]-10)*0.001;
265 digitizerInfo.push_back(digPoint);
268 cout<<
"Plugin TMSI - ERROR - LE2 not found. Check loaded layout."<<endl;
271 int indexZ1 = elcChannelNames.indexOf(
"Z1");
272 digPoint.
kind = FIFFV_POINT_CARDINAL;
273 digPoint.
ident = FIFFV_POINT_NASION;
278 digPoint.
r[0] = elcLocation3D[indexZ1][0]*0.001;
279 digPoint.
r[1] = elcLocation3D[indexZ1][1]*0.001;
280 digPoint.
r[2] = (elcLocation3D[indexZ1][2]-60)*0.001;
281 digitizerInfo.push_back(digPoint);
284 cout<<
"Plugin TMSI - ERROR - Z1 not found. Check loaded layout."<<endl;
287 int indexRE2 = elcChannelNames.indexOf(
"RE2");
288 digPoint.
kind = FIFFV_POINT_CARDINAL;
289 digPoint.
ident = FIFFV_POINT_RPA;
294 digPoint.
r[0] = elcLocation3D[indexRE2][0]*0.001;
295 digPoint.
r[1] = elcLocation3D[indexRE2][1]*0.001;
296 digPoint.
r[2] = (elcLocation3D[indexRE2][2]-10)*0.001;
297 digitizerInfo.push_back(digPoint);
300 cout<<
"Plugin TMSI - ERROR - RE2 not found. Check loaded layout."<<endl;
303 for(
int i=0; i<numberEEGCh; i++)
306 digPoint.
kind = FIFFV_POINT_EEG;
310 digPoint.
r[0] = elcLocation3D[i][0]*0.001;
311 digPoint.
r[1] = elcLocation3D[i][1]*0.001;
312 digPoint.
r[2] = elcLocation3D[i][2]*0.001;
313 digitizerInfo.push_back(digPoint);
317 m_pFiffInfo->dig = digitizerInfo;
322 QStringList QSLChNames;
323 m_pFiffInfo->chs.clear();
325 for(
int i=0; i<m_iNumberOfChannels; i++)
336 sChType = QString(
"EEG ");
338 sChType.append(
"00");
343 fChInfo.
ch_name = sChType.append(sChType.number(i));
346 fChInfo.
kind = FIFFV_EEG_CH;
358 fChInfo.
unit = FIFF_UNIT_V;
362 fChInfo.
eeg_loc(0,0) = elcLocation3D[i][0]*0.001;
363 fChInfo.
eeg_loc(1,0) = elcLocation3D[i][1]*0.001;
364 fChInfo.
eeg_loc(2,0) = elcLocation3D[i][2]*0.001;
367 fChInfo.
eeg_loc(0,1) = center_pos.x()*0.001;
368 fChInfo.
eeg_loc(1,1) = center_pos.y()*0.001;
369 fChInfo.
eeg_loc(2,1) = center_pos.z()*0.001;
372 fChInfo.
loc(0,0) = elcLocation3D[i][0]*0.001;
373 fChInfo.
loc(1,0) = elcLocation3D[i][1]*0.001;
374 fChInfo.
loc(2,0) = elcLocation3D[i][2]*0.001;
376 fChInfo.
loc(3,0) = center_pos.x()*0.001;
377 fChInfo.
loc(4,0) = center_pos.y()*0.001;
378 fChInfo.
loc(5,0) = center_pos.z()*0.001;
380 fChInfo.
loc(6,0) = 0;
381 fChInfo.
loc(7,0) = 1;
382 fChInfo.
loc(8,0) = 0;
384 fChInfo.
loc(9,0) = 0;
385 fChInfo.
loc(10,0) = 0;
386 fChInfo.
loc(11,0) = 1;
395 fChInfo.
kind = FIFFV_MISC_CH;
397 sChType = QString(
"BIPO ");
398 fChInfo.
ch_name = sChType.append(sChType.number(i-128));
405 fChInfo.
kind = FIFFV_MISC_CH;
407 sChType = QString(
"AUX ");
408 fChInfo.
ch_name = sChType.append(sChType.number(i-132));
415 fChInfo.
kind = FIFFV_STIM_CH;
417 sChType = QString(
"STI 014");
425 fChInfo.
kind = FIFFV_MISC_CH;
427 sChType = QString(
"TEST RAMP");
431 QSLChNames << sChType;
433 m_pFiffInfo->chs.append(fChInfo);
437 m_pFiffInfo->ch_names = QSLChNames;
442 m_pFiffInfo->dev_head_t.from = FIFFV_COORD_DEVICE;
443 m_pFiffInfo->dev_head_t.to = FIFFV_COORD_HEAD;
444 m_pFiffInfo->ctf_head_t.from = FIFFV_COORD_DEVICE;
445 m_pFiffInfo->ctf_head_t.to = FIFFV_COORD_HEAD;
450 m_pFiffInfo->projs.clear();
456 namedMatrix->ncol = numberEEGCh/3;
457 namedMatrix->nrow = 1;
458 namedMatrix->data = MatrixXd::Ones(1, namedMatrix->ncol);
461 for(
int i=0; i<namedMatrix->ncol; i++)
462 namedMatrix->col_names << QSLChNames.at(i);
464 proj.
data = namedMatrix;
465 proj.
desc = QString(
"PCA-v1");
466 m_pFiffInfo->projs.append(proj);
469 namedMatrix->col_names.clear();
470 for(
int i=0; i<namedMatrix->ncol; i++)
471 namedMatrix->col_names << QSLChNames.at(i+namedMatrix->ncol);
473 proj.
data = namedMatrix;
474 proj.
desc = QString(
"PCA-v2");
475 m_pFiffInfo->projs.append(proj);
478 namedMatrix->col_names.clear();
479 for(
int i=0; i<namedMatrix->ncol; i++)
480 namedMatrix->col_names << QSLChNames.at(i+(2*namedMatrix->ncol));
482 proj.
data = namedMatrix;
483 proj.
desc = QString(
"PCA-v3");
484 m_pFiffInfo->projs.append(proj);
493 if(this->isRunning())
497 m_qTimerTrigger.start();
503 m_pRMTSA_TMSI->data()->initFromFiffInfo(m_pFiffInfo);
504 m_pRMTSA_TMSI->data()->setMultiArraySize(m_iSamplesPerBlock);
505 m_pRMTSA_TMSI->data()->setSamplingRate(m_iSamplingFreq);
508 m_pRawMatrixBuffer_In = QSharedPointer<RawMatrixBuffer>(
new RawMatrixBuffer(8, m_iNumberOfChannels, m_iSamplesPerBlock));
510 m_pTMSIProducer->start(m_iNumberOfChannels,
516 m_bWriteDriverDebugToFile,
521 if(m_pTMSIProducer->isRunning())
526 if(m_bUseKeyboardTrigger && !m_bCheckImpedances)
528 m_tmsiManualAnnotationWidget->initGui();
529 m_tmsiManualAnnotationWidget->show();
538 qWarning() <<
"Plugin TMSI - ERROR - TMSIProducer thread could not be started - Either the device is turned off (check your OS device manager) or the driver DLL (TMSiSDK.dll / TMSiSDK32bit.dll) is not installed in the system32 / SysWOW64 directory" << endl;
549 m_pTMSIProducer->stop();
552 m_bIsRunning =
false;
555 m_pRawMatrixBuffer_In->releaseFromPop();
557 m_pRawMatrixBuffer_In->clear();
559 m_pRMTSA_TMSI->data()->clear();
561 m_tmsiManualAnnotationWidget->hide();
598 void TMSI::setKeyboardTriggerType(
int type)
601 m_iTriggerType =type;
615 if(m_pTMSIProducer->isRunning() && m_bCheckImpedances)
617 MatrixXf matValue = m_pRawMatrixBuffer_In->pop();
619 for(qint32 i = 0; i < matValue.cols(); ++i)
620 m_pTmsiImpedanceWidget->updateGraphicScene(matValue.col(i).cast<
double>());
624 if(m_pTMSIProducer->isRunning() && !m_bCheckImpedances)
626 MatrixXf matValue = m_pRawMatrixBuffer_In->pop();
629 if(m_bBeepTrigger && m_qTimerTrigger.elapsed() >= m_iTriggerInterval)
631 QtConcurrent::run(Beep, 450, 700);
633 matValue(136, m_iSamplesPerBlock-1) = 252;
634 m_qTimerTrigger.restart();
638 if(m_bUseKeyboardTrigger && m_iTriggerType!=0)
639 matValue(136, m_iSamplesPerBlock-1) = m_iTriggerType;
643 m_pOutfid->write_raw_buffer(matValue.cast<
double>(), m_cals);
648 MatrixXf temp = matValue;
650 matValue = matValue - m_matOldMatrix;
651 m_matOldMatrix = temp;
687 Matrix<complex<float>, 138, 16> freq;
689 for(qint32 i = 0; i < matValue.rows(); ++i)
690 fft.fwd(freq.row(i), matValue.row(i));
700 if(m_iNumberOfChannels>137)
702 for(
int i = 0; i<matValue.row(137).cols(); i++)
705 if(matValue.row(136)[i] == 254)
706 matValue.row(136)[i] = 4000;
709 if(matValue.row(136)[i] == 253)
710 matValue.row(136)[i] = 8000;
713 if(matValue.row(136)[i] == 252)
714 matValue.row(136)[i] = 2000;
719 m_pRMTSA_TMSI->data()->setValue(matValue.cast<
double>());
729 m_pOutfid->finish_writing_raw();
730 m_bWriteToFile =
false;
731 m_pTimerRecordingChange->stop();
732 m_pActionStartRecording->setIcon(QIcon(
":/images/record.png"));
746 if(m_pTmsiImpedanceWidget == NULL)
747 m_pTmsiImpedanceWidget = QSharedPointer<TMSIImpedanceWidget>(
new TMSIImpedanceWidget(
this));
749 if(!m_pTmsiImpedanceWidget->isVisible())
751 m_pTmsiImpedanceWidget->setWindowTitle(
"MNE-X - Measure impedances");
752 m_pTmsiImpedanceWidget->show();
753 m_pTmsiImpedanceWidget->raise();
756 m_pTmsiImpedanceWidget->initGraphicScene();
765 if(m_pTmsiSetupProjectWidget == NULL)
768 if(!m_pTmsiSetupProjectWidget->isVisible())
770 m_pTmsiSetupProjectWidget->setWindowTitle(
"TMSI EEG Connector - Setup project");
771 m_pTmsiSetupProjectWidget->initGui();
772 m_pTmsiSetupProjectWidget->show();
773 m_pTmsiSetupProjectWidget->raise();
784 m_pOutfid->finish_writing_raw();
785 m_bWriteToFile =
false;
786 m_pTimerRecordingChange->stop();
787 m_pActionStartRecording->setIcon(QIcon(
":/images/record.png"));
794 msgBox.setText(
"Start data acquisition first!");
802 msgBox.setText(
"FiffInfo missing!");
808 m_fileOut.setFileName(m_sOutputFilePath);
809 if(m_fileOut.exists())
812 msgBox.setText(
"The file you want to write already exists.");
813 msgBox.setInformativeText(
"Do you want to overwrite this file?");
814 msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
815 int ret = msgBox.exec();
816 if(ret == QMessageBox::No)
821 QStringList list = m_sOutputFilePath.split(
"/");
823 QString fileDir = list.join(
"/");
832 fiff_int_t first = 0;
833 m_pOutfid->write_int(FIFF_FIRST_SAMPLE, &first);
835 m_bWriteToFile =
true;
837 m_pTimerRecordingChange = QSharedPointer<QTimer>(
new QTimer);
839 m_pTimerRecordingChange->start(500);
848 if(m_iBlinkStatus == 0)
850 m_pActionStartRecording->setIcon(QIcon(
":/images/record.png"));
855 m_pActionStartRecording->setIcon(QIcon(
":/images/record_active.png"));
865 DWORD ftyp = GetFileAttributesA(dirName_in.c_str());
866 if (ftyp == INVALID_FILE_ATTRIBUTES)
869 if (ftyp & FILE_ATTRIBUTE_DIRECTORY)
The EEGProducer class provides a EEG data producer for a given sampling rate.
FIFF measurement file information.
void showImpedanceDialog()
OutputConnectorList m_outputConnectors
virtual QString getName() const
bool dirExists(const std::string &dirName_in)
Digitization point description.
QSharedDataPointer< FiffNamedMatrix > SDPtr
virtual IPlugin::PluginType getType() const
void addPluginAction(QAction *pAction)
FiffNamedMatrix::SDPtr data
static bool readAsaElcFile(QString path, QStringList &channelNames, QVector< QVector< double > > &location3D, QVector< QVector< double > > &location2D, QString &unit)
Contains the declaration of the TMSI class.
static FiffStream::SPtr start_writing_raw(QIODevice &p_IODevice, const FiffInfo &info, RowVectorXd &cals, MatrixXi sel=defaultMatrixXi)
void showStartRecording()
static QSharedPointer< PluginOutputData< T > > create(IPlugin *parent, const QString &name, const QString &descr)
void changeRecordingButton()
void showSetupProjectDialog()
Matrix< double, 3, 2, DontAlign > eeg_loc
Contains the declaration of the TMSIProducer class.
virtual QWidget * setupWidget()
virtual QSharedPointer< IPlugin > clone() const
Matrix< double, 12, 1, DontAlign > loc