110 for (
int k = 0; k < from->
nitems; k++) {
111 const auto& it = from->
items[k];
112 add_item(it.vecs.get(),it.kind,it.desc);
127 auto& new_item =
items.back();
129 new_item.active = is_active;
130 new_item.vecs = std::make_unique<MNENamedMatrix>(*vecs);
133 new_item.has_meg =
false;
134 new_item.has_eeg =
true;
137 for (
int k = 0; k < vecs->
ncol; k++) {
138 if (vecs->
collist[k].contains(
"EEG"))
139 new_item.has_eeg =
true;
140 if (vecs->
collist[k].contains(
"MEG"))
141 new_item.has_meg =
true;
143 if (!new_item.has_meg && !new_item.has_eeg) {
144 new_item.has_meg =
true;
145 new_item.has_eeg =
false;
147 else if (new_item.has_meg && new_item.has_eeg) {
148 new_item.has_meg =
true;
149 new_item.has_eeg =
false;
153 new_item.desc = desc;
154 new_item.kind = kind;
155 new_item.nvec = new_item.vecs->nrow;
177 auto res = std::make_unique<MNEProjOp>();
179 for (
int k = 0; k <
nitems; k++) {
180 const auto& it =
items[k];
181 res->add_item_active(it.vecs.get(),it.kind,it.desc,it.active);
182 res->items[k].active_file = it.active_file;
198 for (k = 0; k <
nch; k++)
202 qCritical(
"No EEG channels specified for average reference.");
206 for (k = 0; k <
nch; k++)
208 names.append(chs.at(k).ch_name);
210 Eigen::MatrixXf vec_data = Eigen::MatrixXf::Constant(1, eegcount, 1.0f/sqrt(
static_cast<double>(eegcount)));
212 QStringList emptyList;
215 auto op = std::make_unique<MNEProjOp>();
228 for (k = 0, naff = 0; k <
nitems; k++)
230 naff +=
items[k].nvec;
243 for (
int k = 0; k <
nch; k++)
244 list.append(chs.at(k).ch_name);
259 if (
nch !=
static_cast<int>(vec.size())) {
260 qCritical(
"Data vector size does not match projection operator");
264 Eigen::VectorXf proj = Eigen::VectorXf::Zero(
nch);
266 for (
int p = 0; p < this->
nvec; p++) {
268 float w = row.dot(vec);
269 proj += w * row.transpose();
287 QList<FiffDirNode::SPtr> proj;
289 QList<FiffDirNode::SPtr>
items;
292 QString item_desc,desc_tag;
293 int global_nchan,item_nchan;
294 QStringList item_names;
301 qCritical(
"File not open read_from_node");
305 if (!start || start->isEmpty())
306 start_node = stream->dirtree();
310 auto op = std::make_unique<MNEProjOp>();
312 if (proj.size() == 0 || proj[0]->isEmpty())
324 if(!node->find_tag(stream,
FIFF_NCHAN, t_pTag))
327 global_nchan = *t_pTag->toInt();
333 for (k = 0; k <
items.size(); k++) {
340 if (node->find_tag(stream,
FIFF_NAME, t_pTag)) {
341 item_desc += t_pTag->toString();
348 desc_tag = t_pTag->toString();
350 if((pos = desc_tag.indexOf(
"\n")) >= 0)
351 desc_tag.truncate(pos);
352 if (!item_desc.isEmpty())
354 item_desc += desc_tag;
359 if (!node->find_tag(stream,
FIFF_NCHAN, t_pTag)) {
360 item_nchan = global_nchan;
363 item_nchan = *t_pTag->toInt();
365 if (item_nchan <= 0) {
366 qCritical(
"Number of channels incorrectly specified for one of the projection items.");
378 if (item_names.size() != item_nchan) {
379 qCritical(
"Channel name list incorrectly specified for proj item # %d",k+1);
389 item_kind = *t_pTag->toInt();
396 item_nvec = *t_pTag->toInt();
404 MatrixXf item_vectors = t_pTag->toFloatMatrix().transpose();
410 item_active = *t_pTag->toInt();
417 QStringList emptyList;
419 op->add_item_active(item.get(),item_kind,item_desc,item_active);
420 op->items[op->nitems-1].active_file = item_active;
456 out <<
"Empty operator\n";
460 for (
int k = 0; k <
nitems; k++) {
461 const auto& it =
items[k];
462 if (list_data && !tag.isEmpty())
466 out <<
"# " << (k+1) <<
" : " << it.desc <<
" : " << it.nvec <<
" vecs : " << it.vecs->ncol <<
" chs "
467 << (it.has_meg ?
"MEG" :
"EEG") <<
" "
468 << (it.active ?
"active" :
"idle") <<
"\n";
469 if (list_data && !tag.isEmpty())
472 vecs =
items[k].vecs.get();
474 for (q = 0; q < vecs->
ncol; q++) {
475 out << qSetFieldWidth(10) << Qt::left << vecs->
collist[q] << qSetFieldWidth(0);
476 out << (q < vecs->
ncol-1 ?
" " :
"\n");
478 for (p = 0; p < vecs->
nrow; p++)
479 for (q = 0; q < vecs->
ncol; q++) {
480 found = exclude.contains(vecs->
collist[q]);
481 out << qSetFieldWidth(10) << qSetRealNumberPrecision(5) << Qt::forcepoint
482 << (found ? 0.0 : vecs->
data(p, q)) << qSetFieldWidth(0) <<
" ";
483 out << (q < vecs->
ncol-1 ?
" " :
"\n");
485 if (list_data && !tag.isEmpty())
518void clear_channel_group(Eigen::Ref<Eigen::VectorXf> data,
const QStringList& ch_names,
int nnames,
const QString& prefix)
520 for (
int k = 0; k < nnames; k++)
521 if (ch_names[k].contains(prefix))
525constexpr float USE_LIMIT = 1e-5f;
526constexpr float SMALL_VALUE = 1e-4f;
532 using RowMatrixXf = Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
534 int k,p,q,r,nvec_total;
535 RowMatrixXf vv_meg_mat;
536 Eigen::VectorXf sing_meg_vec;
537 RowMatrixXf vv_eeg_mat;
538 Eigen::VectorXf sing_eeg_vec;
557 RowMatrixXf mat_meg_mat = RowMatrixXf::Zero(nvec_total,
nch);
558 RowMatrixXf mat_eeg_mat = RowMatrixXf::Zero(nvec_total,
nch);
560 for (k = 0, nvec_meg = nvec_eeg = 0; k <
nitems; k++) {
564 if (
items[k].has_meg) {
565 for (p = 0; p <
items[k].nvec; p++, nvec_meg++) {
567 Eigen::Map<Eigen::VectorXf> res_meg(mat_meg_mat.row(nvec_meg).data(),
nch);
572 else if (
items[k].has_eeg) {
573 for (p = 0; p <
items[k].nvec; p++, nvec_eeg++) {
575 Eigen::Map<Eigen::VectorXf> res_eeg(mat_eeg_mat.row(nvec_eeg).data(),
nch);
585 for (q = 0; q < bad.size(); q++)
586 for (r = 0; r <
nch; r++)
587 if (
names[r] == bad[q]) {
588 for (p = 0; p < nvec_meg; p++)
589 mat_meg_mat(p,r) = 0.0;
590 for (p = 0; p < nvec_eeg; p++)
591 mat_eeg_mat(p,r) = 0.0;
596 for (p = 0, nzero = 0; p < nvec_meg; p++) {
597 size = mat_meg_mat.row(p).norm();
599 mat_meg_mat.row(p) /= size;
604 if (nzero == nvec_meg) {
605 mat_meg_mat.resize(0, 0); nvec_meg = 0;
607 for (p = 0, nzero = 0; p < nvec_eeg; p++) {
608 size = mat_eeg_mat.row(p).norm();
610 mat_eeg_mat.row(p) /= size;
615 if (nzero == nvec_eeg) {
616 mat_eeg_mat.resize(0, 0); nvec_eeg = 0;
618 if (nvec_meg + nvec_eeg == 0) {
619 qWarning(
"No projection remains after excluding bad channels. Omitting projection.");
626 Eigen::JacobiSVD<Eigen::MatrixXf> svd(mat_meg_mat.topRows(nvec_meg), Eigen::ComputeFullV);
627 sing_meg_vec = svd.singularValues();
628 vv_meg_mat = svd.matrixV().transpose().topRows(nvec_meg);
631 Eigen::JacobiSVD<Eigen::MatrixXf> svd(mat_eeg_mat.topRows(nvec_eeg), Eigen::ComputeFullV);
632 sing_eeg_vec = svd.singularValues();
633 vv_eeg_mat = svd.matrixV().transpose().topRows(nvec_eeg);
638 for (p = 0,
nvec = 0; p < nvec_meg; p++,
nvec++)
639 if (sing_meg_vec[p]/sing_meg_vec[0] < USE_LIMIT)
641 for (p = 0; p < nvec_eeg; p++,
nvec++)
642 if (sing_eeg_vec[p]/sing_eeg_vec[0] < USE_LIMIT)
644 proj_data = Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>::Zero(
nvec,
nch);
645 for (p = 0,
nvec = 0; p < nvec_meg; p++,
nvec++) {
646 if (sing_meg_vec[p]/sing_meg_vec[0] < USE_LIMIT)
648 for (k = 0; k <
nch; k++) {
649 if (std::fabs(vv_meg_mat(p,k)) < SMALL_VALUE)
656 for (p = 0; p < nvec_eeg; p++,
nvec++) {
657 if (sing_eeg_vec[p]/sing_eeg_vec[0] < USE_LIMIT)
659 for (k = 0; k <
nch; k++) {
660 if (std::fabs(vv_eeg_mat(p,k)) < SMALL_VALUE)
670 for (k = 0; k <
nch; k++)
671 if (
names[k].contains(
"STI")) {
672 for (p = 0; p <
nvec; p++)
693 if (
nch !=
static_cast<int>(vec.size())) {
694 qCritical(
"Data vector size does not match projection operator");
698 Eigen::VectorXd proj = Eigen::VectorXd::Zero(vec.size());
700 for (
int p = 0; p <
nvec; p++) {
701 double w = vec.dot(
proj_data.row(p).cast<
double>());
702 proj += w *
proj_data.row(p).cast<
double>().transpose();
716 const QList<FiffChInfo>& chs,
718 std::unique_ptr<MNEProjOp>& result)
723 for (
int k = 0; k <
nch; k++)
727 if (projnames.size() == 0 && neeg == 0)
730 std::unique_ptr<MNEProjOp> all;
732 for (
int k = 0; k < projnames.size(); k++) {
735 qCritical(
"Failed to read projection from %s.", projnames[k].toUtf8().data());
738 if (one->nitems == 0) {
739 qInfo(
"No linear projection information in %s.", projnames[k].toUtf8().data());
742 qInfo(
"Loaded projection from %s:", projnames[k].toUtf8().data());
743 { QTextStream errStream(stderr); one->report(errStream, QStringLiteral(
"\t")); }
745 all = std::make_unique<MNEProjOp>();
746 all->combine(one.get());
753 for (
int k = 0; k < all->nitems; k++)
762 qInfo(
"Average EEG reference projection added:");
763 { QTextStream errStream(stderr); one->report(errStream, QStringLiteral(
"\t")); }
765 all = std::make_unique<MNEProjOp>();
766 all->combine(one.get());
770 if (all && all->affect_chs(chs,
nch) == 0) {
771 qInfo(
"Projection will not have any effect on selected channels. Projection omitted.");
774 result = std::move(all);
782 using RowMatrixXd = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
785 bool do_complement =
true;
791 qCritical(
"Incompatible data in apply_cov");
795 RowMatrixXd dcovMat = RowMatrixXd::Zero(c->
ncov,c->
ncov);
798 for (j = 0, p = 0; j < c->
ncov; j++)
799 for (k = 0; k < c->
ncov; k++)
800 dcovMat(j,k) = (j == k) ? c->
cov_diag[j] : 0;
803 for (j = 0, p = 0; j < c->
ncov; j++)
804 for (k = 0; k <= j; k++)
805 dcovMat(j,k) = c->
cov[p++];
806 for (j = 0; j < c->
ncov; j++)
807 for (k = j+1; k < c->
ncov; k++)
808 dcovMat(j,k) = dcovMat(k,j);
811 for (k = 0; k < c->
ncov; k++) {
812 Eigen::Map<Eigen::VectorXd> row_k(dcovMat.row(k).data(), c->
ncov);
817 dcovMat.transposeInPlace();
819 for (k = 0; k < c->
ncov; k++) {
820 Eigen::Map<Eigen::VectorXd> row_k(dcovMat.row(k).data(), c->
ncov);
826 for (j = 0; j < c->
ncov; j++) {
832 for (j = 0, p = 0; j < c->
ncov; j++)
833 for (k = 0; k <= j; k++)
834 c->
cov[p++] = dcovMat(j,k);
#define FIFF_PROJ_ITEM_VECTORS
#define FIFF_PROJ_ITEM_KIND
#define FIFF_PROJ_ITEM_CH_NAME_LIST
#define FIFF_PROJ_ITEM_NVEC
FiffTag class declaration, which provides fiff tag I/O and processing methods.
#define FIFF_MNE_PROJ_ITEM_ACTIVE
#define FIFFV_MNE_PROJ_ITEM_EEG_AVREF
MNENamedVector class declaration.
MNECovMatrix class declaration.
MNENamedMatrix class declaration.
MNEProjItem class declaration.
MNEProjOp class declaration.
Core MNE data structures (source spaces, source estimates, hemispheres).
FIFF file I/O and data structures (raw, epochs, evoked, covariance, forward).
QSharedPointer< FiffDirNode > SPtr
QSharedPointer< FiffStream > SPtr
static QStringList split_name_list(QString p_sNameList)
std::unique_ptr< FiffTag > UPtr
Covariance matrix storage.
A dense matrix with named rows and columns.
static std::unique_ptr< MNENamedMatrix > build(int nrow, int ncol, const QStringList &rowlist, const QStringList &collist, const Eigen::MatrixXf &data)
Factory: build a named matrix from its constituent parts.
int pick(const QStringList &names, int nnames, bool require_all, Eigen::Ref< Eigen::VectorXf > res) const
A single SSP (Signal-Space Projection) item.
Eigen::Matrix< float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > proj_data
void report_data(QTextStream &out, const QString &tag, bool list_data, const QStringList &exclude)
void free_proj()
Release the compiled projector data.
static std::unique_ptr< MNEProjOp > read(const QString &name)
void add_item_active(const MNENamedMatrix *vecs, int kind, const QString &desc, bool is_active)
Add a projection item with an explicit active/inactive state.
static bool makeProjection(const QList< QString > &projnames, const QList< FIFFLIB::FiffChInfo > &chs, int nch, std::unique_ptr< MNEProjOp > &result)
Load and combine SSP projection operators from files for the selected channels.
int apply_cov(MNECovMatrix *c)
int affect(const QStringList &list, int nlist)
MNEProjOp()
Default constructor.
int make_proj_bad(const QStringList &bad)
MNEProjOp * combine(MNEProjOp *from)
Append all projection items from another operator.
int project_vector(Eigen::Ref< Eigen::VectorXf > vec, bool do_complement)
int project_dvector(Eigen::Ref< Eigen::VectorXd > vec, bool do_complement)
void add_item(const MNENamedMatrix *vecs, int kind, const QString &desc)
Add a projection item that is active by default.
int affect_chs(const QList< FIFFLIB::FiffChInfo > &chs, int nch)
std::unique_ptr< MNEProjOp > dup() const
Create a deep copy of this projection operator.
int assign_channels(const QStringList &list, int nlist)
static std::unique_ptr< MNEProjOp > create_average_eeg_ref(const QList< FIFFLIB::FiffChInfo > &chs, int nch)
Create an average EEG reference projector.
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.
QList< MNELIB::MNEProjItem > items
void report(QTextStream &out, const QString &tag)