105fiff_int_t
FiffProj::make_projector(
const QList<FiffProj>& projs,
const QStringList& ch_names, MatrixXd& proj,
const QStringList& bads, MatrixXd& U)
107 fiff_int_t nchan = ch_names.size();
110 throw std::invalid_argument(
"No channel names specified");
115 proj = MatrixXd::Identity(nchan,nchan);
116 fiff_int_t nproj = 0;
122 if (projs.size() == 0)
127 for (k = 0; k < projs.size(); ++k)
132 nvec += projs[k].data->nrow;
137 qWarning(
"FiffProj::make_projector - No projectors nproj=0\n");
142 qWarning(
"FiffProj::make_projector - No rows in projector matrices found nvec<=0\n");
149 MatrixXd vecs = MatrixXd::Zero(nchan,nvec);
151 fiff_int_t nonzero = 0;
152 qint32 p, c, i, j, v;
155 RowVectorXi sel(nchan);
156 RowVectorXi vecSel(nchan);
158 vecSel.setConstant(-1);
159 for (k = 0; k < projs.size(); ++k)
165 QMap<QString, int> uniqueMap;
166 for(l = 0; l < one.
data->col_names.size(); ++l)
167 uniqueMap[one.
data->col_names[l] ] = 0;
169 if (one.
data->col_names.size() != uniqueMap.keys().size())
171 qWarning(
"Channel name list in projection item %d contains duplicate items",k);
180 vecSel.resize(nchan);
182 vecSel.setConstant(-1);
184 for (c = 0; c < nchan; ++c)
186 for (i = 0; i < one.
data->col_names.size(); ++i)
188 if (QString::compare(ch_names.at(c),one.
data->col_names[i]) == 0)
191 for (j = 0; j < bads.size(); ++j)
193 if (QString::compare(ch_names.at(c),bads.at(j)) == 0)
199 if (!isBad && sel[p] != c)
209 sel.conservativeResize(p);
210 vecSel.conservativeResize(p);
215 for (v = 0; v < one.
data->nrow; ++v)
216 for (i = 0; i < p; ++i)
217 vecs(sel[i],nvec+v) = one.
data->data(v,vecSel[i]);
222 for (v = 0; v < one.
data->nrow; ++v)
224 onesize = sqrt((vecs.col(nvec+v).transpose()*vecs.col(nvec+v))(0,0));
227 vecs.col(nvec+v) = vecs.col(nvec+v)/onesize;
231 nvec += one.
data->nrow;
243 JacobiSVD<MatrixXd>
svd(vecs.block(0,0,vecs.rows(),nvec), ComputeFullU);
245 VectorXd
S =
svd.singularValues();
246 MatrixXd t_U =
svd.matrixU();
253 for(k = 0; k <
S.size(); ++k)
254 if (
S[k]/
S[0] > 1e-2)
257 U = t_U.block(0, 0, t_U.rows(), nproj);
262 proj -= U*U.transpose();
270 const MatrixXi &events,
277 const QMap<QString,double> &mapReject)
279 QList<FiffProj> projs;
283 int minSamp =
static_cast<int>(std::round(tmin * sfreq));
284 int maxSamp =
static_cast<int>(std::round(tmax * sfreq));
285 int ns = maxSamp - minSamp + 1;
288 qWarning() <<
"[FiffProj::compute_from_raw] Invalid time window.";
293 QList<int> gradIdx, magIdx, eegIdx;
294 for (
int k = 0; k < nchan; ++k) {
308 QList<MatrixXd> epochs;
309 double gradReject = mapReject.value(
"grad", 0.0);
310 double magReject = mapReject.value(
"mag", 0.0);
311 double eegReject = mapReject.value(
"eeg", 0.0);
313 for (
int k = 0; k < events.rows(); ++k) {
314 if (events(k, 1) != 0 || events(k, 2) != eventCode)
317 int evSample = events(k, 0);
318 int epochStart = evSample + minSamp;
319 int epochEnd = evSample + maxSamp;
321 if (epochStart < raw.first_samp || epochEnd > raw.
last_samp)
324 MatrixXd epochData, epochTimes;
330 for (
int c = 0; c < nchan && ok; ++c) {
333 double pp = epochData.row(c).maxCoeff() - epochData.row(c).minCoeff();
345 epochs.append(epochData);
348 if (epochs.isEmpty()) {
349 qWarning() <<
"[FiffProj::compute_from_raw] No valid epochs found for event" << eventCode;
353 qInfo() <<
"[FiffProj::compute_from_raw]" << epochs.size() <<
"epochs collected for event" << eventCode;
356 auto computeProjForChannels = [&](
const QList<int> &chIdx,
int nVec,
const QString &
desc) {
357 if (nVec <= 0 || chIdx.isEmpty())
360 int nRows = epochs.size() * ns;
361 MatrixXd dataMat(nRows, chIdx.size());
363 for (
int e = 0; e < epochs.size(); ++e) {
364 for (
int c = 0; c < chIdx.size(); ++c) {
365 dataMat.block(e * ns, c, ns, 1) = epochs[e].row(chIdx[c]).transpose();
370 VectorXd colMean = dataMat.colwise().mean();
371 dataMat.rowwise() -= colMean.transpose();
374 Eigen::JacobiSVD<MatrixXd>
svd(dataMat, Eigen::ComputeThinV);
375 MatrixXd V =
svd.matrixV();
377 int nComp = qMin(nVec,
static_cast<int>(V.cols()));
379 for (
int v = 0; v < nComp; ++v) {
383 proj.
desc = QString(
"%1-v%2").arg(
desc).arg(v + 1);
386 namedMatrix->nrow = 1;
387 namedMatrix->ncol = nchan;
388 namedMatrix->row_names.clear();
390 namedMatrix->data = MatrixXd::Zero(1, nchan);
392 for (
int c = 0; c < chIdx.size(); ++c) {
393 namedMatrix->data(0, chIdx[c]) = V(c, v);
396 proj.
data = namedMatrix;
400 qInfo() <<
"[FiffProj::compute_from_raw] Created" << nComp <<
desc <<
"projection vector(s)";
403 computeProjForChannels(gradIdx, nGrad,
"PCA-grad");
404 computeProjForChannels(magIdx, nMag,
"PCA-mag");
405 computeProjForChannels(eegIdx, nEeg,
"PCA-eeg");
static QList< FiffProj > compute_from_raw(const FiffRawData &raw, const Eigen::MatrixXi &events, int eventCode, float tmin, float tmax, int nGrad, int nMag, int nEeg, const QMap< QString, double > &mapReject=QMap< QString, double >())
bool read_raw_segment(Eigen::MatrixXd &data, Eigen::MatrixXd ×, fiff_int_t from=-1, fiff_int_t to=-1, const Eigen::RowVectorXi &sel=defaultRowVectorXi, bool do_debug=false) const