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) {
118 qDebug() <<
"Gain matrix is not associated with a 3D grid!\n";
135 qDebug() <<
"Calculate gain matrix combinations. \n";
143 qDebug() <<
"Gain matrix combinations calculated. \n\n";
151 qDebug() <<
"Number of sources to find: " <<
m_iN <<
"\n\n";
157 qDebug() <<
"##### Initialization RAP MUSIC completed ######\n\n\n";
159 Q_UNUSED(p_bSparsed);
184 Q_UNUSED(pick_normal);
189 qDebug() <<
"Number of FiffEvoked channels (" << p_fiffEvoked.
data.rows() <<
") doesn't match the number of channels (" <<
m_iNumChannels <<
") of the forward solution.";
190 return p_sourceEstimate;
205 p_sourceEstimate.
tmin = p_fiffEvoked.
times[0];
206 p_sourceEstimate.
tstep = p_fiffEvoked.
times[1] - p_fiffEvoked.
times[0];
210 QList<InvDipolePair<double>> t_RapDipoles;
213 for (qint32 i = 0; i < t_RapDipoles.size(); ++i) {
214 double dip1 = sqrt(pow(t_RapDipoles[i].m_Dipole1.phi_x(), 2) +
215 pow(t_RapDipoles[i].m_Dipole1.phi_y(), 2) +
216 pow(t_RapDipoles[i].m_Dipole1.phi_z(), 2)) *
217 t_RapDipoles[i].m_vCorrelation;
219 double dip2 = sqrt(pow(t_RapDipoles[i].m_Dipole2.phi_x(), 2) +
220 pow(t_RapDipoles[i].m_Dipole2.phi_y(), 2) +
221 pow(t_RapDipoles[i].m_Dipole2.phi_z(), 2)) *
222 t_RapDipoles[i].m_vCorrelation;
224 RowVectorXd dip1Time = RowVectorXd::Constant(p_fiffEvoked.
data.cols(), dip1);
225 RowVectorXd dip2Time = RowVectorXd::Constant(p_fiffEvoked.
data.cols(), dip2);
227 p_sourceEstimate.
data.block(t_RapDipoles[i].m_iIdx1, 0, 1, p_fiffEvoked.
data.cols()) = dip1Time;
228 p_sourceEstimate.
data.block(t_RapDipoles[i].m_iIdx2, 0, 1, p_fiffEvoked.
data.cols()) = dip2Time;
234 qint32 t_iNumSensors = p_fiffEvoked.
data.rows();
235 qint32 t_iNumSteps = p_fiffEvoked.
data.cols();
238 qint32 t_iSamplesDiscard = t_iSamplesOverlap / 2;
242 qint32 curSample = 0;
243 qint32 curResultSample = 0;
247 QList<InvDipolePair<double>> t_RapDipoles;
259 curSample -= t_iSamplesDiscard;
266 stcWindowSize = p_sourceEstimate.
data.cols() - curResultSample;
268 for (qint32 i = 0; i < t_RapDipoles.size(); ++i) {
269 double dip1 = sqrt(pow(t_RapDipoles[i].m_Dipole1.phi_x(), 2) +
270 pow(t_RapDipoles[i].m_Dipole1.phi_y(), 2) +
271 pow(t_RapDipoles[i].m_Dipole1.phi_z(), 2)) *
272 t_RapDipoles[i].m_vCorrelation;
274 double dip2 = sqrt(pow(t_RapDipoles[i].m_Dipole2.phi_x(), 2) +
275 pow(t_RapDipoles[i].m_Dipole2.phi_y(), 2) +
276 pow(t_RapDipoles[i].m_Dipole2.phi_z(), 2)) *
277 t_RapDipoles[i].m_vCorrelation;
279 RowVectorXd dip1Time = RowVectorXd::Constant(stcWindowSize, dip1);
280 RowVectorXd dip2Time = RowVectorXd::Constant(stcWindowSize, dip2);
282 p_sourceEstimate.
data.block(t_RapDipoles[i].m_iIdx1, curResultSample, 1, stcWindowSize) = dip1Time;
283 p_sourceEstimate.
data.block(t_RapDipoles[i].m_iIdx2, curResultSample, 1, stcWindowSize) = dip2Time;
286 curResultSample += stcWindowSize;
293 return p_sourceEstimate;
300 Q_UNUSED(pick_normal);
305 qDebug() <<
"Number of FiffEvoked channels (" << data.rows() <<
") doesn't match the number of channels (" <<
m_iNumChannels <<
") of the forward solution.";
306 return p_sourceEstimate;
320 p_sourceEstimate.
times = RowVectorXf::Zero(data.cols());
321 p_sourceEstimate.
times[0] = tmin;
322 for (qint32 i = 1; i < p_sourceEstimate.
times.size(); ++i)
323 p_sourceEstimate.
times[i] = p_sourceEstimate.
times[i - 1] + tstep;
324 p_sourceEstimate.
tmin = tmin;
325 p_sourceEstimate.
tstep = tstep;
327 QList<InvDipolePair<double>> t_RapDipoles;
330 for (qint32 i = 0; i < t_RapDipoles.size(); ++i) {
331 double dip1 = sqrt(pow(t_RapDipoles[i].m_Dipole1.phi_x(), 2) +
332 pow(t_RapDipoles[i].m_Dipole1.phi_y(), 2) +
333 pow(t_RapDipoles[i].m_Dipole1.phi_z(), 2)) *
334 t_RapDipoles[i].m_vCorrelation;
336 double dip2 = sqrt(pow(t_RapDipoles[i].m_Dipole2.phi_x(), 2) +
337 pow(t_RapDipoles[i].m_Dipole2.phi_y(), 2) +
338 pow(t_RapDipoles[i].m_Dipole2.phi_z(), 2)) *
339 t_RapDipoles[i].m_vCorrelation;
341 RowVectorXd dip1Time = RowVectorXd::Constant(data.cols(), dip1);
342 RowVectorXd dip2Time = RowVectorXd::Constant(data.cols(), dip2);
344 p_sourceEstimate.
data.block(t_RapDipoles[i].m_iIdx1, 0, 1, data.cols()) = dip1Time;
345 p_sourceEstimate.
data.block(t_RapDipoles[i].m_iIdx2, 0, 1, data.cols()) = dip2Time;
348 return p_sourceEstimate;
355 InvSourceEstimate p_SourceEstimate;
359 throw std::logic_error(
"RAP MUSIC was not initialized");
364 throw std::invalid_argument(
"Lead field channels do not match number of measurement channels");
380 int t_r =
calcPhi_s( p_matMeasurement, t_pMatPhi_s);
382 int t_iMaxSearch =
m_iN < t_r ?
m_iN : t_r;
385 qDebug() <<
"Warning: Rank " << t_r <<
" of the measurement data is smaller than the " <<
m_iN;
386 qDebug() <<
" sources to find.";
387 qDebug() <<
" Searching now for " << t_iMaxSearch <<
" correlated sources.";
394 t_matOrthProj.setIdentity();
398 t_matA_k_1.setZero();
414 p_RapDipoles.clear();
416 qDebug() <<
"##### Calculation of RAP MUSIC started ######\n\n";
418 MatrixXT t_matProj_Phi_s(t_matOrthProj.rows(), t_pMatPhi_s->cols());
422 for (
int r = 0; r < t_iMaxSearch; ++r) {
423 t_matProj_Phi_s = t_matOrthProj * (*t_pMatPhi_s);
430 Eigen::JacobiSVD<MatrixXT> t_svdProj_Phi_S(t_matProj_Phi_s, Eigen::ComputeThinU);
432 useFullRank(t_svdProj_Phi_S.matrixU(), t_svdProj_Phi_S.singularValues().asDiagonal(), t_matU_B);
440 clock_t start_subcorr, end_subcorr;
441 start_subcorr = clock();
445#pragma omp parallel num_threads(m_iMaxNumThreads)
454 MatrixX6T t_matProj_G(t_matProj_LeadField.rows(), 6);
482 end_subcorr = clock();
484 float t_fSubcorrElapsedTime = (
static_cast<float>(end_subcorr - start_subcorr) /
static_cast<float>(CLOCKS_PER_SEC)) * 1000.0f;
485 qDebug() <<
"Time Elapsed: " << t_fSubcorrElapsedTime <<
" ms";
490 VectorXT::Index t_iMaxIdx;
492 t_val_roh_k = t_vecRoh.maxCoeff(&t_iMaxIdx);
499 qDebug() <<
"Iteration: " << r + 1 <<
" of " << t_iMaxSearch
500 <<
"; Correlation: " << t_val_roh_k <<
"; Position (Idx+1): " << t_iIdx1 + 1 <<
" - " << t_iIdx2 + 1 <<
"\n\n";
506 MatrixX6T t_matProj_G_k_1(t_matOrthProj.rows(), t_matG_k_1.cols());
507 t_matProj_G_k_1 = t_matOrthProj * t_matG_k_1;
521 qDebug() <<
"Searching stopped, last correlation " << t_val_roh_k;
522 qDebug() <<
" is smaller then the given threshold " <<
m_dThreshold;
536 qDebug() <<
"##### Calculation of RAP MUSIC completed ######";
540 float t_fElapsedTime = (
static_cast<float>(end - start) /
static_cast<float>(CLOCKS_PER_SEC)) * 1000.0f;
541 qDebug() <<
"Total Time Elapsed: " << t_fElapsedTime <<
" ms";
546 return p_SourceEstimate;
555 if (p_matMeasurement.cols() > p_matMeasurement.rows())
558 t_matF =
MatrixXT(p_matMeasurement);
560 Eigen::JacobiSVD<MatrixXT> t_svdF(t_matF, Eigen::ComputeThinU);
562 int t_r =
getRank(t_svdF.singularValues().asDiagonal());
572 memcpy(p_pMatPhi_s->data(), t_svdF.matrixU().data(),
sizeof(
double) *
m_iNumChannels * t_iCols);
584 Matrix6XT t_matU_A_T(6, p_matProj_G.rows());
586 Eigen::JacobiSVD<MatrixXT> t_svdProj_G(p_matProj_G, Eigen::ComputeThinU);
588 t_matSigma_A = t_svdProj_G.singularValues().asDiagonal();
589 t_matU_A_T = t_svdProj_G.matrixU().transpose();
598 MatrixXT t_matCor(t_matU_A_T_full.rows(), p_matU_B.cols());
601 t_matCor = t_matU_A_T_full * p_matU_B;
605 if (t_matCor.cols() > t_matCor.rows()) {
606 MatrixXT t_matCor_H = t_matCor.adjoint();
608 Eigen::JacobiSVD<MatrixXT> t_svdCor_H(t_matCor_H);
610 t_vecSigma_C = t_svdCor_H.singularValues();
612 Eigen::JacobiSVD<MatrixXT> t_svdCor(t_matCor);
614 t_vecSigma_C = t_svdCor.singularValues();
618 double t_dRetSigma_C;
619 t_dRetSigma_C = t_vecSigma_C(0);
624 return t_dRetSigma_C;
637 Eigen::JacobiSVD<MatrixXT> svdOfProj_G(p_matProj_G, Eigen::ComputeThinU | Eigen::ComputeThinV);
639 sigma_A = svdOfProj_G.singularValues().asDiagonal();
640 U_A_T = svdOfProj_G.matrixU().transpose();
641 V_A = svdOfProj_G.matrixV();
650 t_matCor = U_A_T * p_matU_B;
657 if (t_matCor.cols() > t_matCor.rows()) {
659 Cor_H = t_matCor.adjoint();
662 Eigen::JacobiSVD<MatrixXT> svdOfCor_H(
MatrixXT(Cor_H), Eigen::ComputeThinV);
664 U_C = svdOfCor_H.matrixV();
665 sigma_C = svdOfCor_H.singularValues();
667 Eigen::JacobiSVD<MatrixXT> svdOfCor(
MatrixXT(t_matCor), Eigen::ComputeThinU);
669 U_C = svdOfCor.matrixU();
670 sigma_C = svdOfCor.singularValues();
674 sigma_a_inv = sigma_A.inverse();
677 X = (V_A * sigma_a_inv) * U_C;
682 double norm_X = 1 / (X_max.norm());
685 p_vec_phi_k_1 = X_max * norm_X;
692 ret_sigma_C = sigma_C(0);
708 VectorXT t_vec_a_theta_k_1(p_matG_k_1.rows(), 1);
710 t_vec_a_theta_k_1 = p_matG_k_1 * p_matPhi_k_1;
712 p_matA_k_1.block(0, p_iIdxk_1, p_matA_k_1.rows(), 1) = t_vec_a_theta_k_1;
721 MatrixXT t_matA_k_1_tmp(p_matA_k_1.cols(), p_matA_k_1.cols());
722 t_matA_k_1_tmp = p_matA_k_1.adjoint() * p_matA_k_1;
724 int t_size = t_matA_k_1_tmp.cols();
726 while (!t_matA_k_1_tmp.block(0, 0, t_size, t_size).fullPivLu().isInvertible()) {
730 MatrixXT t_matA_k_1_tmp_inv(t_matA_k_1_tmp.rows(), t_matA_k_1_tmp.cols());
731 t_matA_k_1_tmp_inv.setZero();
733 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();
735 t_matA_k_1_tmp = p_matA_k_1 * t_matA_k_1_tmp_inv;
737 MatrixXT t_matA_k_1_tmp2(p_matA_k_1.rows(), p_matA_k_1.rows());
739 t_matA_k_1_tmp2 = t_matA_k_1_tmp * p_matA_k_1.adjoint();
744 p_matOrthProj = I - t_matA_k_1_tmp2;
753 const int p_iNumCombinations,
754 std::vector<Pair>& p_pairIdxCombinations)
const
761#pragma omp parallel num_threads(m_iMaxNumThreads) private(idx1, idx2)
767 for (
int i = 0; i < p_iNumCombinations; ++i) {
770 Pair t_pairCombination;
771 t_pairCombination.
x1 = idx1;
772 t_pairCombination.
x2 = idx2;
774 p_pairIdxCombinations[i] = t_pairCombination;
783 int ii = p_iPoints * (p_iPoints + 1) / 2 - 1 - p_iCurIdx;
784 int K =
static_cast<int>(floor((sqrt(
static_cast<double>(8 * ii + 1)) - 1) / 2));
786 p_iIdx1 = p_iPoints - 1 - K;
788 p_iIdx2 = (p_iCurIdx - p_iPoints * (p_iPoints + 1) / 2 + (K + 1) * (K + 2) / 2) + p_iIdx1;
795 int p_iIdx1,
int p_iIdx2)
797 p_matGainMarix_Pair.block(0, 0, p_matGainMarix.rows(), 3) = p_matGainMarix.block(0, p_iIdx1 * 3, p_matGainMarix.rows(), 3);
799 p_matGainMarix_Pair.block(0, 3, p_matGainMarix.rows(), 3) = p_matGainMarix.block(0, p_iIdx2 * 3, p_matGainMarix.rows(), 3);
811 t_pRapDipolePair.
m_iIdx1 = p_iDipoleIdx1;
812 t_pRapDipolePair.
m_iIdx2 = p_iDipoleIdx2;
822 t_pRapDipolePair.
m_Dipole1.phi_x() = p_vec_phi_k_1[0];
823 t_pRapDipolePair.
m_Dipole1.phi_y() = p_vec_phi_k_1[1];
824 t_pRapDipolePair.
m_Dipole1.phi_z() = p_vec_phi_k_1[2];
826 t_pRapDipolePair.
m_Dipole2.phi_x() = p_vec_phi_k_1[3];
827 t_pRapDipolePair.
m_Dipole2.phi_y() = p_vec_phi_k_1[4];
828 t_pRapDipolePair.
m_Dipole2.phi_z() = p_vec_phi_k_1[5];
832 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.