75 init(p_pFwd, p_bSparsed, p_iN, p_dThr);
90 qDebug() <<
"OpenMP enabled";
93 qDebug() <<
"OpenMP disabled (to enable it: VS2010->Project Properties->C/C++->Language, then modify OpenMP Support)";
99 qDebug() <<
"##### Initialization RAP MUSIC started ######\n\n";
117 if ( p_pFwd.
sol->data.cols() % 3 != 0 )
119 qDebug() <<
"Gain matrix is not associated with a 3D grid!\n";
136 qDebug() <<
"Calculate gain matrix combinations. \n";
144 qDebug() <<
"Gain matrix combinations calculated. \n\n";
152 qDebug() <<
"Number of sources to find: " <<
m_iN <<
"\n\n";
158 qDebug() <<
"##### Initialization RAP MUSIC completed ######\n\n\n";
160 Q_UNUSED(p_bSparsed);
185 Q_UNUSED(pick_normal);
191 qDebug() <<
"Number of FiffEvoked channels (" << p_fiffEvoked.
data.rows() <<
") doesn't match the number of channels (" <<
m_iNumChannels <<
") of the forward solution.";
192 return p_sourceEstimate;
207 p_sourceEstimate.
tmin = p_fiffEvoked.
times[0];
208 p_sourceEstimate.
tstep = p_fiffEvoked.
times[1] - p_fiffEvoked.
times[0];
212 QList< InvDipolePair<double> > t_RapDipoles;
215 for(qint32 i = 0; i < t_RapDipoles.size(); ++i)
217 double dip1 = sqrt( pow(t_RapDipoles[i].m_Dipole1.phi_x(),2) +
218 pow(t_RapDipoles[i].m_Dipole1.phi_y(),2) +
219 pow(t_RapDipoles[i].m_Dipole1.phi_z(),2) ) * t_RapDipoles[i].m_vCorrelation;
221 double dip2 = sqrt( pow(t_RapDipoles[i].m_Dipole2.phi_x(),2) +
222 pow(t_RapDipoles[i].m_Dipole2.phi_y(),2) +
223 pow(t_RapDipoles[i].m_Dipole2.phi_z(),2) ) * t_RapDipoles[i].m_vCorrelation;
225 RowVectorXd dip1Time = RowVectorXd::Constant(p_fiffEvoked.
data.cols(), dip1);
226 RowVectorXd dip2Time = RowVectorXd::Constant(p_fiffEvoked.
data.cols(), dip2);
228 p_sourceEstimate.
data.block(t_RapDipoles[i].m_iIdx1, 0, 1, p_fiffEvoked.
data.cols()) = dip1Time;
229 p_sourceEstimate.
data.block(t_RapDipoles[i].m_iIdx2, 0, 1, p_fiffEvoked.
data.cols()) = dip2Time;
237 qint32 t_iNumSensors = p_fiffEvoked.
data.rows();
238 qint32 t_iNumSteps = p_fiffEvoked.
data.cols();
241 qint32 t_iSamplesDiscard = t_iSamplesOverlap/2;
245 qint32 curSample = 0;
246 qint32 curResultSample = 0;
251 QList< InvDipolePair<double> > t_RapDipoles;
264 curSample -= t_iSamplesDiscard;
271 stcWindowSize = p_sourceEstimate.
data.cols() - curResultSample;
273 for(qint32 i = 0; i < t_RapDipoles.size(); ++i)
275 double dip1 = sqrt( pow(t_RapDipoles[i].m_Dipole1.phi_x(),2) +
276 pow(t_RapDipoles[i].m_Dipole1.phi_y(),2) +
277 pow(t_RapDipoles[i].m_Dipole1.phi_z(),2) ) * t_RapDipoles[i].m_vCorrelation;
279 double dip2 = sqrt( pow(t_RapDipoles[i].m_Dipole2.phi_x(),2) +
280 pow(t_RapDipoles[i].m_Dipole2.phi_y(),2) +
281 pow(t_RapDipoles[i].m_Dipole2.phi_z(),2) ) * t_RapDipoles[i].m_vCorrelation;
283 RowVectorXd dip1Time = RowVectorXd::Constant(stcWindowSize, dip1);
284 RowVectorXd dip2Time = RowVectorXd::Constant(stcWindowSize, dip2);
286 p_sourceEstimate.
data.block(t_RapDipoles[i].m_iIdx1, curResultSample, 1, stcWindowSize) = dip1Time;
287 p_sourceEstimate.
data.block(t_RapDipoles[i].m_iIdx2, curResultSample, 1, stcWindowSize) = dip2Time;
291 curResultSample += stcWindowSize;
298 return p_sourceEstimate;
305 Q_UNUSED(pick_normal);
311 qDebug() <<
"Number of FiffEvoked channels (" << data.rows() <<
") doesn't match the number of channels (" <<
m_iNumChannels <<
") of the forward solution.";
312 return p_sourceEstimate;
326 p_sourceEstimate.
times = RowVectorXf::Zero(data.cols());
327 p_sourceEstimate.
times[0] = tmin;
328 for(qint32 i = 1; i < p_sourceEstimate.
times.size(); ++i)
329 p_sourceEstimate.
times[i] = p_sourceEstimate.
times[i-1] + tstep;
330 p_sourceEstimate.
tmin = tmin;
331 p_sourceEstimate.
tstep = tstep;
333 QList< InvDipolePair<double> > t_RapDipoles;
336 for(qint32 i = 0; i < t_RapDipoles.size(); ++i)
338 double dip1 = sqrt( pow(t_RapDipoles[i].m_Dipole1.phi_x(),2) +
339 pow(t_RapDipoles[i].m_Dipole1.phi_y(),2) +
340 pow(t_RapDipoles[i].m_Dipole1.phi_z(),2) ) * t_RapDipoles[i].m_vCorrelation;
342 double dip2 = sqrt( pow(t_RapDipoles[i].m_Dipole2.phi_x(),2) +
343 pow(t_RapDipoles[i].m_Dipole2.phi_y(),2) +
344 pow(t_RapDipoles[i].m_Dipole2.phi_z(),2) ) * t_RapDipoles[i].m_vCorrelation;
346 RowVectorXd dip1Time = RowVectorXd::Constant(data.cols(), dip1);
347 RowVectorXd dip2Time = RowVectorXd::Constant(data.cols(), dip2);
349 p_sourceEstimate.
data.block(t_RapDipoles[i].m_iIdx1, 0, 1, data.cols()) = dip1Time;
350 p_sourceEstimate.
data.block(t_RapDipoles[i].m_iIdx2, 0, 1, data.cols()) = dip2Time;
353 return p_sourceEstimate;
360 InvSourceEstimate p_SourceEstimate;
365 throw std::logic_error(
"RAP MUSIC was not initialized");
371 throw std::invalid_argument(
"Lead field channels do not match number of measurement channels");
387 int t_r =
calcPhi_s(p_matMeasurement, t_pMatPhi_s);
389 int t_iMaxSearch =
m_iN < t_r ?
m_iN : t_r;
393 qDebug() <<
"Warning: Rank " << t_r <<
" of the measurement data is smaller than the " <<
m_iN;
394 qDebug() <<
" sources to find.";
395 qDebug() <<
" Searching now for " << t_iMaxSearch <<
" correlated sources.";
402 t_matOrthProj.setIdentity();
406 t_matA_k_1.setZero();
422 p_RapDipoles.clear();
424 qDebug() <<
"##### Calculation of RAP MUSIC started ######\n\n";
426 MatrixXT t_matProj_Phi_s(t_matOrthProj.rows(), t_pMatPhi_s->cols());
430 for(
int r = 0; r < t_iMaxSearch ; ++r)
432 t_matProj_Phi_s = t_matOrthProj*(*t_pMatPhi_s);
439 Eigen::JacobiSVD< MatrixXT > t_svdProj_Phi_S(t_matProj_Phi_s, Eigen::ComputeThinU);
441 useFullRank(t_svdProj_Phi_S.matrixU(), t_svdProj_Phi_S.singularValues().asDiagonal(), t_matU_B);
449 clock_t start_subcorr, end_subcorr;
450 start_subcorr = clock();
454 #pragma omp parallel num_threads(m_iMaxNumThreads)
464 MatrixX6T t_matProj_G(t_matProj_LeadField.rows(),6);
492 end_subcorr = clock();
494 float t_fSubcorrElapsedTime = (
static_cast<float>(end_subcorr-start_subcorr) /
static_cast<float>(CLOCKS_PER_SEC) ) * 1000.0f;
495 qDebug() <<
"Time Elapsed: " << t_fSubcorrElapsedTime <<
" ms";
500 VectorXT::Index t_iMaxIdx;
502 t_val_roh_k = t_vecRoh.maxCoeff(&t_iMaxIdx);
509 qDebug() <<
"Iteration: " << r+1 <<
" of " << t_iMaxSearch
510 <<
"; Correlation: " << t_val_roh_k<<
"; Position (Idx+1): " << t_iIdx1+1 <<
" - " << t_iIdx2+1 <<
"\n\n";
516 MatrixX6T t_matProj_G_k_1(t_matOrthProj.rows(), t_matG_k_1.cols());
517 t_matProj_G_k_1 = t_matOrthProj * t_matG_k_1;
532 qDebug() <<
"Searching stopped, last correlation " << t_val_roh_k;
533 qDebug() <<
" is smaller then the given threshold " <<
m_dThreshold;
547 qDebug() <<
"##### Calculation of RAP MUSIC completed ######";
551 float t_fElapsedTime = (
static_cast<float>(end-start) /
static_cast<float>(CLOCKS_PER_SEC) ) * 1000.0f;
552 qDebug() <<
"Total Time Elapsed: " << t_fElapsedTime <<
" ms";
557 return p_SourceEstimate;
566 if (p_matMeasurement.cols() > p_matMeasurement.rows())
569 t_matF =
MatrixXT(p_matMeasurement);
571 Eigen::JacobiSVD<MatrixXT> t_svdF(t_matF, Eigen::ComputeThinU);
573 int t_r =
getRank(t_svdF.singularValues().asDiagonal());
583 memcpy(p_pMatPhi_s->data(), t_svdF.matrixU().data(),
sizeof(
double) *
m_iNumChannels * t_iCols);
595 Matrix6XT t_matU_A_T(6, p_matProj_G.rows());
597 Eigen::JacobiSVD<MatrixXT> t_svdProj_G(p_matProj_G, Eigen::ComputeThinU);
599 t_matSigma_A = t_svdProj_G.singularValues().asDiagonal();
600 t_matU_A_T = t_svdProj_G.matrixU().transpose();
609 MatrixXT t_matCor(t_matU_A_T_full.rows(), p_matU_B.cols());
612 t_matCor = t_matU_A_T_full*p_matU_B;
616 if (t_matCor.cols() > t_matCor.rows())
618 MatrixXT t_matCor_H = t_matCor.adjoint();
620 Eigen::JacobiSVD<MatrixXT> t_svdCor_H(t_matCor_H);
622 t_vecSigma_C = t_svdCor_H.singularValues();
626 Eigen::JacobiSVD<MatrixXT> t_svdCor(t_matCor);
628 t_vecSigma_C = t_svdCor.singularValues();
632 double t_dRetSigma_C;
633 t_dRetSigma_C = t_vecSigma_C(0);
638 return t_dRetSigma_C;
651 Eigen::JacobiSVD<MatrixXT> svdOfProj_G(p_matProj_G, Eigen::ComputeThinU | Eigen::ComputeThinV);
653 sigma_A = svdOfProj_G.singularValues().asDiagonal();
654 U_A_T = svdOfProj_G.matrixU().transpose();
655 V_A = svdOfProj_G.matrixV();
664 t_matCor = U_A_T*p_matU_B;
671 if (t_matCor.cols() > t_matCor.rows())
674 Cor_H = t_matCor.adjoint();
676 Eigen::JacobiSVD<MatrixXT> svdOfCor_H(Cor_H, Eigen::ComputeThinV);
678 U_C = svdOfCor_H.matrixV();
679 sigma_C = svdOfCor_H.singularValues();
683 Eigen::JacobiSVD<MatrixXT> svdOfCor(t_matCor, Eigen::ComputeThinU);
685 U_C = svdOfCor.matrixU();
686 sigma_C = svdOfCor.singularValues();
690 sigma_a_inv = sigma_A.inverse();
693 X = (V_A*sigma_a_inv)*U_C;
698 double norm_X = 1/(X_max.norm());
701 p_vec_phi_k_1 = X_max*norm_X;
708 ret_sigma_C = sigma_C(0);
724 VectorXT t_vec_a_theta_k_1(p_matG_k_1.rows(),1);
726 t_vec_a_theta_k_1 = p_matG_k_1*p_matPhi_k_1;
728 p_matA_k_1.block(0,p_iIdxk_1,p_matA_k_1.rows(),1) = t_vec_a_theta_k_1;
737 MatrixXT t_matA_k_1_tmp(p_matA_k_1.cols(), p_matA_k_1.cols());
738 t_matA_k_1_tmp = p_matA_k_1.adjoint()*p_matA_k_1;
740 int t_size = t_matA_k_1_tmp.cols();
742 while (!t_matA_k_1_tmp.block(0,0,t_size,t_size).fullPivLu().isInvertible())
747 MatrixXT t_matA_k_1_tmp_inv(t_matA_k_1_tmp.rows(), t_matA_k_1_tmp.cols());
748 t_matA_k_1_tmp_inv.setZero();
750 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();
752 t_matA_k_1_tmp = MatrixXT::Zero(p_matA_k_1.rows(), p_matA_k_1.cols());
754 t_matA_k_1_tmp = p_matA_k_1*t_matA_k_1_tmp_inv;
756 MatrixXT t_matA_k_1_tmp2(p_matA_k_1.rows(), p_matA_k_1.rows());
758 t_matA_k_1_tmp2 = t_matA_k_1_tmp*p_matA_k_1.adjoint();
763 p_matOrthProj = I-t_matA_k_1_tmp2;
772 const int p_iNumCombinations,
773 std::vector<Pair>& p_pairIdxCombinations)
const
780 #pragma omp parallel num_threads(m_iMaxNumThreads) private(idx1, idx2)
786 for (
int i = 0; i < p_iNumCombinations; ++i)
790 Pair t_pairCombination;
791 t_pairCombination.
x1 = idx1;
792 t_pairCombination.
x2 = idx2;
794 p_pairIdxCombinations[i] = t_pairCombination;
803 int ii = p_iPoints*(p_iPoints+1)/2-1-p_iCurIdx;
804 int K =
static_cast<int>(floor((sqrt(
static_cast<double>(8*ii+1))-1)/2));
806 p_iIdx1 = p_iPoints-1-K;
808 p_iIdx2 = (p_iCurIdx-p_iPoints*(p_iPoints+1)/2 + (K+1)*(K+2)/2)+p_iIdx1;
815 int p_iIdx1,
int p_iIdx2)
817 p_matGainMarix_Pair.block(0,0,p_matGainMarix.rows(),3) = p_matGainMarix.block(0, p_iIdx1*3, p_matGainMarix.rows(), 3);
819 p_matGainMarix_Pair.block(0,3,p_matGainMarix.rows(),3) = p_matGainMarix.block(0, p_iIdx2*3, p_matGainMarix.rows(), 3);
831 t_pRapDipolePair.
m_iIdx1 = p_iDipoleIdx1;
832 t_pRapDipolePair.
m_iIdx2 = p_iDipoleIdx2;
842 t_pRapDipolePair.
m_Dipole1.phi_x() = p_vec_phi_k_1[0];
843 t_pRapDipolePair.
m_Dipole1.phi_y() = p_vec_phi_k_1[1];
844 t_pRapDipolePair.
m_Dipole1.phi_z() = p_vec_phi_k_1[2];
846 t_pRapDipolePair.
m_Dipole2.phi_x() = p_vec_phi_k_1[3];
847 t_pRapDipolePair.
m_Dipole2.phi_y() = p_vec_phi_k_1[4];
848 t_pRapDipolePair.
m_Dipole2.phi_z() = p_vec_phi_k_1[5];
852 p_RapDipoles.append(t_pRapDipolePair);
Recursively Applied and Projected MUSIC (RAP-MUSIC) source-localisation algorithm.
General numerical helpers: GCD, log2, histogram binning, baseline rescaling, sparsity tests.
Core MNE data structures (source spaces, source estimates, hemispheres).
FIFF file I/O, in-memory data structures and high-level readers/writers.
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
Inverse source estimation (MNE, dSPM, sLORETA, dipole fitting).
Single averaged evoked response: time axis, data, baseline, channel info and averaging metadata.
Source-space inverse-solution container with dense grid plus optional focal-dipole,...
Pair of correlated dipole indices and orientations found by the RAP MUSIC scanning step.
Index pair representing two grid points evaluated together in the RAP MUSIC subspace scan.
Eigen::Matrix< double, 6, 1 > Vector6T
void calcPairCombinations(const int p_iNumPoints, const int p_iNumCombinations, std::vector< Pair > &p_pairIdxCombinations) const
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)
static void getPointPair(const int p_iPoints, const int p_iCurIdx, int &p_iIdx1, int &p_iIdx2)
virtual InvSourceEstimate calculateInverse(const FIFFLIB::FiffEvoked &p_fiffEvoked, bool pick_normal=false)
static int getRank(const MatrixXT &p_matSigma)
virtual const char * getName() const
static MatrixXT makeSquareMat(const MatrixXT &p_matF)
static void insertSource(int p_iDipoleIdx1, int p_iDipoleIdx2, const Vector6T &p_vec_phi_k_1, double p_valCor, QList< InvDipolePair< double > > &p_RapDipoles)
void setStcAttr(int p_iSampStcWin, float p_fStcOverlap)
bool init(MNELIB::MNEForwardSolution &p_pFwd, bool p_bSparsed=false, int p_iN=2, double p_dThr=0.5)
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > MatrixXT
Eigen::Matrix< double, 6, 6 > Matrix6T
Eigen::Matrix< double, Eigen::Dynamic, 1 > VectorXT
void calcOrthProj(const MatrixXT &p_matA_k_1, MatrixXT &p_matOrthProj) const
int calcPhi_s(const MatrixXT &p_matMeasurement, MatrixXT *&p_pMatPhi_s) const
static int useFullRank(const MatrixXT &p_Mat, const MatrixXT &p_matSigma_src, MatrixXT &p_matFull_Rank, int type=NOT_TRANSPOSED)
Eigen::Matrix< double, Eigen::Dynamic, 6 > MatrixX6T
MNELIB::MNEForwardSolution m_ForwardSolution
virtual const MNELIB::MNESourceSpaces & getSourceSpace() const
std::vector< Pair > m_ppPairIdxCombinations
Eigen::Matrix< double, 6, Eigen::Dynamic > Matrix6XT
static void getGainMatrixPair(const MatrixXT &p_matGainMarix, MatrixX6T &p_matGainMarix_Pair, int p_iIdx1, int p_iIdx2)
int m_iNumLeadFieldCombinations
static double subcorr(MatrixX6T &p_matProj_G, const MatrixXT &p_pMatU_B)
static int nchoose2(int n)
In-memory representation of an -fwd.fif forward solution.
FIFFLIB::fiff_int_t nsource
MNELIB::MNESourceSpaces src
FIFFLIB::FiffNamedMatrix::SDPtr sol
List of MNESourceSpace objects forming a subject source space.