91 init(p_pFwd, p_bSparsed, p_iN, p_dThr);
106 qDebug() <<
"OpenMP enabled";
109 qDebug() <<
"OpenMP disabled (to enable it: VS2010->Project Properties->C/C++->Language, then modify OpenMP Support)";
115 qDebug() <<
"##### Initialization RAP MUSIC started ######\n\n";
133 if ( p_pFwd.
sol->data.cols() % 3 != 0 )
135 qDebug() <<
"Gain matrix is not associated with a 3D grid!\n";
152 qDebug() <<
"Calculate gain matrix combinations. \n";
160 qDebug() <<
"Gain matrix combinations calculated. \n\n";
168 qDebug() <<
"Number of sources to find: " <<
m_iN <<
"\n\n";
174 qDebug() <<
"##### Initialization RAP MUSIC completed ######\n\n\n";
176 Q_UNUSED(p_bSparsed);
201 Q_UNUSED(pick_normal);
207 qDebug() <<
"Number of FiffEvoked channels (" << p_fiffEvoked.
data.rows() <<
") doesn't match the number of channels (" <<
m_iNumChannels <<
") of the forward solution.";
208 return p_sourceEstimate;
223 p_sourceEstimate.
tmin = p_fiffEvoked.
times[0];
224 p_sourceEstimate.
tstep = p_fiffEvoked.
times[1] - p_fiffEvoked.
times[0];
228 QList< InvDipolePair<double> > t_RapDipoles;
231 for(qint32 i = 0; i < t_RapDipoles.size(); ++i)
233 double dip1 = sqrt( pow(t_RapDipoles[i].m_Dipole1.phi_x(),2) +
234 pow(t_RapDipoles[i].m_Dipole1.phi_y(),2) +
235 pow(t_RapDipoles[i].m_Dipole1.phi_z(),2) ) * t_RapDipoles[i].m_vCorrelation;
237 double dip2 = sqrt( pow(t_RapDipoles[i].m_Dipole2.phi_x(),2) +
238 pow(t_RapDipoles[i].m_Dipole2.phi_y(),2) +
239 pow(t_RapDipoles[i].m_Dipole2.phi_z(),2) ) * t_RapDipoles[i].m_vCorrelation;
241 RowVectorXd dip1Time = RowVectorXd::Constant(p_fiffEvoked.
data.cols(), dip1);
242 RowVectorXd dip2Time = RowVectorXd::Constant(p_fiffEvoked.
data.cols(), dip2);
244 p_sourceEstimate.
data.block(t_RapDipoles[i].m_iIdx1, 0, 1, p_fiffEvoked.
data.cols()) = dip1Time;
245 p_sourceEstimate.
data.block(t_RapDipoles[i].m_iIdx2, 0, 1, p_fiffEvoked.
data.cols()) = dip2Time;
253 qint32 t_iNumSensors = p_fiffEvoked.
data.rows();
254 qint32 t_iNumSteps = p_fiffEvoked.
data.cols();
257 qint32 t_iSamplesDiscard = t_iSamplesOverlap/2;
261 qint32 curSample = 0;
262 qint32 curResultSample = 0;
267 QList< InvDipolePair<double> > t_RapDipoles;
280 curSample -= t_iSamplesDiscard;
287 stcWindowSize = p_sourceEstimate.
data.cols() - curResultSample;
289 for(qint32 i = 0; i < t_RapDipoles.size(); ++i)
291 double dip1 = sqrt( pow(t_RapDipoles[i].m_Dipole1.phi_x(),2) +
292 pow(t_RapDipoles[i].m_Dipole1.phi_y(),2) +
293 pow(t_RapDipoles[i].m_Dipole1.phi_z(),2) ) * t_RapDipoles[i].m_vCorrelation;
295 double dip2 = sqrt( pow(t_RapDipoles[i].m_Dipole2.phi_x(),2) +
296 pow(t_RapDipoles[i].m_Dipole2.phi_y(),2) +
297 pow(t_RapDipoles[i].m_Dipole2.phi_z(),2) ) * t_RapDipoles[i].m_vCorrelation;
299 RowVectorXd dip1Time = RowVectorXd::Constant(stcWindowSize, dip1);
300 RowVectorXd dip2Time = RowVectorXd::Constant(stcWindowSize, dip2);
302 p_sourceEstimate.
data.block(t_RapDipoles[i].m_iIdx1, curResultSample, 1, stcWindowSize) = dip1Time;
303 p_sourceEstimate.
data.block(t_RapDipoles[i].m_iIdx2, curResultSample, 1, stcWindowSize) = dip2Time;
307 curResultSample += stcWindowSize;
314 return p_sourceEstimate;
321 Q_UNUSED(pick_normal);
327 qDebug() <<
"Number of FiffEvoked channels (" << data.rows() <<
") doesn't match the number of channels (" <<
m_iNumChannels <<
") of the forward solution.";
328 return p_sourceEstimate;
342 p_sourceEstimate.
times = RowVectorXf::Zero(data.cols());
343 p_sourceEstimate.
times[0] = tmin;
344 for(qint32 i = 1; i < p_sourceEstimate.
times.size(); ++i)
345 p_sourceEstimate.
times[i] = p_sourceEstimate.
times[i-1] + tstep;
346 p_sourceEstimate.
tmin = tmin;
347 p_sourceEstimate.
tstep = tstep;
349 QList< InvDipolePair<double> > t_RapDipoles;
352 for(qint32 i = 0; i < t_RapDipoles.size(); ++i)
354 double dip1 = sqrt( pow(t_RapDipoles[i].m_Dipole1.phi_x(),2) +
355 pow(t_RapDipoles[i].m_Dipole1.phi_y(),2) +
356 pow(t_RapDipoles[i].m_Dipole1.phi_z(),2) ) * t_RapDipoles[i].m_vCorrelation;
358 double dip2 = sqrt( pow(t_RapDipoles[i].m_Dipole2.phi_x(),2) +
359 pow(t_RapDipoles[i].m_Dipole2.phi_y(),2) +
360 pow(t_RapDipoles[i].m_Dipole2.phi_z(),2) ) * t_RapDipoles[i].m_vCorrelation;
362 RowVectorXd dip1Time = RowVectorXd::Constant(data.cols(), dip1);
363 RowVectorXd dip2Time = RowVectorXd::Constant(data.cols(), dip2);
365 p_sourceEstimate.
data.block(t_RapDipoles[i].m_iIdx1, 0, 1, data.cols()) = dip1Time;
366 p_sourceEstimate.
data.block(t_RapDipoles[i].m_iIdx2, 0, 1, data.cols()) = dip2Time;
369 return p_sourceEstimate;
376 InvSourceEstimate p_SourceEstimate;
381 throw std::logic_error(
"RAP MUSIC was not initialized");
387 throw std::invalid_argument(
"Lead field channels do not match number of measurement channels");
403 int t_r =
calcPhi_s(p_matMeasurement, t_pMatPhi_s);
405 int t_iMaxSearch =
m_iN < t_r ?
m_iN : t_r;
409 qDebug() <<
"Warning: Rank " << t_r <<
" of the measurement data is smaller than the " <<
m_iN;
410 qDebug() <<
" sources to find.";
411 qDebug() <<
" Searching now for " << t_iMaxSearch <<
" correlated sources.";
418 t_matOrthProj.setIdentity();
422 t_matA_k_1.setZero();
438 p_RapDipoles.clear();
440 qDebug() <<
"##### Calculation of RAP MUSIC started ######\n\n";
442 MatrixXT t_matProj_Phi_s(t_matOrthProj.rows(), t_pMatPhi_s->cols());
446 for(
int r = 0; r < t_iMaxSearch ; ++r)
448 t_matProj_Phi_s = t_matOrthProj*(*t_pMatPhi_s);
455 Eigen::JacobiSVD< MatrixXT > t_svdProj_Phi_S(t_matProj_Phi_s, Eigen::ComputeThinU);
457 useFullRank(t_svdProj_Phi_S.matrixU(), t_svdProj_Phi_S.singularValues().asDiagonal(), t_matU_B);
465 clock_t start_subcorr, end_subcorr;
466 start_subcorr = clock();
470 #pragma omp parallel num_threads(m_iMaxNumThreads)
480 MatrixX6T t_matProj_G(t_matProj_LeadField.rows(),6);
508 end_subcorr = clock();
510 float t_fSubcorrElapsedTime = (
static_cast<float>(end_subcorr-start_subcorr) /
static_cast<float>(CLOCKS_PER_SEC) ) * 1000.0f;
511 qDebug() <<
"Time Elapsed: " << t_fSubcorrElapsedTime <<
" ms";
516 VectorXT::Index t_iMaxIdx;
518 t_val_roh_k = t_vecRoh.maxCoeff(&t_iMaxIdx);
525 qDebug() <<
"Iteration: " << r+1 <<
" of " << t_iMaxSearch
526 <<
"; Correlation: " << t_val_roh_k<<
"; Position (Idx+1): " << t_iIdx1+1 <<
" - " << t_iIdx2+1 <<
"\n\n";
532 MatrixX6T t_matProj_G_k_1(t_matOrthProj.rows(), t_matG_k_1.cols());
533 t_matProj_G_k_1 = t_matOrthProj * t_matG_k_1;
548 qDebug() <<
"Searching stopped, last correlation " << t_val_roh_k;
549 qDebug() <<
" is smaller then the given threshold " <<
m_dThreshold;
563 qDebug() <<
"##### Calculation of RAP MUSIC completed ######";
567 float t_fElapsedTime = (
static_cast<float>(end-start) /
static_cast<float>(CLOCKS_PER_SEC) ) * 1000.0f;
568 qDebug() <<
"Total Time Elapsed: " << t_fElapsedTime <<
" ms";
573 return p_SourceEstimate;
582 if (p_matMeasurement.cols() > p_matMeasurement.rows())
585 t_matF =
MatrixXT(p_matMeasurement);
587 Eigen::JacobiSVD<MatrixXT> t_svdF(t_matF, Eigen::ComputeThinU);
589 int t_r =
getRank(t_svdF.singularValues().asDiagonal());
593 if (p_pMatPhi_s !=
nullptr)
600 memcpy(p_pMatPhi_s->data(), t_svdF.matrixU().data(),
sizeof(
double) *
m_iNumChannels * t_iCols);
612 Matrix6XT t_matU_A_T(6, p_matProj_G.rows());
614 Eigen::JacobiSVD<MatrixXT> t_svdProj_G(p_matProj_G, Eigen::ComputeThinU);
616 t_matSigma_A = t_svdProj_G.singularValues().asDiagonal();
617 t_matU_A_T = t_svdProj_G.matrixU().transpose();
626 MatrixXT t_matCor(t_matU_A_T_full.rows(), p_matU_B.cols());
629 t_matCor = t_matU_A_T_full*p_matU_B;
633 if (t_matCor.cols() > t_matCor.rows())
635 MatrixXT t_matCor_H = t_matCor.adjoint();
637 Eigen::JacobiSVD<MatrixXT> t_svdCor_H(t_matCor_H);
639 t_vecSigma_C = t_svdCor_H.singularValues();
643 Eigen::JacobiSVD<MatrixXT> t_svdCor(t_matCor);
645 t_vecSigma_C = t_svdCor.singularValues();
649 double t_dRetSigma_C;
650 t_dRetSigma_C = t_vecSigma_C(0);
655 return t_dRetSigma_C;
668 Eigen::JacobiSVD<MatrixXT> svdOfProj_G(p_matProj_G, Eigen::ComputeThinU | Eigen::ComputeThinV);
670 sigma_A = svdOfProj_G.singularValues().asDiagonal();
671 U_A_T = svdOfProj_G.matrixU().transpose();
672 V_A = svdOfProj_G.matrixV();
681 t_matCor = U_A_T*p_matU_B;
688 if (t_matCor.cols() > t_matCor.rows())
691 Cor_H = t_matCor.adjoint();
693 Eigen::JacobiSVD<MatrixXT> svdOfCor_H(Cor_H, Eigen::ComputeThinV);
695 U_C = svdOfCor_H.matrixV();
696 sigma_C = svdOfCor_H.singularValues();
700 Eigen::JacobiSVD<MatrixXT> svdOfCor(t_matCor, Eigen::ComputeThinU);
702 U_C = svdOfCor.matrixU();
703 sigma_C = svdOfCor.singularValues();
707 sigma_a_inv = sigma_A.inverse();
710 X = (V_A*sigma_a_inv)*U_C;
715 double norm_X = 1/(X_max.norm());
718 p_vec_phi_k_1 = X_max*norm_X;
725 ret_sigma_C = sigma_C(0);
741 VectorXT t_vec_a_theta_k_1(p_matG_k_1.rows(),1);
743 t_vec_a_theta_k_1 = p_matG_k_1*p_matPhi_k_1;
745 p_matA_k_1.block(0,p_iIdxk_1,p_matA_k_1.rows(),1) = t_vec_a_theta_k_1;
754 MatrixXT t_matA_k_1_tmp(p_matA_k_1.cols(), p_matA_k_1.cols());
755 t_matA_k_1_tmp = p_matA_k_1.adjoint()*p_matA_k_1;
757 int t_size = t_matA_k_1_tmp.cols();
759 while (!t_matA_k_1_tmp.block(0,0,t_size,t_size).fullPivLu().isInvertible())
764 MatrixXT t_matA_k_1_tmp_inv(t_matA_k_1_tmp.rows(), t_matA_k_1_tmp.cols());
765 t_matA_k_1_tmp_inv.setZero();
767 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();
769 t_matA_k_1_tmp = MatrixXT::Zero(p_matA_k_1.rows(), p_matA_k_1.cols());
771 t_matA_k_1_tmp = p_matA_k_1*t_matA_k_1_tmp_inv;
773 MatrixXT t_matA_k_1_tmp2(p_matA_k_1.rows(), p_matA_k_1.rows());
775 t_matA_k_1_tmp2 = t_matA_k_1_tmp*p_matA_k_1.adjoint();
780 p_matOrthProj = I-t_matA_k_1_tmp2;
789 const int p_iNumCombinations,
790 std::vector<Pair>& p_pairIdxCombinations)
const
797 #pragma omp parallel num_threads(m_iMaxNumThreads) private(idx1, idx2)
803 for (
int i = 0; i < p_iNumCombinations; ++i)
807 Pair t_pairCombination;
808 t_pairCombination.
x1 = idx1;
809 t_pairCombination.
x2 = idx2;
811 p_pairIdxCombinations[i] = t_pairCombination;
820 int ii = p_iPoints*(p_iPoints+1)/2-1-p_iCurIdx;
821 int K =
static_cast<int>(floor((sqrt(
static_cast<double>(8*ii+1))-1)/2));
823 p_iIdx1 = p_iPoints-1-K;
825 p_iIdx2 = (p_iCurIdx-p_iPoints*(p_iPoints+1)/2 + (K+1)*(K+2)/2)+p_iIdx1;
832 int p_iIdx1,
int p_iIdx2)
834 p_matGainMarix_Pair.block(0,0,p_matGainMarix.rows(),3) = p_matGainMarix.block(0, p_iIdx1*3, p_matGainMarix.rows(), 3);
836 p_matGainMarix_Pair.block(0,3,p_matGainMarix.rows(),3) = p_matGainMarix.block(0, p_iIdx2*3, p_matGainMarix.rows(), 3);
848 t_pRapDipolePair.
m_iIdx1 = p_iDipoleIdx1;
849 t_pRapDipolePair.
m_iIdx2 = p_iDipoleIdx2;
859 t_pRapDipolePair.
m_Dipole1.phi_x() = p_vec_phi_k_1[0];
860 t_pRapDipolePair.
m_Dipole1.phi_y() = p_vec_phi_k_1[1];
861 t_pRapDipolePair.
m_Dipole1.phi_z() = p_vec_phi_k_1[2];
863 t_pRapDipolePair.
m_Dipole2.phi_x() = p_vec_phi_k_1[3];
864 t_pRapDipolePair.
m_Dipole2.phi_y() = p_vec_phi_k_1[4];
865 t_pRapDipolePair.
m_Dipole2.phi_z() = p_vec_phi_k_1[5];
869 p_RapDipoles.append(t_pRapDipolePair);
Numerics class declaration.
InvRapMusic algorithm class declaration.
Core MNE data structures (source spaces, source estimates, hemispheres).
FIFF file I/O and data structures (raw, epochs, evoked, covariance, forward).
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
Inverse source estimation (MNE, dSPM, sLORETA, dipole fitting).
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)
FIFFLIB::fiff_int_t nsource
MNELIB::MNESourceSpaces src
FIFFLIB::FiffNamedMatrix::SDPtr sol
Source Space descritpion.