65 const MatrixXd& matData,
66 const MatrixXd& matSourcePos,
69 QList<TrapMusicDipole> dipoles;
71 const int nCh =
static_cast<int>(matLeadField.rows());
72 const int nSrc =
static_cast<int>(matSourcePos.rows());
74 if (nCh == 0 || matData.rows() != nCh || matLeadField.cols() !=
static_cast<Eigen::Index
>(nSrc) * iNOrient) {
75 qWarning() <<
"[InvTrapMusic::compute] Dimension mismatch.";
80 JacobiSVD<MatrixXd> dataSvd(matData, ComputeThinU);
81 const VectorXd& singVals = dataSvd.singularValues();
85 for (
int i = 1; i < singVals.size(); ++i) {
86 if (singVals[i] < singVals[0] * 0.05)
90 nSignal = std::max(nSignal, m_iMaxSources);
91 nSignal = std::min(nSignal,
static_cast<int>(std::min(dataSvd.matrixU().cols(),
static_cast<Index
>(nCh / 2))));
94 MatrixXd signalSubspace = dataSvd.matrixU().leftCols(nSignal);
97 MatrixXd found(nCh, 0);
98 MatrixXd projector = MatrixXd::Identity(nCh, nCh);
100 for (
int iter = 0; iter < m_iMaxSources; ++iter) {
101 MatrixXd projLF = projector * matLeadField;
102 MatrixXd projSS = projector * signalSubspace;
105 const int ssDim =
static_cast<int>(projSS.cols()) - iter;
108 JacobiSVD<MatrixXd> ssSvd(projSS, ComputeThinU);
109 const MatrixXd truncSS = ssSvd.matrixU().leftCols(ssDim);
113 const double bestCorr = correlations.maxCoeff(&bestIdx);
114 if (bestCorr < m_dThreshold)
118 dipole.
sourceIdx =
static_cast<int>(bestIdx);
120 dipole.
position = matSourcePos.row(bestIdx).transpose();
123 const int colStart =
static_cast<int>(bestIdx) * iNOrient;
124 VectorXd orient = VectorXd::Ones(1);
126 const MatrixXd projSrc = projLF.middleCols(colStart, iNOrient);
128 const MatrixXd gram = projSrc.transpose() * projSrc;
129 const MatrixXd fit = projSrc.transpose() * truncSS * truncSS.transpose() * projSrc;
130 GeneralizedSelfAdjointEigenSolver<MatrixXd> ges(fit, gram);
131 orient = ges.eigenvectors().col(iNOrient - 1);
133 dipole.
orientation = Vector3d(orient(0), orient(1), orient(2));
137 dipoles.append(dipole);
140 found.conservativeResize(NoChange, found.cols() + 1);
141 found.col(found.cols() - 1) = matLeadField.middleCols(colStart, iNOrient) * orient;
142 const MatrixXd q = found.householderQr().householderQ() * MatrixXd::Identity(nCh, found.cols());
143 projector = MatrixXd::Identity(nCh, nCh) - q * q.transpose();
152 const MatrixXd& matSignalSubspace,
155 const int nSrcTotal =
static_cast<int>(matLeadField.cols()) / iNOrient;
156 VectorXd correlations(nSrcTotal);
158 for (
int s = 0; s < nSrcTotal; ++s) {
159 const MatrixXd G_s = matLeadField.middleCols(s * iNOrient, iNOrient);
160 if (G_s.norm() <= 1e-15) {
161 correlations[s] = 0.0;
166 JacobiSVD<MatrixXd> gSvd(G_s, ComputeThinU);
167 const VectorXd& sv = gSvd.singularValues();
169 while (rank < sv.size() && sv(rank) > 1e-10 * sv(0))
171 const MatrixXd basis = gSvd.matrixU().leftCols(rank);
172 correlations[s] = JacobiSVD<MatrixXd>(matSignalSubspace.transpose() * basis).singularValues()(0);
static Eigen::VectorXd scanCorrelations(const Eigen::MatrixXd &matLeadField, const Eigen::MatrixXd &matSignalSubspace, int iNOrient)
Compute the MUSIC-type subspace correlation for all source locations.
QList< TrapMusicDipole > compute(const Eigen::MatrixXd &matLeadField, const Eigen::MatrixXd &matData, const Eigen::MatrixXd &matSourcePos, int iNOrient=3) const
Compute TRAP-MUSIC source localization.