v2.0.0
Loading...
Searching...
No Matches
rapmusic.cpp
Go to the documentation of this file.
1//=============================================================================================================
35
36//=============================================================================================================
37// INCLUDES
38//=============================================================================================================
39
40#include "rapmusic.h"
41
42#include <utils/mnemath.h>
43
44#ifdef _OPENMP
45#include <omp.h>
46#endif
47
48//=============================================================================================================
49// STL INCLUDES
50//=============================================================================================================
51
52#include <iostream>
53
54//=============================================================================================================
55// USED NAMESPACES
56//=============================================================================================================
57
58using namespace INVERSELIB;
59using namespace MNELIB;
60using namespace FIFFLIB;
61using namespace UTILSLIB;
62
63//=============================================================================================================
64// DEFINE MEMBER METHODS
65//=============================================================================================================
66
80
81//=============================================================================================================
82
83RapMusic::RapMusic(MNEForwardSolution& p_pFwd, bool p_bSparsed, int p_iN, double p_dThr)
84: m_iN(0)
85, m_dThreshold(0)
91, m_bIsInit(false)
93, m_fStcOverlap(-1)
94{
95 //Init
96 init(p_pFwd, p_bSparsed, p_iN, p_dThr);
97}
98
99//=============================================================================================================
100
106
107//=============================================================================================================
108
109bool RapMusic::init(MNEForwardSolution& p_pFwd, bool p_bSparsed, int p_iN, double p_dThr)
110{
111 //Get available thread number
112 #ifdef _OPENMP
113 std::cout << "OpenMP enabled" << std::endl;
114 m_iMaxNumThreads = omp_get_max_threads();
115 #else
116 std::cout << "OpenMP disabled (to enable it: VS2010->Project Properties->C/C++->Language, then modify OpenMP Support)" << std::endl;
118 #endif
119 std::cout << "Available Threats: " << m_iMaxNumThreads << std::endl << std::endl;
120
121 //Initialize RAP MUSIC
122 std::cout << "##### Initialization RAP MUSIC started ######\n\n";
123
124 m_iN = p_iN;
125 m_dThreshold = p_dThr;
126
127// //Grid check
128// if(p_pMatGrid != NULL)
129// {
130// if ( p_pMatGrid->rows() != p_pMatLeadField->cols() / 3 )
131// {
132// std::cout << "Grid does not fit to given Lead Field!\n";
133// return false;
134// }
135// }
136
137// m_pMatGrid = p_pMatGrid;
138
139 //Lead Field check
140 if ( p_pFwd.sol->data.cols() % 3 != 0 )
141 {
142 std::cout << "Gain matrix is not associated with a 3D grid!\n";
143 return false;
144 }
145
146 m_iNumGridPoints = p_pFwd.sol->data.cols()/3;
147
148 m_iNumChannels = p_pFwd.sol->data.rows();
149
150// m_pMappedMatLeadField = new Eigen::Map<MatrixXT>
151// ( p_pMatLeadField->data(),
152// p_pMatLeadField->rows(),
153// p_pMatLeadField->cols() );
154
155 m_ForwardSolution = p_pFwd;
156
157 //##### Calc lead field combination #####
158
159 std::cout << "Calculate gain matrix combinations. \n";
160
162
164
166
167 std::cout << "Gain matrix combinations calculated. \n\n";
168
169 //##### Calc lead field combination end #####
170
171 std::cout << "Number of grid points: " << m_iNumGridPoints << "\n\n";
172
173 std::cout << "Number of combinated points: " << m_iNumLeadFieldCombinations << "\n\n";
174
175 std::cout << "Number of sources to find: " << m_iN << "\n\n";
176
177 std::cout << "Threshold: " << m_dThreshold << "\n\n";
178
179 //Init end
180
181 std::cout << "##### Initialization RAP MUSIC completed ######\n\n\n";
182
183 Q_UNUSED(p_bSparsed);
184
185 m_bIsInit = true;
186
187 return m_bIsInit;
188}
189
190//=============================================================================================================
191
192const char* RapMusic::getName() const
193{
194 return "RAP MUSIC";
195}
196
197//=============================================================================================================
198
200{
201 return m_ForwardSolution.src;
202}
203
204//=============================================================================================================
205
206MNESourceEstimate RapMusic::calculateInverse(const FiffEvoked &p_fiffEvoked, bool pick_normal)
207{
208 Q_UNUSED(pick_normal);
209
210 MNESourceEstimate p_sourceEstimate;
211
212 if(p_fiffEvoked.data.rows() != m_iNumChannels)
213 {
214 std::cout << "Number of FiffEvoked channels (" << p_fiffEvoked.data.rows() << ") doesn't match the number of channels (" << m_iNumChannels << ") of the forward solution." << std::endl;
215 return p_sourceEstimate;
216 }
217// else
218// std::cout << "Number of FiffEvoked channels (" << p_fiffEvoked.data.rows() << ") matchs the number of channels (" << m_iNumChannels << ") of the forward solution." << std::endl;
219
220 //
221 // Rap MUSIC Source estimate
222 //
223 p_sourceEstimate.data = MatrixXd::Zero(m_ForwardSolution.nsource, p_fiffEvoked.data.cols());
224
225 //Results
226 p_sourceEstimate.vertices = VectorXi(m_ForwardSolution.src[0].vertno.size() + m_ForwardSolution.src[1].vertno.size());
227 p_sourceEstimate.vertices << m_ForwardSolution.src[0].vertno, m_ForwardSolution.src[1].vertno;
228
229 p_sourceEstimate.times = p_fiffEvoked.times;
230 p_sourceEstimate.tmin = p_fiffEvoked.times[0];
231 p_sourceEstimate.tstep = p_fiffEvoked.times[1] - p_fiffEvoked.times[0];
232
233 if(m_iSamplesStcWindow <= 3) //if samples per stc aren't set -> use full window
234 {
235 QList< DipolePair<double> > t_RapDipoles;
236 calculateInverse(p_fiffEvoked.data, t_RapDipoles);
237
238 for(qint32 i = 0; i < t_RapDipoles.size(); ++i)
239 {
240 double dip1 = sqrt( pow(t_RapDipoles[i].m_Dipole1.phi_x(),2) +
241 pow(t_RapDipoles[i].m_Dipole1.phi_y(),2) +
242 pow(t_RapDipoles[i].m_Dipole1.phi_z(),2) ) * t_RapDipoles[i].m_vCorrelation;
243
244 double dip2 = sqrt( pow(t_RapDipoles[i].m_Dipole2.phi_x(),2) +
245 pow(t_RapDipoles[i].m_Dipole2.phi_y(),2) +
246 pow(t_RapDipoles[i].m_Dipole2.phi_z(),2) ) * t_RapDipoles[i].m_vCorrelation;
247
248 RowVectorXd dip1Time = RowVectorXd::Constant(p_fiffEvoked.data.cols(), dip1);
249 RowVectorXd dip2Time = RowVectorXd::Constant(p_fiffEvoked.data.cols(), dip2);
250
251 p_sourceEstimate.data.block(t_RapDipoles[i].m_iIdx1, 0, 1, p_fiffEvoked.data.cols()) = dip1Time;
252 p_sourceEstimate.data.block(t_RapDipoles[i].m_iIdx2, 0, 1, p_fiffEvoked.data.cols()) = dip2Time;
253 }
254 }
255 else
256 {
257 bool first = true;
258 bool last = false;
259
260 qint32 t_iNumSensors = p_fiffEvoked.data.rows();
261 qint32 t_iNumSteps = p_fiffEvoked.data.cols();
262
263 qint32 t_iSamplesOverlap = (qint32)floor(((float)m_iSamplesStcWindow)*m_fStcOverlap);
264 qint32 t_iSamplesDiscard = t_iSamplesOverlap/2;
265
266 MatrixXd data = MatrixXd::Zero(t_iNumSensors, m_iSamplesStcWindow);
267
268 qint32 curSample = 0;
269 qint32 curResultSample = 0;
270 qint32 stcWindowSize = m_iSamplesStcWindow - 2*t_iSamplesDiscard;
271
272 while(!last)
273 {
274 QList< DipolePair<double> > t_RapDipoles;
275
276 //Data
277 if(curSample + m_iSamplesStcWindow >= t_iNumSteps) //last
278 {
279 last = true;
280 data = p_fiffEvoked.data.block(0, p_fiffEvoked.data.cols()-m_iSamplesStcWindow, t_iNumSensors, m_iSamplesStcWindow);
281 }
282 else
283 data = p_fiffEvoked.data.block(0, curSample, t_iNumSensors, m_iSamplesStcWindow);
284
285 curSample += (m_iSamplesStcWindow - t_iSamplesOverlap);
286 if(first)
287 curSample -= t_iSamplesDiscard; //shift on start t_iSamplesDiscard backwards
288
289 //Calculate
290 calculateInverse(data, t_RapDipoles);
291
292 //Assign Result
293 if(last)
294 stcWindowSize = p_sourceEstimate.data.cols() - curResultSample;
295
296 for(qint32 i = 0; i < t_RapDipoles.size(); ++i)
297 {
298 double dip1 = sqrt( pow(t_RapDipoles[i].m_Dipole1.phi_x(),2) +
299 pow(t_RapDipoles[i].m_Dipole1.phi_y(),2) +
300 pow(t_RapDipoles[i].m_Dipole1.phi_z(),2) ) * t_RapDipoles[i].m_vCorrelation;
301
302 double dip2 = sqrt( pow(t_RapDipoles[i].m_Dipole2.phi_x(),2) +
303 pow(t_RapDipoles[i].m_Dipole2.phi_y(),2) +
304 pow(t_RapDipoles[i].m_Dipole2.phi_z(),2) ) * t_RapDipoles[i].m_vCorrelation;
305
306 RowVectorXd dip1Time = RowVectorXd::Constant(stcWindowSize, dip1);
307 RowVectorXd dip2Time = RowVectorXd::Constant(stcWindowSize, dip2);
308
309 p_sourceEstimate.data.block(t_RapDipoles[i].m_iIdx1, curResultSample, 1, stcWindowSize) = dip1Time;
310 p_sourceEstimate.data.block(t_RapDipoles[i].m_iIdx2, curResultSample, 1, stcWindowSize) = dip2Time;
311
312 }
313
314 curResultSample += stcWindowSize;
315
316 if(first)
317 first = false;
318 }
319 }
320
321 return p_sourceEstimate;
322}
323
324//=============================================================================================================
325
326MNESourceEstimate RapMusic::calculateInverse(const MatrixXd &data, float tmin, float tstep, bool pick_normal) const
327{
328 Q_UNUSED(pick_normal);
329
330 MNESourceEstimate p_sourceEstimate;
331
332 if(data.rows() != m_iNumChannels)
333 {
334 std::cout << "Number of FiffEvoked channels (" << data.rows() << ") doesn't match the number of channels (" << m_iNumChannels << ") of the forward solution." << std::endl;
335 return p_sourceEstimate;
336 }
337// else
338// std::cout << "Number of FiffEvoked channels (" << data.rows() << ") matchs the number of channels (" << m_iNumChannels << ") of the forward solution." << std::endl;
339
340 //
341 // Rap MUSIC Source estimate
342 //
343 p_sourceEstimate.data = MatrixXd::Zero(m_ForwardSolution.nsource, data.cols());
344
345 //Results
346 p_sourceEstimate.vertices = VectorXi(m_ForwardSolution.src[0].vertno.size() + m_ForwardSolution.src[1].vertno.size());
347 p_sourceEstimate.vertices << m_ForwardSolution.src[0].vertno, m_ForwardSolution.src[1].vertno;
348
349 p_sourceEstimate.times = RowVectorXf::Zero(data.cols());
350 p_sourceEstimate.times[0] = tmin;
351 for(qint32 i = 1; i < p_sourceEstimate.times.size(); ++i)
352 p_sourceEstimate.times[i] = p_sourceEstimate.times[i-1] + tstep;
353 p_sourceEstimate.tmin = tmin;
354 p_sourceEstimate.tstep = tstep;
355
356 QList< DipolePair<double> > t_RapDipoles;
357 calculateInverse(data, t_RapDipoles);
358
359 for(qint32 i = 0; i < t_RapDipoles.size(); ++i)
360 {
361 double dip1 = sqrt( pow(t_RapDipoles[i].m_Dipole1.phi_x(),2) +
362 pow(t_RapDipoles[i].m_Dipole1.phi_y(),2) +
363 pow(t_RapDipoles[i].m_Dipole1.phi_z(),2) ) * t_RapDipoles[i].m_vCorrelation;
364
365 double dip2 = sqrt( pow(t_RapDipoles[i].m_Dipole2.phi_x(),2) +
366 pow(t_RapDipoles[i].m_Dipole2.phi_y(),2) +
367 pow(t_RapDipoles[i].m_Dipole2.phi_z(),2) ) * t_RapDipoles[i].m_vCorrelation;
368
369 RowVectorXd dip1Time = RowVectorXd::Constant(data.cols(), dip1);
370 RowVectorXd dip2Time = RowVectorXd::Constant(data.cols(), dip2);
371
372 p_sourceEstimate.data.block(t_RapDipoles[i].m_iIdx1, 0, 1, data.cols()) = dip1Time;
373 p_sourceEstimate.data.block(t_RapDipoles[i].m_iIdx2, 0, 1, data.cols()) = dip2Time;
374 }
375
376 return p_sourceEstimate;
377}
378
379//=============================================================================================================
380
381MNESourceEstimate RapMusic::calculateInverse(const MatrixXd& p_matMeasurement, QList< DipolePair<double> > &p_RapDipoles) const
382{
383 MNESourceEstimate p_SourceEstimate;
384
385 //if not initialized -> break
386 if(!m_bIsInit)
387 {
388 std::cout << "RAP MUSIC wasn't initialized!"; //ToDo: catch this earlier
389 return p_SourceEstimate; //false
390 }
391
392 //Test if data are correct
393 if(p_matMeasurement.rows() != m_iNumChannels)
394 {
395 std::cout << "Lead Field channels do not fit to number of measurement channels!"; //ToDo: catch this earlier
396 return p_SourceEstimate;
397 }
398
399 //Inits
400 //Stop the time for benchmark purpose
401 clock_t start, end;
402 start = clock();
403
404// //Map HPCMatrix to Eigen Matrix
405// Eigen::Map<MatrixXT>
406// t_MappedMatMeasurement( p_pMatMeasurement->data(),
407// p_pMatMeasurement->rows(),
408// p_pMatMeasurement->cols() );
409
410 //Calculate the signal subspace (t_pMatPhi_s)
411 MatrixXT* t_pMatPhi_s = NULL;//(m_iNumChannels, m_iN < t_r ? m_iN : t_r);
412 int t_r = calcPhi_s(/*(MatrixXT)*/p_matMeasurement, t_pMatPhi_s);
413
414 int t_iMaxSearch = m_iN < t_r ? m_iN : t_r; //The smallest of Rank and Iterations
415
416 if (t_r < m_iN)
417 {
418 std::cout << "Warning: Rank " << t_r << " of the measurement data is smaller than the " << m_iN;
419 std::cout << " sources to find." << std::endl;
420 std::cout << " Searching now for " << t_iMaxSearch << " correlated sources.";
421 std::cout << std::endl << std::endl;
422 }
423
424 //Create Orthogonal Projector
425 //OrthProj
427 t_matOrthProj.setIdentity();
428
429 //A_k_1
430 MatrixXT t_matA_k_1(m_iNumChannels, t_iMaxSearch);
431 t_matA_k_1.setZero();
432
433// if (m_pMatGrid != NULL)
434// {
435// if(p_pRapDipoles != NULL)
436// p_pRapDipoles->initRapDipoles(m_pMatGrid);
437// else
438// p_pRapDipoles = new RapDipoles<T>(m_pMatGrid);
439// }
440// else
441// {
442// if(p_pRapDipoles != NULL)
443// delete p_pRapDipoles;
444
445// p_pRapDipoles = new RapDipoles<T>();
446// }
447 p_RapDipoles.clear();
448
449 std::cout << "##### Calculation of RAP MUSIC started ######\n\n";
450
451 MatrixXT t_matProj_Phi_s(t_matOrthProj.rows(), t_pMatPhi_s->cols());
452 //new Version: Calculate projection before
453 MatrixXT t_matProj_LeadField(m_ForwardSolution.sol->data.rows(), m_ForwardSolution.sol->data.cols());
454
455 for(int r = 0; r < t_iMaxSearch ; ++r)
456 {
457 t_matProj_Phi_s = t_matOrthProj*(*t_pMatPhi_s);
458
459 //new Version: Calculating Projection before
460 t_matProj_LeadField = t_matOrthProj * m_ForwardSolution.sol->data;//Subtract the found sources from the current found source
461
462 //###First Option###
463 //Step 1: lt. Mosher 1998 -> Maybe tmp_Proj_Phi_S is already orthogonal -> so no SVD needed -> U_B = tmp_Proj_Phi_S;
464 Eigen::JacobiSVD< MatrixXT > t_svdProj_Phi_S(t_matProj_Phi_s, Eigen::ComputeThinU);
465 MatrixXT t_matU_B;
466 useFullRank(t_svdProj_Phi_S.matrixU(), t_svdProj_Phi_S.singularValues().asDiagonal(), t_matU_B);
467
468 //Inits
470 t_vecRoh.setZero();
471
472 //subcorr benchmark
473 //Stop the time
474 clock_t start_subcorr, end_subcorr;
475 start_subcorr = clock();
476
477 //Multithreading correlation calculation
478 #ifdef _OPENMP
479 #pragma omp parallel num_threads(m_iMaxNumThreads)
480 #endif
481 {
482 #ifdef _OPENMP
483 #pragma omp for
484 #endif
485 for(int i = 0; i < m_iNumLeadFieldCombinations; i++)
486 {
487 //new Version: calculate matrix multiplication before
488 //Create Lead Field combinations -> It would be better to use a pointer construction, to increase performance
489 MatrixX6T t_matProj_G(t_matProj_LeadField.rows(),6);
490
491 int idx1 = m_ppPairIdxCombinations[i]->x1;
492 int idx2 = m_ppPairIdxCombinations[i]->x2;
493
494 RapMusic::getGainMatrixPair(t_matProj_LeadField, t_matProj_G, idx1, idx2);
495
496 t_vecRoh(i) = RapMusic::subcorr(t_matProj_G, t_matU_B);//t_vecRoh holds the correlations roh_k
497 }
498 }
499
500// if(r==0)
501// {
502// std::fstream filestr;
503// std::stringstream filename;
504// filename << "Roh_gold.txt";
505//
506// filestr.open ( filename.str().c_str(), std::fstream::out);
507// for(int i = 0; i < m_iNumLeadFieldCombinations; ++i)
508// {
509// filestr << t_vecRoh(i) << "\n";
510// }
511// filestr.close();
512//
513// //exit(0);
514// }
515
516 //subcorr benchmark
517 end_subcorr = clock();
518
519 float t_fSubcorrElapsedTime = ( (float)(end_subcorr-start_subcorr) / (float)CLOCKS_PER_SEC ) * 1000.0f;
520 std::cout << "Time Elapsed: " << t_fSubcorrElapsedTime << " ms" << std::endl;
521
522 //Find the maximum of correlation - can't put this in the for loop because it's running in different threads.
523 double t_val_roh_k;
524
525 VectorXT::Index t_iMaxIdx;
526
527 t_val_roh_k = t_vecRoh.maxCoeff(&t_iMaxIdx);//p_vecCor = ^roh_k
528
529 //get positions in sparsed leadfield from index combinations;
530 int t_iIdx1 = m_ppPairIdxCombinations[t_iMaxIdx]->x1;
531 int t_iIdx2 = m_ppPairIdxCombinations[t_iMaxIdx]->x2;
532
533 // (Idx+1) because of MATLAB positions -> starting with 1 not with 0
534 std::cout << "Iteration: " << r+1 << " of " << t_iMaxSearch
535 << "; Correlation: " << t_val_roh_k<< "; Position (Idx+1): " << t_iIdx1+1 << " - " << t_iIdx2+1 <<"\n\n";
536
537 //Calculations with the max correlated dipole pair G_k_1 -> ToDo Obsolet when taking direkt Projected Lead Field
538 MatrixX6T t_matG_k_1(m_ForwardSolution.sol->data.rows(),6);
539 RapMusic::getGainMatrixPair(m_ForwardSolution.sol->data, t_matG_k_1, t_iIdx1, t_iIdx2);
540
541 MatrixX6T t_matProj_G_k_1(t_matOrthProj.rows(), t_matG_k_1.cols());
542 t_matProj_G_k_1 = t_matOrthProj * t_matG_k_1;//Subtract the found sources from the current found source
543// MatrixX6T t_matProj_G_k_1(t_matProj_LeadField.rows(), 6);
544// getLeadFieldPair(t_matProj_LeadField, t_matProj_G_k_1, t_iIdx1, t_iIdx2);
545
546 //Calculate source direction
547 //source direction (p_pMatPhi) for current source r (phi_k_1)
548 Vector6T t_vec_phi_k_1(6);
549 RapMusic::subcorr(t_matProj_G_k_1, t_matU_B, t_vec_phi_k_1);//Correlate the current source to calculate the direction
550
551 //Set return values
552 RapMusic::insertSource(t_iIdx1, t_iIdx2, t_vec_phi_k_1, t_val_roh_k, p_RapDipoles);
553
554 //Stop Searching when Correlation is smaller then the Threshold
555 if (t_val_roh_k < m_dThreshold)
556 {
557 std::cout << "Searching stopped, last correlation " << t_val_roh_k;
558 std::cout << " is smaller then the given threshold " << m_dThreshold << std::endl << std::endl;
559 break;
560 }
561
562 //Calculate A_k_1 = [a_theta_1..a_theta_k_1] matrix for subtraction of found source
563 RapMusic::calcA_k_1(t_matG_k_1, t_vec_phi_k_1, r, t_matA_k_1);
564
565 //Calculate new orthogonal Projector (Pi_k_1)
566 calcOrthProj(t_matA_k_1, t_matOrthProj);
567
568 //garbage collecting
569 //ToDo
570 }
571
572 std::cout << "##### Calculation of RAP MUSIC completed ######"<< std::endl << std::endl << std::endl;
573
574 end = clock();
575
576 float t_fElapsedTime = ( (float)(end-start) / (float)CLOCKS_PER_SEC ) * 1000.0f;
577 std::cout << "Total Time Elapsed: " << t_fElapsedTime << " ms" << std::endl << std::endl;
578
579 //garbage collecting
580 delete t_pMatPhi_s;
581
582 return p_SourceEstimate;
583}
584
585//=============================================================================================================
586
587int RapMusic::calcPhi_s(const MatrixXT& p_matMeasurement, MatrixXT* &p_pMatPhi_s) const
588{
589 //Calculate p_pMatPhi_s
590 MatrixXT t_matF;//t_matF = makeSquareMat(p_pMatMeasurement); //FF^T -> ToDo Check this
591 if (p_matMeasurement.cols() > p_matMeasurement.rows())
592 t_matF = makeSquareMat(p_matMeasurement); //FF^T
593 else
594 t_matF = MatrixXT(p_matMeasurement);
595
596 Eigen::JacobiSVD<MatrixXT> t_svdF(t_matF, Eigen::ComputeThinU);
597
598 int t_r = getRank(t_svdF.singularValues().asDiagonal());
599
600 int t_iCols = t_r;//t_r < m_iN ? m_iN : t_r;
601
602 if (p_pMatPhi_s != NULL)
603 delete p_pMatPhi_s;
604
605 //m_iNumChannels has to be equal to t_svdF.matrixU().rows()
606 p_pMatPhi_s = new MatrixXT(m_iNumChannels, t_iCols);
607
608 //assign the signal subspace
609 memcpy(p_pMatPhi_s->data(), t_svdF.matrixU().data(), sizeof(double) * m_iNumChannels * t_iCols);
610
611 return t_r;
612}
613
614//=============================================================================================================
615
616double RapMusic::subcorr(MatrixX6T& p_matProj_G, const MatrixXT& p_matU_B)
617{
618 //Orthogonalisierungstest wegen performance weggelassen -> ohne is es viel schneller
619
620 Matrix6T t_matSigma_A(6, 6);
621 Matrix6XT t_matU_A_T(6, p_matProj_G.rows()); //rows and cols are changed, because of CV_SVD_U_T
622
623 Eigen::JacobiSVD<MatrixXT> t_svdProj_G(p_matProj_G, Eigen::ComputeThinU);
624
625 t_matSigma_A = t_svdProj_G.singularValues().asDiagonal();
626 t_matU_A_T = t_svdProj_G.matrixU().transpose();
627
628 //lt. Mosher 1998 ToDo: Only Retain those Components of U_A and U_B that correspond to nonzero singular values
629 //for U_A and U_B the number of columns corresponds to their ranks
630 MatrixXT t_matU_A_T_full;
631 //reduce to rank only when directions aren't calculated, otherwise use the full t_matU_A_T
632
633 useFullRank(t_matU_A_T, t_matSigma_A, t_matU_A_T_full, IS_TRANSPOSED);//lt. Mosher 1998: Only Retain those Components of U_A that correspond to nonzero singular values -> for U_A the number of columns corresponds to their ranks
634
635 MatrixXT t_matCor(t_matU_A_T_full.rows(), p_matU_B.cols());
636
637 //Step 2: compute the subspace correlation
638 t_matCor = t_matU_A_T_full*p_matU_B;//lt. Mosher 1998: C = U_A^T * U_B
639
640 VectorXT t_vecSigma_C;
641
642 if (t_matCor.cols() > t_matCor.rows())
643 {
644 MatrixXT t_matCor_H(t_matCor.cols(), t_matCor.rows());
645 t_matCor_H = t_matCor.adjoint(); //for complex it has to be adjunct
646 //ToDo -> use instead adjointInPlace
647
648 Eigen::JacobiSVD<MatrixXT> t_svdCor_H(t_matCor_H);
649
650 t_vecSigma_C = t_svdCor_H.singularValues();
651 }
652 else
653 {
654 Eigen::JacobiSVD<MatrixXT> t_svdCor(t_matCor);
655
656 t_vecSigma_C = t_svdCor.singularValues();
657 }
658
659 //Step 3
660 double t_dRetSigma_C;
661 t_dRetSigma_C = t_vecSigma_C(0); //Take only the correlation of the first principal components
662
663 //garbage collecting
664 //ToDo
665
666 return t_dRetSigma_C;
667}
668
669//=============================================================================================================
670
671double RapMusic::subcorr(MatrixX6T& p_matProj_G, const MatrixXT& p_matU_B, Vector6T& p_vec_phi_k_1)
672{
673 //Orthogonalisierungstest wegen performance weggelassen -> ohne is es viel schneller
674
675 Matrix6T sigma_A(6, 6);
676 Matrix6XT U_A_T(6, p_matProj_G.rows()); //rows and cols are changed, because of CV_SVD_U_T
677 Matrix6T V_A(6, 6);
678
679 Eigen::JacobiSVD<MatrixXT> svdOfProj_G(p_matProj_G, Eigen::ComputeThinU | Eigen::ComputeThinV);
680
681 sigma_A = svdOfProj_G.singularValues().asDiagonal();
682 U_A_T = svdOfProj_G.matrixU().transpose();
683 V_A = svdOfProj_G.matrixV();
684
685 //lt. Mosher 1998 ToDo: Only Retain those Components of U_A and U_B that correspond to nonzero singular values
686 //for U_A and U_B the number of columns corresponds to their ranks
687 //-> reduce to rank only when directions aren't calculated, otherwise use the full U_A_T
688
689 Matrix6XT t_matCor(6, p_matU_B.cols());
690
691 //Step 2: compute the subspace correlation
692 t_matCor = U_A_T*p_matU_B;//lt. Mosher 1998: C = U_A^T * U_B
693
694 VectorXT sigma_C;
695
696 //Step 4
697 Matrix6XT U_C;
698
699 if (t_matCor.cols() > t_matCor.rows())
700 {
701 MatrixX6T Cor_H(t_matCor.cols(), 6);
702 Cor_H = t_matCor.adjoint(); //for complex it has to be adjunct
703
704 Eigen::JacobiSVD<MatrixXT> svdOfCor_H(Cor_H, Eigen::ComputeThinV);
705
706 U_C = svdOfCor_H.matrixV(); //because t_matCor Hermitesch U and V are exchanged
707 sigma_C = svdOfCor_H.singularValues();
708 }
709 else
710 {
711 Eigen::JacobiSVD<MatrixXT> svdOfCor(t_matCor, Eigen::ComputeThinU);
712
713 U_C = svdOfCor.matrixU();
714 sigma_C = svdOfCor.singularValues();
715 }
716
717 Matrix6T sigma_a_inv;
718 sigma_a_inv = sigma_A.inverse();
719
720 Matrix6XT X;
721 X = (V_A*sigma_a_inv)*U_C;//X = V_A*Sigma_A^-1*U_C
722
723 Vector6T X_max;//only for the maximum c - so instead of X->cols use 1
724 X_max = X.col(0);
725
726 double norm_X = 1/(X_max.norm());
727
728 //Multiply a scalar with an Array -> linear transform
729 p_vec_phi_k_1 = X_max*norm_X;//u1 = x1/||x1|| this is the orientation
730
731 //garbage collecting
732 //ToDo
733
734 //Step 3
735 double ret_sigma_C;
736 ret_sigma_C = sigma_C(0); //Take only the correlation of the first principal components
737
738 //garbage collecting
739 //ToDo
740
741 return ret_sigma_C;
742}
743
744//=============================================================================================================
745
746void RapMusic::calcA_k_1( const MatrixX6T& p_matG_k_1,
747 const Vector6T& p_matPhi_k_1,
748 const int p_iIdxk_1,
749 MatrixXT& p_matA_k_1)
750{
751 //Calculate A_k_1 = [a_theta_1..a_theta_k_1] matrix for subtraction of found source
752 VectorXT t_vec_a_theta_k_1(p_matG_k_1.rows(),1);
753
754 t_vec_a_theta_k_1 = p_matG_k_1*p_matPhi_k_1; // a_theta_k_1 = G_k_1*phi_k_1 this corresponds to the normalized signal component in subspace r
755
756 p_matA_k_1.block(0,p_iIdxk_1,p_matA_k_1.rows(),1) = t_vec_a_theta_k_1;
757}
758
759//=============================================================================================================
760
761void RapMusic::calcOrthProj(const MatrixXT& p_matA_k_1, MatrixXT& p_matOrthProj) const
762{
763 //Calculate OrthProj=I-A_k_1*(A_k_1'*A_k_1)^-1*A_k_1' //Wetterling -> A_k_1 = Gain
764
765 MatrixXT t_matA_k_1_tmp(p_matA_k_1.cols(), p_matA_k_1.cols());
766 t_matA_k_1_tmp = p_matA_k_1.adjoint()*p_matA_k_1;//A_k_1'*A_k_1 = A_k_1_tmp -> A_k_1' has to be adjoint for complex
767
768 int t_size = t_matA_k_1_tmp.cols();
769
770 while (!t_matA_k_1_tmp.block(0,0,t_size,t_size).fullPivLu().isInvertible())
771 {
772 --t_size;
773 }
774
775 MatrixXT t_matA_k_1_tmp_inv(t_matA_k_1_tmp.rows(), t_matA_k_1_tmp.cols());
776 t_matA_k_1_tmp_inv.setZero();
777
778 t_matA_k_1_tmp_inv.block(0,0,t_size,t_size) = t_matA_k_1_tmp.block(0,0,t_size,t_size).inverse();//(A_k_1_tmp)^-1 = A_k_1_tmp_inv
779
780 t_matA_k_1_tmp = MatrixXT::Zero(p_matA_k_1.rows(), p_matA_k_1.cols());
781
782 t_matA_k_1_tmp = p_matA_k_1*t_matA_k_1_tmp_inv;//(A_k_1*A_k_1_tmp_inv) = A_k_1_tmp
783
784 MatrixXT t_matA_k_1_tmp2(p_matA_k_1.rows(), p_matA_k_1.rows());
785
786 t_matA_k_1_tmp2 = t_matA_k_1_tmp*p_matA_k_1.adjoint();//(A_k_1_tmp)*A_k_1' -> here A_k_1' is only transposed - it has to be adjoint
787
789 I.setIdentity();
790
791 p_matOrthProj = I-t_matA_k_1_tmp2; //OrthProj=I-A_k_1*(A_k_1'*A_k_1)^-1*A_k_1';
792
793 //garbage collecting
794 //ToDo
795}
796
797//=============================================================================================================
798
799void RapMusic::calcPairCombinations( const int p_iNumPoints,
800 const int p_iNumCombinations,
801 Pair** p_ppPairIdxCombinations) const
802{
803 int idx1 = 0;
804 int idx2 = 0;
805
806 //Process Code in {m_max_num_threads} threads -> When compile with Intel Compiler -> probably obsolete
807 #ifdef _OPENMP
808 #pragma omp parallel num_threads(m_iMaxNumThreads) private(idx1, idx2)
809 #endif
810 {
811 #ifdef _OPENMP
812 #pragma omp for
813 #endif
814 for (int i = 0; i < p_iNumCombinations; ++i)
815 {
816 RapMusic::getPointPair(p_iNumPoints, i, idx1, idx2);
817
818 Pair* t_pairCombination = new Pair();
819 t_pairCombination->x1 = idx1;
820 t_pairCombination->x2 = idx2;
821
822 p_ppPairIdxCombinations[i] = t_pairCombination;
823 }
824 }
825}
826
827//=============================================================================================================
828
829void RapMusic::getPointPair(const int p_iPoints, const int p_iCurIdx, int &p_iIdx1, int &p_iIdx2)
830{
831 int ii = p_iPoints*(p_iPoints+1)/2-1-p_iCurIdx;
832 int K = (int)floor((sqrt((double)(8*ii+1))-1)/2);
833
834 p_iIdx1 = p_iPoints-1-K;
835
836 p_iIdx2 = (p_iCurIdx-p_iPoints*(p_iPoints+1)/2 + (K+1)*(K+2)/2)+p_iIdx1;
837}
838
839//=============================================================================================================
840//ToDo don't make a real copy
841void RapMusic::getGainMatrixPair( const MatrixXT& p_matGainMarix,
842 MatrixX6T& p_matGainMarix_Pair,
843 int p_iIdx1, int p_iIdx2)
844{
845 p_matGainMarix_Pair.block(0,0,p_matGainMarix.rows(),3) = p_matGainMarix.block(0, p_iIdx1*3, p_matGainMarix.rows(), 3);
846
847 p_matGainMarix_Pair.block(0,3,p_matGainMarix.rows(),3) = p_matGainMarix.block(0, p_iIdx2*3, p_matGainMarix.rows(), 3);
848}
849
850//=============================================================================================================
851
852void RapMusic::insertSource( int p_iDipoleIdx1, int p_iDipoleIdx2,
853 const Vector6T &p_vec_phi_k_1,
854 double p_valCor,
855 QList< DipolePair<double> > &p_RapDipoles)
856{
857 DipolePair<double> t_pRapDipolePair;
858
859 t_pRapDipolePair.m_iIdx1 = p_iDipoleIdx1; //p_iDipoleIdx1+1 because of MATLAB index
860 t_pRapDipolePair.m_iIdx2 = p_iDipoleIdx2;
861
862 t_pRapDipolePair.m_Dipole1.x() = 0; //m_bGridInitialized ? (*m_pMatGrid)(p_iDipoleIdx1, 0) : 0;
863 t_pRapDipolePair.m_Dipole1.y() = 0; //m_bGridInitialized ? (*m_pMatGrid)(p_iDipoleIdx1, 1) : 0;
864 t_pRapDipolePair.m_Dipole1.z() = 0; //m_bGridInitialized ? (*m_pMatGrid)(p_iDipoleIdx1, 2) : 0;
865
866 t_pRapDipolePair.m_Dipole2.x() = 0; //m_bGridInitialized ? (*m_pMatGrid)(p_iDipoleIdx2, 0) : 0;
867 t_pRapDipolePair.m_Dipole2.y() = 0; //m_bGridInitialized ? (*m_pMatGrid)(p_iDipoleIdx2, 1) : 0;
868 t_pRapDipolePair.m_Dipole2.z() = 0; //m_bGridInitialized ? (*m_pMatGrid)(p_iDipoleIdx2, 2) : 0;
869
870 t_pRapDipolePair.m_Dipole1.phi_x() = p_vec_phi_k_1[0];
871 t_pRapDipolePair.m_Dipole1.phi_y() = p_vec_phi_k_1[1];
872 t_pRapDipolePair.m_Dipole1.phi_z() = p_vec_phi_k_1[2];
873
874 t_pRapDipolePair.m_Dipole2.phi_x() = p_vec_phi_k_1[3];
875 t_pRapDipolePair.m_Dipole2.phi_y() = p_vec_phi_k_1[4];
876 t_pRapDipolePair.m_Dipole2.phi_z() = p_vec_phi_k_1[5];
877
878 t_pRapDipolePair.m_vCorrelation = p_valCor;
879
880 p_RapDipoles.append(t_pRapDipolePair);
881}
882
883//=============================================================================================================
884
885void RapMusic::setStcAttr(int p_iSampStcWin, float p_fStcOverlap)
886{
887 m_iSamplesStcWindow = p_iSampStcWin;
888 m_fStcOverlap = p_fStcOverlap;
889}
MNEMath class declaration.
#define X
RapMusic algorithm class declaration.
#define IS_TRANSPOSED
Definition pwlrapmusic.h:74
Core MNE data structures (source spaces, source estimates, hemispheres).
FIFF file I/O and data structures (raw, epochs, evoked, covariance, forward).
Inverse source estimation (MNE, dSPM, sLORETA, dipole fitting).
struct INVERSELIB::Pair Pair
Index pair representing two grid points evaluated together in the RAP MUSIC subspace scan.
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
Definition buildinfo.h:45
Eigen::RowVectorXf times
Eigen::MatrixXd data
Pair of correlated dipole indices and orientations found by the RAP MUSIC scanning step.
Definition dipole.h:59
Dipole< T > m_Dipole1
Definition dipole.h:61
Dipole< T > m_Dipole2
Definition dipole.h:64
Index pair representing two grid points evaluated together in the RAP MUSIC subspace scan.
Definition rapmusic.h:83
static double subcorr(MatrixX6T &p_matProj_G, const MatrixXT &p_pMatU_B)
Definition rapmusic.cpp:616
Eigen::Matrix< double, 6, 6 > Matrix6T
Definition rapmusic.h:111
Eigen::Matrix< double, Eigen::Dynamic, 1 > VectorXT
Definition rapmusic.h:113
Eigen::Matrix< double, Eigen::Dynamic, 6 > MatrixX6T
Definition rapmusic.h:107
bool init(MNELIB::MNEForwardSolution &p_pFwd, bool p_bSparsed=false, int p_iN=2, double p_dThr=0.5)
Definition rapmusic.cpp:109
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > MatrixXT
Definition rapmusic.h:105
virtual const char * getName() const
Definition rapmusic.cpp:192
static void getPointPair(const int p_iPoints, const int p_iCurIdx, int &p_iIdx1, int &p_iIdx2)
Definition rapmusic.cpp:829
int m_iNumLeadFieldCombinations
Definition rapmusic.h:309
static void insertSource(int p_iDipoleIdx1, int p_iDipoleIdx2, const Vector6T &p_vec_phi_k_1, double p_valCor, QList< DipolePair< double > > &p_RapDipoles)
Definition rapmusic.cpp:852
void calcOrthProj(const MatrixXT &p_matA_k_1, MatrixXT &p_matOrthProj) const
Definition rapmusic.cpp:761
void setStcAttr(int p_iSampStcWin, float p_fStcOverlap)
Definition rapmusic.cpp:885
Pair ** m_ppPairIdxCombinations
Definition rapmusic.h:311
static MatrixXT makeSquareMat(const MatrixXT &p_matF)
Definition rapmusic.h:393
virtual MNELIB::MNESourceEstimate calculateInverse(const FIFFLIB::FiffEvoked &p_fiffEvoked, bool pick_normal=false)
Definition rapmusic.cpp:206
Eigen::Matrix< double, 6, Eigen::Dynamic > Matrix6XT
Definition rapmusic.h:109
virtual const MNELIB::MNESourceSpaces & getSourceSpace() const
Definition rapmusic.cpp:199
void calcPairCombinations(const int p_iNumPoints, const int p_iNumCombinations, Pair **p_ppPairIdxCombinations) const
Definition rapmusic.cpp:799
static int useFullRank(const MatrixXT &p_Mat, const MatrixXT &p_matSigma_src, MatrixXT &p_matFull_Rank, int type=NOT_TRANSPOSED)
Definition rapmusic.h:376
MNELIB::MNEForwardSolution m_ForwardSolution
Definition rapmusic.h:300
static void getGainMatrixPair(const MatrixXT &p_matGainMarix, MatrixX6T &p_matGainMarix_Pair, int p_iIdx1, int p_iIdx2)
Definition rapmusic.cpp:841
int calcPhi_s(const MatrixXT &p_matMeasurement, MatrixXT *&p_pMatPhi_s) const
Definition rapmusic.cpp:587
static int getRank(const MatrixXT &p_matSigma)
Definition rapmusic.h:360
Eigen::Matrix< double, 6, 1 > Vector6T
Definition rapmusic.h:115
static void calcA_k_1(const MatrixX6T &p_matG_k_1, const Vector6T &p_matPhi_k_1, const int p_iIdxk_1, MatrixXT &p_matA_k_1)
Definition rapmusic.cpp:746
FIFFLIB::FiffNamedMatrix::SDPtr sol
Source Space descritpion.
static int nchoose2(int n)
Definition mnemath.cpp:387