v2.0.0
Loading...
Searching...
No Matches
mne_cov_matrix.cpp
Go to the documentation of this file.
1//=============================================================================================================
36
37//=============================================================================================================
38// INCLUDES
39//=============================================================================================================
40
41#include "mne_cov_matrix.h"
42#include "mne_sss_data.h"
43#include "mne_proj_item.h"
44#include "mne_proj_op.h"
45
46#include <Eigen/Core>
47#include <Eigen/Eigenvalues>
49#include <fiff/fiff_ch_info.h>
50#include <fiff/fiff_constants.h>
51#include <fiff/fiff_stream.h>
52#include <fiff/fiff_tag.h>
53
54#include <QFile>
55
56//=============================================================================================================
57// USED NAMESPACES
58//=============================================================================================================
59
60using namespace Eigen;
61using namespace FIFFLIB;
62using namespace MNELIB;
63
64#ifndef FAIL
65#define FAIL -1
66#endif
67
68#ifndef OK
69#define OK 0
70#endif
71
72//============================= mne_decompose.c =============================
73
74int mne_decompose_eigen (const VectorXd& mat,
75 VectorXd& lambda,
76 Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>& vectors,
77 int dim)
78/*
79 * Compute the eigenvalue decomposition of
80 * a symmetric matrix using the LAPACK routines
81 *
82 * 'mat' contains the lower triangle of the matrix
83 */
84{
85 int np = dim*(dim+1)/2;
86 int maxi;
87 double scale;
88
89// idamax workaround begin
90 maxi = 0;
91 for(int i = 0; i < np; ++i)
92 if (std::fabs(mat[i]) > std::fabs(mat[maxi]))
93 maxi = i;
94// idamax workaround end
95
96 scale = 1.0/mat[maxi];
97
98// dspev workaround begin
99 MatrixXd dmat_full = MatrixXd::Zero(dim,dim);
100 int idx = 0;
101 for (int i = 0; i < dim; ++i) {
102 for(int j = 0; j <= i; ++j) {
103 double val = mat[idx]*scale;
104 dmat_full(i,j) = val;
105 dmat_full(j,i) = val;
106 ++idx;
107 }
108 }
109 SelfAdjointEigenSolver<MatrixXd> es;
110 es.compute(dmat_full);
111// dspev workaround end
112
113 scale = 1.0/scale;
114 lambda = es.eigenvalues() * scale;
115 vectors = es.eigenvectors().transpose().cast<float>();
116
117 return 0;
118}
119
120//=============================================================================================================
121// DEFINE MEMBER METHODS
122//=============================================================================================================
123
125 int p_ncov,
126 const QStringList& p_names,
127 const VectorXd& p_cov,
128 const VectorXd& p_cov_diag,
129 FiffSparseMatrix* p_cov_sparse)
130:kind(p_kind)
131,ncov(p_ncov)
132,nfree(1)
133,nproj(0)
134,nzero(0)
135,names(p_names)
136,cov(p_cov)
137,cov_diag(p_cov_diag)
138,cov_sparse(p_cov_sparse)
139,proj(nullptr)
140,sss(nullptr)
141,nbad(0)
142{
143}
144
145//=============================================================================================================
146
150
151//=============================================================================================================
152
153std::unique_ptr<MNECovMatrix> MNECovMatrix::read(const QString& name, int kind)
154{
155 QFile file(name);
156 FiffStream::SPtr stream(new FiffStream(&file));
157
158 FiffTag::UPtr t_pTag;
159 QList<FiffDirNode::SPtr> nodes;
160 FiffDirNode::SPtr covnode;
161
162 QStringList names;
163 int nnames = 0;
164 Eigen::VectorXd cov;
165 Eigen::VectorXd cov_diag;
166 FiffSparseMatrix* cov_sparse = nullptr;
167 Eigen::VectorXd lambda;
168 Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> eigen;
169 MatrixXf tmp_eigen;
170 QStringList bads;
171 int nbad = 0;
172 int ncov = 0;
173 int nfree = 1;
174 std::unique_ptr<MNECovMatrix> res;
175
176 int k,p,nn;
177 float *f;
178 double *d;
179 std::unique_ptr<MNEProjOp> op;
180 std::unique_ptr<MNESssData> sss;
181
182 if (!stream->open())
183 return nullptr;
184
185 nodes = stream->dirtree()->dir_tree_find(FIFFB_MNE_COV);
186
187 if (nodes.size() == 0) {
188 qWarning("No covariance matrix available in %s", name.toUtf8().data());
189 stream->close();
190 return nullptr;
191 }
192 /*
193 * Locate the desired matrix
194 */
195 for (k = 0; k < nodes.size(); ++k) {
196 if (!nodes[k]->find_tag(stream, FIFF_MNE_COV_KIND, t_pTag))
197 continue;
198
199 if (*t_pTag->toInt() == kind) {
200 covnode = nodes[k];
201 break;
202 }
203 }
204 if (covnode->isEmpty()) {
205 qWarning("Desired covariance matrix not found from %s", name.toUtf8().data());
206 stream->close();
207 return nullptr;
208 }
209 /*
210 * Read the data
211 */
212 if (!nodes[k]->find_tag(stream, FIFF_MNE_COV_DIM, t_pTag)) {
213 stream->close();
214 return nullptr;
215 }
216 ncov = *t_pTag->toInt();
217
218 if (nodes[k]->find_tag(stream, FIFF_MNE_COV_NFREE, t_pTag)) {
219 nfree = *t_pTag->toInt();
220 }
221 if (covnode->find_tag(stream, FIFF_MNE_ROW_NAMES, t_pTag)) {
222 names = FiffStream::split_name_list(t_pTag->toString());
223 nnames = names.size();
224 if (nnames != ncov) {
225 qCritical("Incorrect number of channel names for a covariance matrix");
226 stream->close();
227 return nullptr;
228 }
229 }
230 if (!nodes[k]->find_tag(stream, FIFF_MNE_COV, t_pTag)) {
231 if (!nodes[k]->find_tag(stream, FIFF_MNE_COV_DIAG, t_pTag)) {
232 stream->close();
233 return nullptr;
234 } else {
235 if (t_pTag->getType() == FIFFT_DOUBLE) {
236 cov_diag.resize(ncov);
237 d = t_pTag->toDouble();
238 for (p = 0; p < ncov; p++)
239 cov_diag[p] = d[p];
240 /*
241 * Check for all-zero data
242 */
243 if (cov_diag.sum() == 0.0) {
244 qCritical("Sum of covariance matrix elements is zero!");
245 stream->close();
246 return nullptr;
247 }
248 } else if (t_pTag->getType() == FIFFT_FLOAT) {
249 cov_diag.resize(ncov);
250 f = t_pTag->toFloat();
251 for (p = 0; p < ncov; p++)
252 cov_diag[p] = f[p];
253 } else {
254 qWarning("Illegal data type for covariance matrix");
255 stream->close();
256 return nullptr;
257 }
258 }
259 } else {
260 nn = ncov * (ncov + 1) / 2;
261 if (t_pTag->getType() == FIFFT_DOUBLE) {
262 cov.resize(nn);
263 d = t_pTag->toDouble();
264 for (p = 0; p < nn; p++)
265 cov[p] = d[p];
266 if (cov.sum() == 0.0) {
267 qCritical("Sum of covariance matrix elements is zero!");
268 stream->close();
269 return nullptr;
270 }
271 } else if (t_pTag->getType() == FIFFT_FLOAT) {
272 cov.resize(nn);
273 f = t_pTag->toFloat();
274 for (p = 0; p < nn; p++)
275 cov[p] = f[p];
276 } else {
277 auto cov_sparse_uptr = FiffSparseMatrix::fiff_get_float_sparse_matrix(t_pTag);
278 if (!cov_sparse_uptr) {
279 stream->close();
280 return nullptr;
281 }
282 cov_sparse = cov_sparse_uptr.release();
283 }
284
285 if (nodes[k]->find_tag(stream, FIFF_MNE_COV_EIGENVALUES, t_pTag)) {
286 const double *lambda_data = static_cast<const double *>(t_pTag->toDouble());
287 lambda = Eigen::Map<const Eigen::VectorXd>(lambda_data, ncov);
288 if (nodes[k]->find_tag(stream, FIFF_MNE_COV_EIGENVECTORS, t_pTag)) {
289 stream->close();
290 delete cov_sparse;
291 return nullptr;
292 }
293
294 tmp_eigen = t_pTag->toFloatMatrix().transpose();
295 eigen.resize(tmp_eigen.rows(), tmp_eigen.cols());
296 for (int r = 0; r < tmp_eigen.rows(); ++r)
297 for (int c = 0; c < tmp_eigen.cols(); ++c)
298 eigen(r, c) = tmp_eigen(r, c);
299 }
300 /*
301 * Read the optional projection operator
302 */
303 op.reset(MNEProjOp::read_from_node(stream, nodes[k]));
304 if (!op) {
305 stream->close();
306 delete cov_sparse;
307 return nullptr;
308 }
309 /*
310 * Read the optional SSS data
311 */
312 sss.reset(MNESssData::read_from_node(stream, nodes[k]));
313 if (!sss) {
314 stream->close();
315 delete cov_sparse;
316 return nullptr;
317 }
318 /*
319 * Read the optional bad channel list
320 */
321 bads = stream->read_bad_channels(nodes[k]);
322 nbad = bads.size();
323 }
324 if (cov_sparse)
326 else if (cov.size() > 0)
327 res = create_dense(kind, ncov, names, cov);
328 else if (cov_diag.size() > 0)
330 else {
331 qCritical("MNECovMatrix::read : covariance matrix data is not defined.");
332 stream->close();
333 return nullptr;
334 }
335 cov_sparse = nullptr;
336 res->eigen = std::move(eigen);
337 res->lambda = std::move(lambda);
338 res->nfree = nfree;
339 res->bads = bads;
340 res->nbad = nbad;
341 /*
342 * Count the non-zero eigenvalues
343 */
344 if (res->lambda.size() > 0) {
345 res->nzero = 0;
346 for (k = 0; k < res->ncov; k++, res->nzero++)
347 if (res->lambda[k] > 0)
348 break;
349 }
350
351 if (op && op->nitems > 0) {
352 res->proj = std::move(op);
353 }
354 if (sss && sss->comp_info.size() > 0 && sss->job != FIFFV_SSS_JOB_NOTHING) {
355 res->sss = std::move(sss);
356 }
357
358 stream->close();
359 return res;
360}
361
362//=============================================================================================================
363
364std::unique_ptr<MNECovMatrix> MNECovMatrix::dup() const
365{
366 auto res = cov_diag.size() > 0
367 ? create(kind,ncov,names,VectorXd(),VectorXd(cov_diag))
368 : create(kind,ncov,names,VectorXd(cov),VectorXd());
369 /*
370 * Duplicate additional items
371 */
372 if (ch_class.size() > 0) {
373 res->ch_class = ch_class;
374 }
375 res->bads = bads;
376 res->nbad = nbad;
377 res->proj.reset(proj ? proj->dup() : nullptr);
378 if (sss)
379 res->sss = std::make_unique<MNESssData>(*sss);
380
381 return res;
382}
383
384//=============================================================================================================
385
387{
388 return cov_diag.size() > 0;
389}
390
391//=============================================================================================================
392
394/*
395 * Calculate the inverse square roots for whitening
396 */
397{
398 const VectorXd& src = lambda.size() > 0 ? lambda : cov_diag;
399 int k;
400
401 if (src.size() == 0) {
402 qCritical("Covariance matrix is not diagonal or not decomposed.");
403 return FAIL;
404 }
405 inv_lambda.resize(ncov);
406 for (k = 0; k < ncov; k++) {
407 if (src[k] <= 0.0)
408 inv_lambda[k] = 0.0;
409 else
410 inv_lambda[k] = 1.0/sqrt(src[k]);
411 }
412 return OK;
413}
414
415//=============================================================================================================
416
417int MNECovMatrix::condition(float rank_threshold, int use_rank)
418{
419 VectorXd scale_vec;
420 VectorXd cov_local;
421 VectorXd lambda_local;
422 Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> local_eigen;
423 MatrixXd data1;
424 double magscale,gradscale,eegscale;
425 int nmag,ngrad,neeg,nok;
426 int j,k;
427 int res = FAIL;
428
429 if (cov_diag.size() > 0)
430 return OK;
431 if (ch_class.size() == 0) {
432 qCritical("Channels not classified. Rank cannot be determined.");
433 return FAIL;
434 }
435 magscale = gradscale = eegscale = 0.0;
436 nmag = ngrad = neeg = 0;
437 for (k = 0; k < ncov; k++) {
438 if (ch_class[k] == MNE_COV_CH_MEG_MAG) {
439 magscale += this->cov[lt_packed_index(k,k)]; nmag++;
440 }
441 else if (ch_class[k] == MNE_COV_CH_MEG_GRAD) {
442 gradscale += this->cov[lt_packed_index(k,k)]; ngrad++;
443 }
444 else if (ch_class[k] == MNE_COV_CH_EEG) {
445 eegscale += this->cov[lt_packed_index(k,k)]; neeg++;
446 }
447#ifdef DEBUG
448 fprintf(stdout,"%d ",ch_class[k]);
449#endif
450 }
451#ifdef DEBUG
452 fprintf(stdout,"\n");
453#endif
454 if (nmag > 0)
455 magscale = magscale > 0.0 ? sqrt(nmag/magscale) : 0.0;
456 if (ngrad > 0)
457 gradscale = gradscale > 0.0 ? sqrt(ngrad/gradscale) : 0.0;
458 if (neeg > 0)
459 eegscale = eegscale > 0.0 ? sqrt(neeg/eegscale) : 0.0;
460#ifdef DEBUG
461 fprintf(stdout,"%d %g\n",nmag,magscale);
462 fprintf(stdout,"%d %g\n",ngrad,gradscale);
463 fprintf(stdout,"%d %g\n",neeg,eegscale);
464#endif
465 scale_vec.resize(ncov);
466 for (k = 0; k < ncov; k++) {
468 scale_vec[k] = magscale;
469 else if (ch_class[k] == MNE_COV_CH_MEG_GRAD)
470 scale_vec[k] = gradscale;
471 else if (ch_class[k] == MNE_COV_CH_EEG)
472 scale_vec[k] = eegscale;
473 else
474 scale_vec[k] = 1.0;
475 }
476 cov_local.resize(ncov*(ncov+1)/2);
477 lambda_local.resize(ncov);
478 local_eigen.resize(ncov,ncov);
479 for (j = 0; j < ncov; j++)
480 for (k = 0; k <= j; k++)
481 cov_local[lt_packed_index(j,k)] = this->cov[lt_packed_index(j,k)]*scale_vec[j]*scale_vec[k];
482 if (mne_decompose_eigen(cov_local,lambda_local,local_eigen,ncov) == 0) {
483#ifdef DEBUG
484 for (k = 0; k < ncov; k++)
485 fprintf(stdout,"%g ",lambda_local[k]/lambda_local[ncov-1]);
486 fprintf(stdout,"\n");
487#endif
488 nok = 0;
489 for (k = ncov-1; k >= 0; k--) {
490 if (lambda_local[k] >= rank_threshold*lambda_local[ncov-1])
491 nok++;
492 else
493 break;
494 }
495 printf("\n\tEstimated covariance matrix rank = %d (%g)\n",nok,lambda_local[ncov-nok]/lambda_local[ncov-1]);
496 if (use_rank > 0 && use_rank < nok) {
497 nok = use_rank;
498 printf("\tUser-selected covariance matrix rank = %d (%g)\n",nok,lambda_local[ncov-nok]/lambda_local[ncov-1]);
499 }
500 /*
501 * Put it back together
502 */
503 for (j = 0; j < ncov-nok; j++)
504 lambda_local[j] = 0.0;
505 data1.resize(ncov,ncov);
506 for (j = 0; j < ncov; j++) {
507#ifdef DEBUG
508 mne_print_vector(stdout,NULL,local_eigen.row(j).data(),ncov);
509#endif
510 for (k = 0; k < ncov; k++)
511 data1(j,k) = sqrt(lambda_local[j])*local_eigen(j,k);
512 }
513 MatrixXd data2 = data1.transpose() * data1;
514#ifdef DEBUG
515 printf(">>>\n");
516 for (j = 0; j < ncov; j++)
517 mne_print_dvector(stdout,NULL,data2.row(j).data(),ncov);
518 printf(">>>\n");
519#endif
520 /*
521 * Scale back
522 */
523 for (k = 0; k < ncov; k++)
524 if (scale_vec[k] > 0.0)
525 scale_vec[k] = 1.0/scale_vec[k];
526 for (j = 0; j < ncov; j++)
527 for (k = 0; k <= j; k++)
528 if (this->cov[lt_packed_index(j,k)] != 0.0)
529 this->cov[lt_packed_index(j,k)] = scale_vec[j]*scale_vec[k]*data2(j,k);
530 res = nok;
531 }
532 return res;
533}
534
535//=============================================================================================================
536
537int MNECovMatrix::decompose_eigen_small(float p_small, int use_rank)
538/*
539 * Do the eigenvalue decomposition
540 */
541{
542 int k,p,rank;
543 float rank_threshold = 1e-6;
544
545 if (p_small < 0)
546 p_small = 1.0;
547
548 if (cov_diag.size() > 0)
549 return add_inv();
550 if (lambda.size() > 0 && eigen.size() > 0) {
551 printf("\n\tEigenvalue decomposition had been precomputed.\n");
552 nzero = 0;
553 for (k = 0; k < ncov; k++, nzero++)
554 if (lambda[k] > 0)
555 break;
556 }
557 else {
558 lambda.resize(0);
559 eigen.resize(0,0);
560
561 if ((rank = condition(rank_threshold,use_rank)) < 0)
562 return FAIL;
563
564 lambda.resize(ncov);
565 eigen.resize(ncov,ncov);
567 goto bad;
568 nzero = ncov - rank;
569 for (k = 0; k < nzero; k++)
570 lambda[k] = 0.0;
571 /*
572 * Find which eigenvectors correspond to EEG/MEG
573 */
574 {
575 float meglike,eeglike;
576 int nmeg,neeg;
577
578 nmeg = neeg = 0;
579 for (k = nzero; k < ncov; k++) {
580 meglike = eeglike = 0.0;
581 for (p = 0; p < ncov; p++) {
582 if (ch_class[p] == MNE_COV_CH_EEG)
583 eeglike += std::fabs(eigen(k,p));
585 meglike += std::fabs(eigen(k,p));
586 }
587 if (meglike > eeglike)
588 nmeg++;
589 else
590 neeg++;
591 }
592 printf("\t%d MEG and %d EEG-like channels remain in the whitened data\n",nmeg,neeg);
593 }
594 }
595 return add_inv();
596
597bad : {
598 lambda.resize(0);
599 eigen.resize(0,0);
600 return FAIL;
601 }
602}
603
604//=============================================================================================================
605
607
608{
609 return decompose_eigen_small(-1.0,-1);
610}
611
612//=============================================================================================================
613
615
616{
617 if (j >= k)
618 return k + j*(j+1)/2;
619 else
620 return j + k*(k+1)/2;
621}
622
623//=============================================================================================================
624
625int MNECovMatrix::classify_channels(const QList<FiffChInfo>& chs, int nchan)
626{
627 int k,p;
628 FiffChInfo ch;
629
630 if (chs.isEmpty()) {
631 qCritical("Channel information not available in classify_channels");
632 return FAIL;
633 }
634 ch_class.resize(ncov);
635 for (k = 0; k < ncov; k++) {
637 for (p = 0; p < nchan; p++) {
638 if (QString::compare(chs[p].ch_name,names[k]) == 0) {
639 ch = chs[p];
640 if (ch.kind == FIFFV_MEG_CH) {
641 if (ch.unit == FIFF_UNIT_T)
643 else
645 }
646 else if (ch.kind == FIFFV_EEG_CH)
648 break;
649 }
650 }
651 }
652 return OK;
653}
654
655//=============================================================================================================
656
657int MNECovMatrix::whiten_vector(Eigen::Ref<Eigen::VectorXf> data, Eigen::Ref<Eigen::VectorXf> whitened_data, int nchan) const
658{
659 if (ncov != nchan) {
660 qWarning("Incompatible covariance matrix. Cannot whiten the data.");
661 return FAIL;
662 }
663 const double *inv = inv_lambda.data();
664 if (is_diag()) {
665 for (int k = 0; k < nchan; k++)
666 whitened_data[k] = data[k]*inv[k];
667 }
668 else {
669 std::vector<float> tmp(nchan);
670 for (int k = nzero; k < nchan; k++)
671 tmp[k] = eigen.row(k).dot(data.cast<float>());
672 for (int k = 0; k < nzero; k++)
673 whitened_data[k] = 0.0;
674 for (int k = nzero; k < nchan; k++)
675 whitened_data[k] = tmp[k]*inv[k];
676 }
677 return OK;
678}
679
680//=============================================================================================================
681
682void MNECovMatrix::regularize(const Eigen::Vector3f& regs)
683{
684 int j;
685 float sums[3],nn[3];
686 int nkind = 3;
687
688 if (cov.size() == 0 || ch_class.size() == 0)
689 return;
690
691 for (j = 0; j < nkind; j++) {
692 sums[j] = 0.0;
693 nn[j] = 0;
694 }
695 for (j = 0; j < ncov; j++) {
696 if (ch_class[j] >= 0) {
697 sums[ch_class[j]] += cov[lt_packed_index(j,j)];
698 nn[ch_class[j]]++;
699 }
700 }
701 qInfo("Average noise-covariance matrix diagonals:");
702 for (j = 0; j < nkind; j++) {
703 if (nn[j] > 0) {
704 sums[j] = sums[j]/nn[j];
705 if (j == MNE_COV_CH_MEG_MAG)
706 qInfo("\tMagnetometers : %-7.2f fT reg = %-6.2f",1e15*sqrt(sums[j]),regs[j]);
707 else if (j == MNE_COV_CH_MEG_GRAD)
708 qInfo("\tPlanar gradiometers : %-7.2f fT/cm reg = %-6.2f",1e13*sqrt(sums[j]),regs[j]);
709 else
710 qInfo("\tEEG : %-7.2f uV reg = %-6.2f",1e6*sqrt(sums[j]),regs[j]);
711 sums[j] = regs[j]*sums[j];
712 }
713 }
714 for (j = 0; j < ncov; j++)
715 if (ch_class[j] >= 0)
716 cov[lt_packed_index(j,j)] += sums[ch_class[j]];
717
718 qInfo("Noise-covariance regularized as requested.");
719}
720
721//=============================================================================================================
722
724{
725 int k,p;
726 if (cov.size() == 0)
727 return;
728
729 cov_diag.resize(ncov);
730
731 for (k = p = 0; k < ncov; k++) {
732 cov_diag[k] = cov[p];
733 p = p + k + 2;
734 }
735 cov.resize(0);
736
737 lambda.resize(0);
738 eigen.resize(0,0);
739}
740
741//=============================================================================================================
742
743std::unique_ptr<MNECovMatrix> MNECovMatrix::pick_chs_omit(const QStringList& new_names,
744 int new_ncov,
745 int omit_meg_eeg,
746 const QList<FiffChInfo>& chs) const
747{
748 int j,k;
749 int *pick = nullptr;
750 Eigen::VectorXd cov_local;
751 Eigen::VectorXd cov_diag_local;
752 QStringList picked_names;
753 int *is_meg = nullptr;
754 int from,to;
755 std::unique_ptr<MNECovMatrix> res;
756
757 if (new_ncov == 0) {
758 qCritical("No channels specified for picking in pick_chs_omit");
759 return nullptr;
760 }
761 if (names.isEmpty()) {
762 qCritical("No names in covariance matrix. Cannot do picking.");
763 return nullptr;
764 }
765 std::vector<int> pickVec(new_ncov, -1);
766 pick = pickVec.data();
767 for (j = 0; j < new_ncov; j++)
768 for (k = 0; k < ncov; k++)
769 if (QString::compare(names[k],new_names[j]) == 0) {
770 pick[j] = k;
771 break;
772 }
773 for (j = 0; j < new_ncov; j++) {
774 if (pick[j] < 0) {
775 qWarning("All desired channels not found in the covariance matrix (at least missing %s).", new_names[j].toUtf8().constData());
776 return nullptr;
777 }
778 }
779 std::vector<int> isMegVec;
780 if (omit_meg_eeg) {
781 isMegVec.resize(new_ncov);
782 is_meg = isMegVec.data();
783 if (!chs.isEmpty()) {
784 for (j = 0; j < new_ncov; j++)
785 if (chs[j].kind == FIFFV_MEG_CH)
786 is_meg[j] = true;
787 else
788 is_meg[j] = false;
789 }
790 else {
791 for (j = 0; j < new_ncov; j++)
792 if (new_names[j].startsWith("MEG"))
793 is_meg[j] = true;
794 else
795 is_meg[j] = false;
796 }
797 }
798 if (cov_diag.size() > 0) {
799 cov_diag_local.resize(new_ncov);
800 for (j = 0; j < new_ncov; j++) {
801 cov_diag_local[j] = cov_diag[pick[j]];
802 picked_names.append(names[pick[j]]);
803 }
804 }
805 else {
806 cov_local.resize(new_ncov*(new_ncov+1)/2);
807 for (j = 0; j < new_ncov; j++) {
808 picked_names.append(names[pick[j]]);
809 for (k = 0; k <= j; k++) {
810 from = lt_packed_index(pick[j],pick[k]);
811 to = lt_packed_index(j,k);
812 if (to < 0 || to > new_ncov*(new_ncov+1)/2-1) {
813 qCritical("Wrong destination index in pick_chs_omit : %d %d %d",j,k,to);
814 return nullptr;
815 }
816 if (from < 0 || from > ncov*(ncov+1)/2-1) {
817 qCritical("Wrong source index in pick_chs_omit : %d %d %d",pick[j],pick[k],from);
818 return nullptr;
819 }
820 cov_local[to] = cov[from];
821 if (omit_meg_eeg)
822 if (is_meg[j] != is_meg[k])
823 cov_local[to] = 0.0;
824 }
825 }
826 }
827
828 res = MNECovMatrix::create(kind,new_ncov,picked_names,cov_local,cov_diag_local);
829
830 res->bads = bads;
831 res->nbad = nbad;
832 res->proj.reset(proj ? proj->dup() : nullptr);
833 res->sss.reset(sss ? new MNESssData(*sss) : nullptr);
834
835 if (ch_class.size() > 0) {
836 res->ch_class.resize(res->ncov);
837 for (k = 0; k < res->ncov; k++)
838 res->ch_class[k] = ch_class[pick[k]];
839 }
840 return res;
841}
#define OK
#define FAIL
FiffTag class declaration, which provides fiff tag I/O and processing methods.
Fiff constants.
#define FIFF_MNE_COV_KIND
#define FIFFV_EEG_CH
#define FIFF_MNE_COV
#define FIFF_MNE_COV_DIAG
#define FIFF_MNE_ROW_NAMES
#define FIFF_MNE_COV_EIGENVALUES
#define FIFFV_MEG_CH
#define FIFFB_MNE_COV
#define FIFF_MNE_COV_NFREE
#define FIFF_MNE_COV_EIGENVECTORS
#define FIFF_UNIT_T
#define FIFF_MNE_COV_DIM
FiffStream class declaration.
FiffChInfo class declaration.
#define FIFFT_DOUBLE
Definition fiff_file.h:233
#define FIFFT_FLOAT
Definition fiff_file.h:232
#define FIFFV_SSS_JOB_NOTHING
Definition fiff_file.h:538
FiffSparseMatrix class declaration.
MNECovMatrix class declaration.
#define MNE_COV_CH_MEG_MAG
#define MNE_COV_CH_EEG
#define MNE_COV_CH_MEG_GRAD
#define MNE_COV_CH_UNKNOWN
MNEProjOp class declaration.
MNEProjItem class declaration.
int mne_decompose_eigen(const VectorXd &mat, VectorXd &lambda, Eigen::Matrix< float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > &vectors, int dim)
MNE SSS Data (MNESssData) class declaration.
Core MNE data structures (source spaces, source estimates, hemispheres).
FIFF file I/O and data structures (raw, epochs, evoked, covariance, forward).
Channel info descriptor.
QSharedPointer< FiffDirNode > SPtr
FIFF sparse matrix storage.
static FiffSparseMatrix::UPtr fiff_get_float_sparse_matrix(const FIFFLIB::FiffTag::UPtr &tag)
FIFF File I/O routines.
QSharedPointer< FiffStream > SPtr
static QStringList split_name_list(QString p_sNameList)
std::unique_ptr< FiffTag > UPtr
Definition fiff_tag.h:158
Eigen::VectorXd inv_lambda
std::unique_ptr< FIFFLIB::FiffSparseMatrix > cov_sparse
Eigen::VectorXd lambda
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 &regs)
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
Eigen::VectorXd cov
Eigen::VectorXd cov_diag
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
Eigen::VectorXi ch_class
int whiten_vector(Eigen::Ref< Eigen::VectorXf > data, Eigen::Ref< Eigen::VectorXf > whitened_data, int nchan) const
static MNEProjOp * read_from_node(FIFFLIB::FiffStream::SPtr &stream, const FIFFLIB::FiffDirNode::SPtr &start)
Read all linear projection items from a FIFF tree node.
Container for Signal Space Separation (SSS/Maxwell filtering) expansion coefficients and metadata.
static MNESssData * read_from_node(QSharedPointer< FIFFLIB::FiffStream > &stream, const QSharedPointer< FIFFLIB::FiffDirNode > &start)