47#include <Eigen/Eigenvalues>
72 Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>& vectors,
81 int np = dim*(dim+1)/2;
87 for(
int i = 0; i < np; ++i)
88 if (std::fabs(mat[i]) > std::fabs(mat[maxi]))
92 scale = 1.0/mat[maxi];
95 MatrixXd dmat_full = MatrixXd::Zero(dim,dim);
97 for (
int i = 0; i < dim; ++i) {
98 for(
int j = 0; j <= i; ++j) {
99 double val = mat[idx]*scale;
100 dmat_full(i,j) = val;
101 dmat_full(j,i) = val;
105 SelfAdjointEigenSolver<MatrixXd> es;
106 es.compute(dmat_full);
110 lambda = es.eigenvalues() * scale;
111 vectors = es.eigenvectors().transpose().cast<
float>();
122 const QStringList& p_names,
123 const VectorXd& p_cov,
124 const VectorXd& p_cov_diag,
155 QList<FiffDirNode::SPtr> nodes;
162 std::unique_ptr<FiffSparseMatrix> cov_sparse_owner;
164 Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
eigen;
170 std::unique_ptr<MNECovMatrix> res;
175 std::unique_ptr<MNEProjOp> op;
176 std::unique_ptr<MNESssData>
sss;
183 if (nodes.size() == 0) {
184 qWarning(
"No covariance matrix available in %s", name.toUtf8().data());
191 for (k = 0; k < nodes.size(); ++k) {
195 if (*t_pTag->toInt() ==
kind) {
200 if (covnode->isEmpty()) {
201 qWarning(
"Desired covariance matrix not found from %s", name.toUtf8().data());
212 ncov = *t_pTag->toInt();
215 nfree = *t_pTag->toInt();
219 nnames =
names.size();
220 if (nnames !=
ncov) {
221 qCritical(
"Incorrect number of channel names for a covariance matrix");
226 if (!nodes[k]->find_tag(stream,
FIFF_MNE_COV, t_pTag)) {
233 d = t_pTag->toDouble();
234 for (p = 0; p <
ncov; p++)
240 qCritical(
"Sum of covariance matrix elements is zero!");
246 f = t_pTag->toFloat();
247 for (p = 0; p <
ncov; p++)
250 qWarning(
"Illegal data type for covariance matrix");
259 d = t_pTag->toDouble();
260 for (p = 0; p < nn; p++)
262 if (
cov.sum() == 0.0) {
263 qCritical(
"Sum of covariance matrix elements is zero!");
269 f = t_pTag->toFloat();
270 for (p = 0; p < nn; p++)
274 if (!cov_sparse_owner) {
281 const double *lambda_data =
static_cast<const double *
>(t_pTag->toDouble());
282 lambda = Eigen::Map<const Eigen::VectorXd>(lambda_data,
ncov);
288 tmp_eigen = t_pTag->toFloatMatrix().transpose();
289 eigen.resize(tmp_eigen.rows(), tmp_eigen.cols());
290 for (
int r = 0; r < tmp_eigen.rows(); ++r)
291 for (
int c = 0; c < tmp_eigen.cols(); ++c)
292 eigen(r, c) = tmp_eigen(r, c);
313 bads = stream->read_bad_channels(nodes[k]);
316 if (cov_sparse_owner)
318 else if (
cov.size() > 0)
323 qCritical(
"MNECovMatrix::read : covariance matrix data is not defined.");
327 res->eigen = std::move(
eigen);
328 res->lambda = std::move(
lambda);
335 if (res->lambda.size() > 0) {
337 for (k = 0; k < res->ncov; k++, res->nzero++)
338 if (res->lambda[k] > 0)
342 if (op && op->nitems > 0) {
343 res->proj = std::move(op);
346 res->sss = std::move(
sss);
368 res->proj =
proj ?
proj->dup() :
nullptr;
370 res->sss = std::make_unique<MNESssData>(*
sss);
392 if (src.size() == 0) {
393 qCritical(
"Covariance matrix is not diagonal or not decomposed.");
397 for (k = 0; k <
ncov; k++) {
412 VectorXd lambda_local;
413 Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> local_eigen;
415 double magscale,gradscale,eegscale;
416 int nmag,ngrad,neeg,nok;
423 qCritical(
"Channels not classified. Rank cannot be determined.");
426 magscale = gradscale = eegscale = 0.0;
427 nmag = ngrad = neeg = 0;
428 for (k = 0; k <
ncov; k++) {
443 fprintf(stdout,
"\n");
446 magscale = magscale > 0.0 ? sqrt(nmag/magscale) : 0.0;
448 gradscale = gradscale > 0.0 ? sqrt(ngrad/gradscale) : 0.0;
450 eegscale = eegscale > 0.0 ? sqrt(neeg/eegscale) : 0.0;
452 fprintf(stdout,
"%d %g\n",nmag,magscale);
453 fprintf(stdout,
"%d %g\n",ngrad,gradscale);
454 fprintf(stdout,
"%d %g\n",neeg,eegscale);
456 scale_vec.resize(
ncov);
457 for (k = 0; k <
ncov; k++) {
459 scale_vec[k] = magscale;
461 scale_vec[k] = gradscale;
463 scale_vec[k] = eegscale;
468 lambda_local.resize(
ncov);
470 for (j = 0; j <
ncov; j++)
471 for (k = 0; k <= j; k++)
475 for (k = 0; k <
ncov; k++)
476 fprintf(stdout,
"%g ",lambda_local[k]/lambda_local[
ncov-1]);
477 fprintf(stdout,
"\n");
480 for (k =
ncov-1; k >= 0; k--) {
481 if (lambda_local[k] >= rank_threshold*lambda_local[
ncov-1])
486 qInfo(
"\n\tEstimated covariance matrix rank = %d (%g)\n",nok,lambda_local[
ncov-nok]/lambda_local[
ncov-1]);
487 if (use_rank > 0 && use_rank < nok) {
489 qInfo(
"\tUser-selected covariance matrix rank = %d (%g)\n",nok,lambda_local[
ncov-nok]/lambda_local[
ncov-1]);
494 for (j = 0; j <
ncov-nok; j++)
495 lambda_local[j] = 0.0;
497 for (j = 0; j <
ncov; j++) {
499 mne_print_vector(stdout,
nullptr,local_eigen.row(j).data(),
ncov);
501 for (k = 0; k <
ncov; k++)
502 data1(j,k) = sqrt(lambda_local[j])*local_eigen(j,k);
504 MatrixXd data2 = data1.transpose() * data1;
507 for (j = 0; j <
ncov; j++)
508 mne_print_dvector(stdout,
nullptr,data2.row(j).data(),
ncov);
514 for (k = 0; k <
ncov; k++)
515 if (scale_vec[k] > 0.0)
516 scale_vec[k] = 1.0/scale_vec[k];
517 for (j = 0; j <
ncov; j++)
518 for (k = 0; k <= j; k++)
534 float rank_threshold = 1e-6;
542 qInfo(
"\n\tEigenvalue decomposition had been precomputed.\n");
552 if ((rank =
condition(rank_threshold,use_rank)) < 0)
563 for (k = 0; k <
nzero; k++)
569 float meglike,eeglike;
574 meglike = eeglike = 0.0;
575 for (p = 0; p <
ncov; p++) {
577 eeglike += std::fabs(
eigen(k,p));
579 meglike += std::fabs(
eigen(k,p));
581 if (meglike > eeglike)
586 qInfo(
"\t%d MEG and %d EEG-like channels remain in the whitened data\n",nmeg,neeg);
606 return k + j*(j+1)/2;
608 return j + k*(k+1)/2;
619 qCritical(
"Channel information not available in classify_channels");
623 for (k = 0; k <
ncov; k++) {
625 for (p = 0; p < nchan; p++) {
626 if (QString::compare(chs[p].ch_name,
names[k]) == 0) {
648 qWarning(
"Incompatible covariance matrix. Cannot whiten the data.");
653 for (
int k = 0; k < nchan; k++)
654 whitened_data[k] = data[k]*inv[k];
657 Eigen::VectorXf tmp(nchan);
658 for (
int k =
nzero; k < nchan; k++)
659 tmp[k] =
eigen.row(k).dot(data.cast<
float>());
660 for (
int k = 0; k <
nzero; k++)
661 whitened_data[k] = 0.0;
662 for (
int k =
nzero; k < nchan; k++)
663 whitened_data[k] = tmp[k]*inv[k];
679 for (j = 0; j < nkind; j++) {
683 for (j = 0; j <
ncov; j++) {
689 qInfo(
"Average noise-covariance matrix diagonals:");
690 for (j = 0; j < nkind; j++) {
692 sums[j] = sums[j]/nn[j];
694 qInfo(
"\tMagnetometers : %-7.2f fT reg = %-6.2f",1e15*sqrt(sums[j]),regs[j]);
696 qInfo(
"\tPlanar gradiometers : %-7.2f fT/cm reg = %-6.2f",1e13*sqrt(sums[j]),regs[j]);
698 qInfo(
"\tEEG : %-7.2f uV reg = %-6.2f",1e6*sqrt(sums[j]),regs[j]);
699 sums[j] = regs[j]*sums[j];
702 for (j = 0; j <
ncov; j++)
706 qInfo(
"Noise-covariance regularized as requested.");
719 for (k = p = 0; k <
ncov; k++) {
734 const QList<FiffChInfo>& chs)
const
737 Eigen::VectorXd cov_local;
738 Eigen::VectorXd cov_diag_local;
739 QStringList picked_names;
741 std::unique_ptr<MNECovMatrix> res;
744 qCritical(
"No channels specified for picking in pick_chs_omit");
747 if (
names.isEmpty()) {
748 qCritical(
"No names in covariance matrix. Cannot do picking.");
751 Eigen::VectorXi pickVec = Eigen::VectorXi::Constant(new_ncov, -1);
752 for (j = 0; j < new_ncov; j++)
753 for (k = 0; k <
ncov; k++)
754 if (QString::compare(
names[k],new_names[j]) == 0) {
758 for (j = 0; j < new_ncov; j++) {
759 if (pickVec[j] < 0) {
760 qWarning(
"All desired channels not found in the covariance matrix (at least missing %s).", new_names[j].toUtf8().constData());
764 Eigen::VectorXi isMegVec;
766 isMegVec.resize(new_ncov);
767 if (!chs.isEmpty()) {
768 for (j = 0; j < new_ncov; j++)
775 for (j = 0; j < new_ncov; j++)
776 if (new_names[j].startsWith(
"MEG"))
783 cov_diag_local.resize(new_ncov);
784 for (j = 0; j < new_ncov; j++) {
785 cov_diag_local[j] =
cov_diag[pickVec[j]];
786 picked_names.append(
names[pickVec[j]]);
790 cov_local.resize(new_ncov*(new_ncov+1)/2);
791 for (j = 0; j < new_ncov; j++) {
792 picked_names.append(
names[pickVec[j]]);
793 for (k = 0; k <= j; k++) {
796 if (to < 0 || to > new_ncov*(new_ncov+1)/2-1) {
797 qCritical(
"Wrong destination index in pick_chs_omit : %d %d %d",j,k,to);
800 if (from < 0 || from >
ncov*(
ncov+1)/2-1) {
801 qCritical(
"Wrong source index in pick_chs_omit : %d %d %d",pickVec[j],pickVec[k],from);
804 cov_local[to] =
cov[from];
806 if (isMegVec[j] != isMegVec[k])
816 res->proj =
proj ?
proj->dup() :
nullptr;
817 res->sss =
sss ? std::make_unique<MNESssData>(*
sss) :
nullptr;
820 res->ch_class.resize(res->ncov);
821 for (k = 0; k < res->ncov; k++)
822 res->ch_class[k] =
ch_class[pickVec[k]];
#define FIFFV_SSS_JOB_NOTHING
FiffStream class declaration.
FiffTag class declaration, which provides fiff tag I/O and processing methods.
FiffSparseMatrix class declaration.
#define FIFF_MNE_COV_KIND
#define FIFF_MNE_COV_DIAG
#define FIFF_MNE_ROW_NAMES
#define FIFF_MNE_COV_EIGENVALUES
#define FIFF_MNE_COV_NFREE
#define FIFF_MNE_COV_EIGENVECTORS
FiffChInfo class declaration.
MNECovMatrix class declaration.
#define MNE_COV_CH_MEG_MAG
#define MNE_COV_CH_MEG_GRAD
#define MNE_COV_CH_UNKNOWN
MNE SSS Data (MNESssData) class declaration.
MNEProjItem class declaration.
MNEProjOp class declaration.
int mne_decompose_eigen(const VectorXd &mat, VectorXd &lambda, Eigen::Matrix< float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > &vectors, int dim)
Core MNE data structures (source spaces, source estimates, hemispheres).
FIFF file I/O and data structures (raw, epochs, evoked, covariance, forward).
QSharedPointer< FiffDirNode > SPtr
FIFF sparse matrix storage backed by Eigen.
static FiffSparseMatrix::UPtr fiff_get_float_sparse_matrix(const FIFFLIB::FiffTag::UPtr &tag)
QSharedPointer< FiffStream > SPtr
static QStringList split_name_list(QString p_sNameList)
std::unique_ptr< FiffTag > UPtr
Eigen::VectorXd inv_lambda
std::unique_ptr< FIFFLIB::FiffSparseMatrix > cov_sparse
int condition(float rank_threshold, int use_rank)
static std::unique_ptr< MNECovMatrix > create_sparse(int kind, int ncov, const QStringList &names, FIFFLIB::FiffSparseMatrix *cov_sparse)
void regularize(const Eigen::Vector3f ®s)
int decompose_eigen_small(float p_small, int use_rank)
int classify_channels(const QList< FIFFLIB::FiffChInfo > &chs, int nchan)
std::unique_ptr< MNEProjOp > proj
static std::unique_ptr< MNECovMatrix > create_diag(int kind, int ncov, const QStringList &names, const Eigen::VectorXd &cov_diag)
static std::unique_ptr< MNECovMatrix > create_dense(int kind, int ncov, const QStringList &names, const Eigen::VectorXd &cov)
std::unique_ptr< MNECovMatrix > dup() const
MNECovMatrix(int p_kind, int p_ncov, const QStringList &p_names, const Eigen::VectorXd &p_cov, const Eigen::VectorXd &p_cov_diag, FIFFLIB::FiffSparseMatrix *p_cov_sparse)
std::unique_ptr< MNESssData > sss
static std::unique_ptr< MNECovMatrix > read(const QString &name, int kind)
static std::unique_ptr< MNECovMatrix > create(int kind, int ncov, const QStringList &names, const Eigen::VectorXd &cov, const Eigen::VectorXd &cov_diag)
Eigen::Matrix< float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > eigen
static int lt_packed_index(int j, int k)
std::unique_ptr< MNECovMatrix > pick_chs_omit(const QStringList &new_names, int new_ncov, int omit_meg_eeg, const QList< FIFFLIB::FiffChInfo > &chs) const
int whiten_vector(Eigen::Ref< Eigen::VectorXf > data, Eigen::Ref< Eigen::VectorXf > whitened_data, int nchan) const
static std::unique_ptr< MNEProjOp > read_from_node(FIFFLIB::FiffStream::SPtr &stream, const FIFFLIB::FiffDirNode::SPtr &start)
Read all linear projection items from a FIFF tree node.
static std::unique_ptr< MNESssData > read_from_node(QSharedPointer< FIFFLIB::FiffStream > &stream, const QSharedPointer< FIFFLIB::FiffDirNode > &start)