MNE-CPP  beta 1.0
mne.cpp
1 //=============================================================================================================
36 //*************************************************************************************************************
37 //=============================================================================================================
38 // INCLUDES
39 //=============================================================================================================
40 
41 #include "mne.h"
42 
44 
45 
46 //*************************************************************************************************************
47 //=============================================================================================================
48 // QT INCLUDES
49 //=============================================================================================================
50 
51 #include <QtCore/QtPlugin>
52 #include <QtConcurrent>
53 #include <QDebug>
54 
55 
56 //*************************************************************************************************************
57 //=============================================================================================================
58 // USED NAMESPACES
59 //=============================================================================================================
60 
61 using namespace MNEPlugin;
62 using namespace FIFFLIB;
63 using namespace XMEASLIB;
64 
65 
66 //*************************************************************************************************************
67 //=============================================================================================================
68 // DEFINE MEMBER METHODS
69 //=============================================================================================================
70 
71 MNE::MNE()
72 : m_bIsRunning(false)
73 , m_bReceiveData(false)
74 , m_bProcessData(false)
75 , m_bFinishedClustering(false)
76 , m_qFileFwdSolution("./MNE-sample-data/MEG/sample/sample_audvis-meg-eeg-oct-6-fwd.fif")
77 , m_sAtlasDir("./MNE-sample-data/subjects/sample/label")
78 , m_sSurfaceDir("./MNE-sample-data/subjects/sample/surf")
79 , m_iNumAverages(10)
80 , m_iDownSample(4)
81 {
82 
83 }
84 
85 
86 //*************************************************************************************************************
87 
89 {
90  if(this->isRunning())
91  stop();
92 }
93 
94 
95 //*************************************************************************************************************
96 
97 QSharedPointer<IPlugin> MNE::clone() const
98 {
99  QSharedPointer<MNE> pMNEClone(new MNE());
100  return pMNEClone;
101 }
102 
103 
104 //*************************************************************************************************************
105 //=============================================================================================================
106 // Creating required display instances and set configurations
107 //=============================================================================================================
108 
109 void MNE::init()
110 {
111  // Inits
112  m_pFwd = MNEForwardSolution::SPtr(new MNEForwardSolution(m_qFileFwdSolution));
113  m_pAnnotationSet = AnnotationSet::SPtr(new AnnotationSet(m_sAtlasDir+"/lh.aparc.a2009s.annot", m_sAtlasDir+"/rh.aparc.a2009s.annot"));
114  m_pSurfaceSet = SurfaceSet::SPtr(new SurfaceSet(m_sSurfaceDir+"/lh.white", m_sSurfaceDir+"/rh.white"));
115 
116  // Input
117  m_pRTEInput = PluginInputData<RealTimeEvoked>::create(this, "MNE RTE In", "MNE real-time evoked input data");
118  connect(m_pRTEInput.data(), &PluginInputConnector::notify, this, &MNE::updateRTE, Qt::DirectConnection);
119  m_inputConnectors.append(m_pRTEInput);
120 
121  m_pRTCInput = PluginInputData<RealTimeCov>::create(this, "MNE RTC In", "MNE real-time covariance input data");
122  connect(m_pRTCInput.data(), &PluginInputConnector::notify, this, &MNE::updateRTC, Qt::DirectConnection);
123  m_inputConnectors.append(m_pRTCInput);
124 
125  // Output
126  m_pRTSEOutput = PluginOutputData<RealTimeSourceEstimate>::create(this, "MNE Out", "MNE output data");
127  m_outputConnectors.append(m_pRTSEOutput);
128  m_pRTSEOutput->data()->setName(this->getName());//Provide name to auto store widget settings
129 
130  m_pRTSEOutput->data()->setAnnotSet(m_pAnnotationSet);
131  m_pRTSEOutput->data()->setSurfSet(m_pSurfaceSet);
132 
133  // start clustering
134  QFuture<void> future = QtConcurrent::run(this, &MNE::doClustering);
135 
136 }
137 
138 
139 //*************************************************************************************************************
140 
141 void MNE::unload()
142 {
143 
144 }
145 
146 
147 //*************************************************************************************************************
148 
149 void MNE::calcFiffInfo()
150 {
151  QMutexLocker locker(&m_qMutex);
152  if(m_qListCovChNames.size() > 0 && m_pFiffInfoEvoked && m_pFiffInfoForward)
153  {
154  qDebug() << "Fiff Infos available";
155 
156  QStringList tmp_pick_ch_names;
157  foreach (const QString &ch, m_pFiffInfoForward->ch_names)
158  {
159  if(m_pFiffInfoEvoked->ch_names.contains(ch))
160  tmp_pick_ch_names << ch;
161  }
162 
163  m_qListPickChannels.clear();
164 
165  foreach (const QString &ch, tmp_pick_ch_names)
166  {
167  if(m_qListCovChNames.contains(ch))
168  m_qListPickChannels << ch;
169  }
170 
171  RowVectorXi sel = m_pFiffInfoEvoked->pick_channels(m_qListPickChannels);
172 
173  m_pFiffInfo = QSharedPointer<FiffInfo>(new FiffInfo(m_pFiffInfoEvoked->pick_info(sel)));
174  }
175 
176 }
177 
178 
179 //*************************************************************************************************************
180 
181 void MNE::doClustering()
182 {
183  emit clusteringStarted();
184 
185  m_qMutex.lock();
186  m_bFinishedClustering = false;
187  m_pClusteredFwd = MNEForwardSolution::SPtr(new MNEForwardSolution(m_pFwd->cluster_forward_solution(*m_pAnnotationSet.data(), 40)));
188  m_qMutex.unlock();
189 
190  finishedClustering();
191 }
192 
193 
194 //*************************************************************************************************************
195 
196 void MNE::finishedClustering()
197 {
198  m_qMutex.lock();
199  m_bFinishedClustering = true;
200  m_pFiffInfoForward = QSharedPointer<FiffInfoBase>(new FiffInfoBase(m_pClusteredFwd->info));
201  m_qMutex.unlock();
202 
203  emit clusteringFinished();
204 }
205 
206 
207 //*************************************************************************************************************
208 
209 bool MNE::start()
210 {
211  //Check if the thread is already or still running. This can happen if the start button is pressed immediately after the stop button was pressed. In this case the stopping process is not finished yet but the start process is initiated.
212  if(this->isRunning())
213  QThread::wait();
214 
215  if(m_bFinishedClustering)
216  {
217  m_bIsRunning = true;
218  QThread::start();
219  return true;
220  }
221  else
222  return false;
223 }
224 
225 
226 //*************************************************************************************************************
227 
228 bool MNE::stop()
229 {
230  m_bIsRunning = false;
231 
232  if(m_pRtInvOp->isRunning())
233  m_pRtInvOp->stop();
234 
235  if(m_bProcessData) // Only clear if buffers have been initialised
236  {
237  m_qVecFiffEvoked.clear();
238  m_qVecFiffCov.clear();
239  }
240 
241  m_qListCovChNames.clear();
242 
243  // Stop filling buffers with data from the inputs
244  m_bProcessData = false;
245 
246  m_bReceiveData = false;
247 
248  return true;
249 }
250 
251 
252 //*************************************************************************************************************
253 
254 IPlugin::PluginType MNE::getType() const
255 {
256  return _IAlgorithm;
257 }
258 
259 
260 //*************************************************************************************************************
261 
262 QString MNE::getName() const
263 {
264  return "MNE";
265 }
266 
267 
268 //*************************************************************************************************************
269 
270 QWidget* MNE::setupWidget()
271 {
272  MNESetupWidget* setupWidget = new MNESetupWidget(this);//widget is later distroyed by CentralWidget - so it has to be created everytime new
273 
274  if(!m_bFinishedClustering)
275  setupWidget->setClusteringState();
276 
277  connect(this, &MNE::clusteringStarted, setupWidget, &MNESetupWidget::setClusteringState);
278  connect(this, &MNE::clusteringFinished, setupWidget, &MNESetupWidget::setSetupState);
279 
280  return setupWidget;
281 }
282 
283 
284 //*************************************************************************************************************
285 
286 void MNE::updateRTC(XMEASLIB::NewMeasurement::SPtr pMeasurement)
287 {
288  QSharedPointer<RealTimeCov> pRTC = pMeasurement.dynamicCast<RealTimeCov>();
289 
290  //MEG
291  if(pRTC && m_bReceiveData)
292  {
293  //Fiff Information of the covariance
294  if(m_qListCovChNames.size() != pRTC->getValue()->names.size())
295  m_qListCovChNames = pRTC->getValue()->names;
296 
297  if(m_bProcessData)
298  {
299  m_qMutex.lock();
300  m_qVecFiffCov.push_back(pRTC->getValue()->pick_channels(m_qListPickChannels));
301  m_qMutex.unlock();
302  }
303  }
304 }
305 
306 
307 
308 //*************************************************************************************************************
309 
310 void MNE::updateRTE(XMEASLIB::NewMeasurement::SPtr pMeasurement)
311 {
312  QSharedPointer<RealTimeEvoked> pRTE = pMeasurement.dynamicCast<RealTimeEvoked>();
313 
314  QMutexLocker locker(&m_qMutex);
315  //MEG
316  if(pRTE && m_bReceiveData)
317  {
318  //Fiff Information of the evoked
319  if(!m_pFiffInfoEvoked)
320  m_pFiffInfoEvoked = QSharedPointer<FiffInfo>(new FiffInfo(pRTE->getValue()->info));
321 
322  if(m_bProcessData)
323  m_qVecFiffEvoked.push_back(pRTE->getValue()->pick_channels(m_qListPickChannels));
324  }
325 }
326 
327 
328 //*************************************************************************************************************
329 
330 void MNE::updateInvOp(MNEInverseOperator::SPtr p_pInvOp)
331 {
332  m_pInvOp = p_pInvOp;
333 
334  double snr = 3.0;
335  double lambda2 = 1.0 / pow(snr, 2); //ToDO estimate lambda using covariance
336 
337  QString method("dSPM"); //"MNE" | "dSPM" | "sLORETA"
338 
339  m_qMutex.lock();
340  m_pMinimumNorm = MinimumNorm::SPtr(new MinimumNorm(*m_pInvOp.data(), lambda2, method));
341  //
342  // Set up the inverse according to the parameters
343  //
344  m_pMinimumNorm->doInverseSetup(m_iNumAverages,false);
345  m_qMutex.unlock();
346 }
347 
348 
349 //*************************************************************************************************************
350 
351 void MNE::run()
352 {
353  //
354  // start receiving data
355  //
356  m_qMutex.lock();
357  m_bReceiveData = true;
358  m_qMutex.unlock();
359 
360  //
361  // Read Fiff Info
362  //
363  while(true)
364  {
365  {
366  QMutexLocker locker(&m_qMutex);
367  if(m_pFiffInfo)
368  break;
369  }
370  calcFiffInfo();
371  msleep(10);// Wait for fiff Info
372  }
373 
374  //
375  // Init Real-Time inverse estimator
376  //
377  m_pRtInvOp = RtInvOp::SPtr(new RtInvOp(m_pFiffInfo, m_pClusteredFwd));
378  connect(m_pRtInvOp.data(), &RtInvOp::invOperatorCalculated, this, &MNE::updateInvOp);
379 
380  m_pMinimumNorm.reset();
381 
382  //
383  // Start the rt helpers
384  //
385  m_pRtInvOp->start();
386 
387  //
388  // start processing data
389  //
390  m_bProcessData = true;
391 
392  qint32 skip_count = 0;
393 
394  while(m_bIsRunning)
395  {
396  m_qMutex.lock();
397  qint32 t_covSize = m_qVecFiffCov.size();
398  m_qMutex.unlock();
399  if(t_covSize > 0)
400  {
401  m_qMutex.lock();
402  m_pRtInvOp->appendNoiseCov(m_qVecFiffCov[0]);
403  m_qVecFiffCov.pop_front();
404  m_qMutex.unlock();
405  }
406 
407  m_qMutex.lock();
408  qint32 t_evokedSize = m_qVecFiffEvoked.size();
409  m_qMutex.unlock();
410  if(t_evokedSize > 0)
411  {
412  if(m_pMinimumNorm && ((skip_count % 4) == 0))
413  {
414  m_qMutex.lock();
415  FiffEvoked t_fiffEvoked = m_qVecFiffEvoked[0];
416  m_qVecFiffEvoked.pop_front();
417  m_qMutex.unlock();
418 
419  float tmin = ((float)t_fiffEvoked.first) / t_fiffEvoked.info.sfreq;
420  float tstep = 1/t_fiffEvoked.info.sfreq;
421 
422  m_qMutex.lock();
423  MNESourceEstimate sourceEstimate = m_pMinimumNorm->calculateInverse(t_fiffEvoked.data, tmin, tstep);
424  m_qMutex.unlock();
425 
426  m_pRTSEOutput->data()->setValue(sourceEstimate);
427  }
428  else
429  {
430  m_qMutex.lock();
431  m_qVecFiffEvoked.pop_front();
432  m_qMutex.unlock();
433  }
434  ++skip_count;
435  }
436  }
437 }
The RealTimeMultiSampleArrayNew class is the base class of every RealTimeMultiSampleArrayNew Measurem...
Definition: realtimecov.h:88
FIFF measurement file information.
Definition: fiff_info.h:96
virtual ~MNE()
Definition: mne.h:112
The DummySetupWidget class provides the DummyToolbox configuration window.
Real-time inverse operator estimation.
Definition: rtinvop.h:106
QSharedPointer< MinimumNorm > SPtr
Definition: minimumnorm.h:85
QSharedPointer< MNEForwardSolution > SPtr
evoked data
Definition: fiff_evoked.h:91
virtual FiffCov::SPtr & getValue()
Definition: realtimecov.cpp:84
Contains the declaration of the MNESetupWidget class.
Annotation set.
Definition: annotationset.h:96
QSharedPointer< SurfaceSet > SPtr
Definition: surfaceset.h:86
PluginOutputConnector with specified Measurement.
Definition: fiff.h:98
QSharedPointer< NewMeasurement > SPtr
QSharedPointer< AnnotationSet > SPtr
Definition: annotationset.h:99
Minimum norm estimation.
Definition: minimumnorm.h:82
The RealTimeMultiSampleArrayNew class is the base class of every RealTimeMultiSampleArrayNew Measurem...
light measurement info
The MNE class provides wrapper functions to stay consistent with mne matlab toolbox.
Definition: mne.h:103
A hemisphere set of surfaces.
Definition: surfaceset.h:83
QSharedPointer< MNEInverseOperator > SPtr
QSharedPointer< RtInvOp > SPtr
Definition: rtinvop.h:110