74#define MALLOC_23(x,t) (t *)malloc((x)*sizeof(t))
76#define REALLOC_23(x,y,t) (t *)((x == NULL) ? malloc((y)*sizeof(t)) : realloc((x),(y)*sizeof(t)))
78#define FREE_23(x) if ((char *)(x) != NULL) free((char *)(x))
80#define FREE_CMATRIX_23(m) mne_free_cmatrix_23((m))
90#define ALLOC_CMATRIX_23(x,y) mne_cmatrix_23((x),(y))
92static void matrix_error_23(
int kind,
int nr,
int nc)
96 printf(
"Failed to allocate memory pointers for a %d x %d matrix\n",nr,nc);
98 printf(
"Failed to allocate memory for a %d x %d matrix\n",nr,nc);
100 printf(
"Allocation error for a %d x %d matrix\n",nr,nc);
101 if (
sizeof(
void *) == 4) {
102 printf(
"This is probably because you seem to be using a computer with 32-bit architecture.\n");
103 printf(
"Please consider moving to a 64-bit platform.");
105 printf(
"Cannot continue. Sorry.\n");
117 if (!m) matrix_error_23(1,nr,nc);
119 if (!whole) matrix_error_23(2,nr,nc);
133 float res = sdot(&nn,v1,&one,v2,&one);
139 for (k = 0; k < nn; k++)
140 res = res + v1[k]*v2[k];
154 if (!s.isEmpty() && s.size() > 0) {
159 nlistp = list.size();
165 for (
int i = 0; i < m; ++i)
166 for (
int j = 0; j < n; ++j)
167 to_mat[i][j] = from_mat(i,j);
180 int nlist = list.size();
182 if (nlist == 0 || list.isEmpty())
185 for (
int k = 0; k < nlist-1; k++) {
189 res += list[nlist-1];
202 for (
int k = 0; k < nch; k++)
203 names.append(chs.at(k).ch_name);
212using namespace Eigen;
254 for (
int k = 0; k < from->
nitems; k++) {
255 const auto& it = from->
items[k];
256 add_item(it.vecs.get(),it.kind,it.desc);
271 auto& new_item =
items.back();
273 new_item.active = is_active;
274 new_item.vecs = std::make_unique<MNENamedMatrix>(*vecs);
277 new_item.has_meg =
FALSE;
278 new_item.has_eeg =
TRUE;
281 for (
int k = 0; k < vecs->
ncol; k++) {
282 if (vecs->
collist[k].contains(
"EEG"))
283 new_item.has_eeg =
TRUE;
284 if (vecs->
collist[k].contains(
"MEG"))
285 new_item.has_meg =
TRUE;
287 if (!new_item.has_meg && !new_item.has_eeg) {
288 new_item.has_meg =
TRUE;
289 new_item.has_eeg =
FALSE;
291 else if (new_item.has_meg && new_item.has_eeg) {
292 new_item.has_meg =
TRUE;
293 new_item.has_eeg =
FALSE;
297 new_item.desc = desc;
298 new_item.kind = kind;
299 new_item.nvec = new_item.vecs->nrow;
323 for (
int k = 0; k <
nitems; k++) {
324 const auto& it =
items[k];
326 res->
items[k].active_file = it.active_file;
343 for (k = 0; k <
nch; k++)
347 qCritical(
"No EEG channels specified for average reference.");
351 for (k = 0; k <
nch; k++)
353 names.append(chs.at(k).ch_name);
355 Eigen::MatrixXf vec_data = Eigen::MatrixXf::Constant(1, eegcount, 1.0f/sqrt((
double)eegcount));
357 QStringList emptyList;
373 for (k = 0, naff = 0; k <
nitems; k++)
375 naff +=
items[k].nvec;
406 thread_local std::vector<float> res;
415 printf(
"Data vector size does not match projection operator");
419 if (
nch >
static_cast<int>(res.size())) {
423 for (k = 0; k <
nch; k++)
426 for (p = 0; p < this->nvec; p++) {
429 for (k = 0; k <
nch; k++)
430 res[k] = res[k] + w*pvec[k];
433 for (k = 0; k <
nch; k++)
434 vec[k] = vec[k] - res[k];
437 for (k = 0; k <
nch; k++)
451 QList<FiffDirNode::SPtr> proj;
453 QList<FiffDirNode::SPtr>
items;
456 QString item_desc,desc_tag;
457 int global_nchan,item_nchan;
458 QStringList item_names;
465 qCritical(
"File not open read_from_node");
469 if (!start || start->isEmpty())
470 start_node = stream->dirtree();
476 if (proj.size() == 0 || proj[0]->isEmpty())
488 if(!node->find_tag(stream,
FIFF_NCHAN, t_pTag))
491 global_nchan = *t_pTag->toInt();
497 for (k = 0; k <
items.size(); k++) {
504 if (node->find_tag(stream,
FIFF_NAME, t_pTag)) {
505 item_desc += t_pTag->toString();
512 desc_tag = t_pTag->toString();
514 if((pos = desc_tag.indexOf(
"\n")) >= 0)
515 desc_tag.truncate(pos);
516 if (!item_desc.isEmpty())
518 item_desc += desc_tag;
523 if (!node->find_tag(stream,
FIFF_NCHAN, t_pTag)) {
524 item_nchan = global_nchan;
527 item_nchan = *t_pTag->toInt();
529 if (item_nchan <= 0) {
530 qCritical(
"Number of channels incorrectly specified for one of the projection items.");
541 if (item_names.size() != item_nchan) {
542 printf(
"Channel name list incorrectly specified for proj item # %d",k+1);
551 item_kind = *t_pTag->toInt();
557 item_nvec = *t_pTag->toInt();
564 MatrixXf item_vectors = t_pTag->toFloatMatrix().transpose();
570 item_active = *t_pTag->toInt();
577 QStringList emptyList;
625 out <<
"Empty operator\n";
629 for (
int k = 0; k <
nitems; k++) {
630 const auto& it =
items[k];
631 if (list_data && tag)
635 out <<
"# " << (k+1) <<
" : " << it.desc <<
" : " << it.nvec <<
" vecs : " << it.vecs->ncol <<
" chs "
636 << (it.has_meg ?
"MEG" :
"EEG") <<
" "
637 << (it.active ?
"active" :
"idle") <<
"\n";
638 if (list_data && tag)
641 vecs =
items[k].vecs.get();
643 for (q = 0; q < vecs->
ncol; q++) {
644 out << qSetFieldWidth(10) << Qt::left << vecs->
collist[q] << qSetFieldWidth(0);
645 out << (q < vecs->
ncol-1 ?
" " :
"\n");
647 for (p = 0; p < vecs->
nrow; p++)
648 for (q = 0; q < vecs->
ncol; q++) {
649 for (j = 0, found = 0; j < nexclude; j++) {
650 if (QString::compare(exclude[j],vecs->
collist[q]) == 0) {
655 out << qSetFieldWidth(10) << qSetRealNumberPrecision(5) << Qt::forcepoint
656 << (found ? 0.0 : vecs->
data(p, q)) << qSetFieldWidth(0) <<
" ";
657 out << (q < vecs->
ncol-1 ?
" " :
"\n");
659 if (list_data && tag)
692void clear_channel_group(Eigen::Ref<Eigen::VectorXf> data,
const QStringList& ch_names,
int nnames,
const QString& prefix)
694 for (
int k = 0; k < nnames; k++)
695 if (ch_names[k].contains(prefix))
699constexpr float USE_LIMIT = 1e-5f;
700constexpr float SMALL_VALUE = 1e-4f;
706 using RowMatrixXf = Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
708 int k,p,q,r,nvec_total;
709 RowMatrixXf vv_meg_mat;
710 Eigen::VectorXf sing_meg_vec;
711 RowMatrixXf vv_eeg_mat;
712 Eigen::VectorXf sing_eeg_vec;
731 RowMatrixXf mat_meg_mat = RowMatrixXf::Zero(nvec_total,
nch);
732 RowMatrixXf mat_eeg_mat = RowMatrixXf::Zero(nvec_total,
nch);
734 for (k = 0, nvec_meg = nvec_eeg = 0; k <
nitems; k++) {
738 if (
items[k].has_meg) {
739 for (p = 0; p <
items[k].nvec; p++, nvec_meg++) {
741 Eigen::Map<Eigen::VectorXf> res_meg(mat_meg_mat.row(nvec_meg).data(),
nch);
746 else if (
items[k].has_eeg) {
747 for (p = 0; p <
items[k].nvec; p++, nvec_eeg++) {
749 Eigen::Map<Eigen::VectorXf> res_eeg(mat_eeg_mat.row(nvec_eeg).data(),
nch);
759 for (q = 0; q < nbad; q++)
760 for (r = 0; r <
nch; r++)
761 if (QString::compare(
names[r],bad[q]) == 0) {
762 for (p = 0; p < nvec_meg; p++)
763 mat_meg_mat(p,r) = 0.0;
764 for (p = 0; p < nvec_eeg; p++)
765 mat_eeg_mat(p,r) = 0.0;
770 for (p = 0, nzero = 0; p < nvec_meg; p++) {
771 size = mat_meg_mat.row(p).norm();
773 mat_meg_mat.row(p) /= size;
778 if (nzero == nvec_meg) {
779 mat_meg_mat.resize(0, 0); nvec_meg = 0;
781 for (p = 0, nzero = 0; p < nvec_eeg; p++) {
782 size = mat_eeg_mat.row(p).norm();
784 mat_eeg_mat.row(p) /= size;
789 if (nzero == nvec_eeg) {
790 mat_eeg_mat.resize(0, 0); nvec_eeg = 0;
792 if (nvec_meg + nvec_eeg == 0) {
793 qWarning(
"No projection remains after excluding bad channels. Omitting projection.");
800 Eigen::JacobiSVD<Eigen::MatrixXf> svd(mat_meg_mat.topRows(nvec_meg), Eigen::ComputeFullV);
801 sing_meg_vec = svd.singularValues();
802 vv_meg_mat = svd.matrixV().transpose().topRows(nvec_meg);
805 Eigen::JacobiSVD<Eigen::MatrixXf> svd(mat_eeg_mat.topRows(nvec_eeg), Eigen::ComputeFullV);
806 sing_eeg_vec = svd.singularValues();
807 vv_eeg_mat = svd.matrixV().transpose().topRows(nvec_eeg);
812 for (p = 0,
nvec = 0; p < nvec_meg; p++,
nvec++)
813 if (sing_meg_vec[p]/sing_meg_vec[0] < USE_LIMIT)
815 for (p = 0; p < nvec_eeg; p++,
nvec++)
816 if (sing_eeg_vec[p]/sing_eeg_vec[0] < USE_LIMIT)
819 for (p = 0,
nvec = 0; p < nvec_meg; p++,
nvec++) {
820 if (sing_meg_vec[p]/sing_meg_vec[0] < USE_LIMIT)
822 for (k = 0; k <
nch; k++) {
823 if (std::fabs(vv_meg_mat(p,k)) < SMALL_VALUE)
830 for (p = 0; p < nvec_eeg; p++,
nvec++) {
831 if (sing_eeg_vec[p]/sing_eeg_vec[0] < USE_LIMIT)
833 for (k = 0; k <
nch; k++) {
834 if (std::fabs(vv_eeg_mat(p,k)) < SMALL_VALUE)
844 for (k = 0; k <
nch; k++)
845 if (
names[k].contains(
"STI")) {
846 for (p = 0; p <
nvec; p++)
867 if (
nch != vec_nch) {
868 qCritical(
"Data vector size does not match projection operator");
872 Eigen::VectorXd proj = Eigen::VectorXd::Zero(vec_nch);
874 for (
int p = 0; p <
nvec; p++) {
875 double w = vec.dot(
proj_data.row(p).cast<
double>());
876 proj += w *
proj_data.row(p).cast<
double>().transpose();
890 const QList<FiffChInfo>& chs,
892 std::unique_ptr<MNEProjOp>& result)
897 for (
int k = 0; k <
nch; k++)
901 if (projnames.size() == 0 && neeg == 0)
904 std::unique_ptr<MNEProjOp> all;
906 for (
int k = 0; k < projnames.size(); k++) {
909 qCritical(
"Failed to read projection from %s.", projnames[k].toUtf8().data());
912 if (one->nitems == 0) {
913 qInfo(
"No linear projection information in %s.", projnames[k].toUtf8().data());
916 qInfo(
"Loaded projection from %s:", projnames[k].toUtf8().data());
917 { QTextStream errStream(stderr); one->report(errStream,
"\t"); }
919 all = std::make_unique<MNEProjOp>();
920 all->combine(one.get());
927 for (
int k = 0; k < all->nitems; k++)
936 qInfo(
"Average EEG reference projection added:");
937 { QTextStream errStream(stderr); one->report(errStream,
"\t"); }
939 all = std::make_unique<MNEProjOp>();
940 all->combine(one.get());
944 if (all && all->affect_chs(chs,
nch) == 0) {
945 qInfo(
"Projection will not have any effect on selected channels. Projection omitted.");
948 result = std::move(all);
956 using RowMatrixXd = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
959 int do_complement =
true;
965 qCritical(
"Incompatible data in apply_cov");
969 RowMatrixXd dcovMat = RowMatrixXd::Zero(c->
ncov,c->
ncov);
972 for (j = 0, p = 0; j < c->
ncov; j++)
973 for (k = 0; k < c->
ncov; k++)
974 dcovMat(j,k) = (j == k) ? c->
cov_diag[j] : 0;
977 for (j = 0, p = 0; j < c->
ncov; j++)
978 for (k = 0; k <= j; k++)
979 dcovMat(j,k) = c->
cov[p++];
980 for (j = 0; j < c->
ncov; j++)
981 for (k = j+1; k < c->
ncov; k++)
982 dcovMat(j,k) = dcovMat(k,j);
985 for (k = 0; k < c->
ncov; k++) {
986 Eigen::Map<Eigen::VectorXd> row_k(dcovMat.row(k).data(), c->
ncov);
991 dcovMat.transposeInPlace();
993 for (k = 0; k < c->
ncov; k++) {
994 Eigen::Map<Eigen::VectorXd> row_k(dcovMat.row(k).data(), c->
ncov);
1000 for (j = 0; j < c->
ncov; j++) {
1006 for (j = 0, p = 0; j < c->
ncov; j++)
1007 for (k = 0; k <= j; k++)
1008 c->
cov[p++] = dcovMat(j,k);
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
#define FIFF_PROJ_ITEM_VECTORS
#define FIFF_PROJ_ITEM_KIND
#define FIFF_PROJ_ITEM_CH_NAME_LIST
#define FIFF_PROJ_ITEM_NVEC
MNECovMatrix class declaration.
MNEProjOp class declaration.
MNEProjItem class declaration.
void mne_string_to_name_list_23(const QString &s, QStringList &listp, int &nlistp)
void mne_free_cmatrix_23(float **m)
QString mne_name_list_to_string_23(const QStringList &list)
QString mne_channel_names_to_string_23(const QList< FIFFLIB::FiffChInfo > &chs, int nch)
float mne_dot_vectors_23(float *v1, float *v2, int nn)
void fromFloatEigenMatrix_23(const Eigen::MatrixXf &from_mat, float **&to_mat, const int m, const int n)
float ** mne_cmatrix_23(int nr, int nc)
MNENamedMatrix 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.
void free_proj()
Release the compiled projector data.
static MNEProjOp * read_from_node(FIFFLIB::FiffStream::SPtr &stream, const FIFFLIB::FiffDirNode::SPtr &start)
Read all linear projection items from a FIFF tree node.
RowMajorMatrixXf proj_data
int project_vector(float *vec, int nvec, int do_complement)
static MNEProjOp * read(const QString &name)
static MNEProjOp * create_average_eeg_ref(const QList< FIFFLIB::FiffChInfo > &chs, int nch)
Create an average EEG reference projector.
void report_data(QTextStream &out, const char *tag, int list_data, char **exclude, int nexclude)
int project_dvector(Eigen::Ref< Eigen::VectorXd > vec, int nch, int do_complement)
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)
void report(QTextStream &out, const char *tag)
MNEProjOp()
Default constructor.
MNEProjOp * combine(MNEProjOp *from)
Append all projection items from another operator.
MNEProjOp * dup() const
Create a deep copy of this projection operator.
int make_proj_bad(char **bad, int nbad)
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)
int assign_channels(const QStringList &list, int nlist)
QList< MNELIB::MNEProjItem > items
void add_item_active(const MNENamedMatrix *vecs, int kind, const QString &desc, int is_active)
Add a projection item with an explicit active/inactive state.