124 printf(
"No channel names specified\n");
130 proj = MatrixXd::Identity(nchan,nchan);
137 if (projs.size() == 0)
142 for (k = 0; k < projs.size(); ++k)
147 nvec += projs[k].data->nrow;
152 printf(
"FiffProj::make_projector - No projectors nproj=0\n");
157 printf(
"FiffProj::make_projector - No rows in projector matrices found nvec<=0\n");
164 MatrixXd vecs = MatrixXd::Zero(nchan,nvec);
167 qint32 p, c, i, j, v;
170 RowVectorXi sel(nchan);
171 RowVectorXi vecSel(nchan);
173 vecSel.setConstant(-1);
174 for (k = 0; k < projs.size(); ++k)
180 QMap<QString, int> uniqueMap;
181 for(l = 0; l < one.
data->col_names.size(); ++l)
182 uniqueMap[one.
data->col_names[l] ] = 0;
184 if (one.
data->col_names.size() != uniqueMap.keys().size())
186 printf(
"Channel name list in projection item %d contains duplicate items",k);
195 vecSel.resize(nchan);
197 vecSel.setConstant(-1);
199 for (c = 0; c < nchan; ++c)
201 for (i = 0; i < one.
data->col_names.size(); ++i)
203 if (QString::compare(ch_names.at(c),one.
data->col_names[i]) == 0)
206 for (j = 0; j < bads.size(); ++j)
208 if (QString::compare(ch_names.at(c),bads.at(j)) == 0)
214 if (!isBad && sel[p] != c)
224 sel.conservativeResize(p);
225 vecSel.conservativeResize(p);
230 for (v = 0; v < one.
data->nrow; ++v)
231 for (i = 0; i < p; ++i)
232 vecs(sel[i],nvec+v) = one.
data->data(v,vecSel[i]);
237 for (v = 0; v < one.
data->nrow; ++v)
239 onesize = sqrt((vecs.col(nvec+v).transpose()*vecs.col(nvec+v))(0,0));
242 vecs.col(nvec+v) = vecs.col(nvec+v)/onesize;
246 nvec += one.
data->nrow;
258 JacobiSVD<MatrixXd> svd(vecs.block(0,0,vecs.rows(),nvec), ComputeFullU);
260 VectorXd S = svd.singularValues();
261 MatrixXd t_U = svd.matrixU();
268 for(k = 0; k < S.size(); ++k)
269 if (S[k]/S[0] > 1e-2)
272 U = t_U.block(0, 0, t_U.rows(), nproj);
277 proj -= U*U.transpose();
285 const MatrixXi &events,
292 const QMap<QString,double> &mapReject)
294 QList<FiffProj> projs;
298 int minSamp =
static_cast<int>(std::round(tmin * sfreq));
299 int maxSamp =
static_cast<int>(std::round(tmax * sfreq));
300 int ns = maxSamp - minSamp + 1;
303 qWarning() <<
"[FiffProj::compute_from_raw] Invalid time window.";
308 QList<int> gradIdx, magIdx, eegIdx;
309 for (
int k = 0; k < nchan; ++k) {
323 QList<MatrixXd> epochs;
324 double gradReject = mapReject.value(
"grad", 0.0);
325 double magReject = mapReject.value(
"mag", 0.0);
326 double eegReject = mapReject.value(
"eeg", 0.0);
328 for (
int k = 0; k < events.rows(); ++k) {
329 if (events(k, 1) != 0 || events(k, 2) != eventCode)
332 int evSample = events(k, 0);
333 int epochStart = evSample + minSamp;
334 int epochEnd = evSample + maxSamp;
336 if (epochStart < raw.first_samp || epochEnd > raw.
last_samp)
339 MatrixXd epochData, epochTimes;
345 for (
int c = 0; c < nchan && ok; ++c) {
348 double pp = epochData.row(c).maxCoeff() - epochData.row(c).minCoeff();
360 epochs.append(epochData);
363 if (epochs.isEmpty()) {
364 qWarning() <<
"[FiffProj::compute_from_raw] No valid epochs found for event" << eventCode;
368 qInfo() <<
"[FiffProj::compute_from_raw]" << epochs.size() <<
"epochs collected for event" << eventCode;
371 auto computeProjForChannels = [&](
const QList<int> &chIdx,
int nVec,
const QString &
desc) {
372 if (nVec <= 0 || chIdx.isEmpty())
375 int nRows = epochs.size() * ns;
376 MatrixXd dataMat(nRows, chIdx.size());
378 for (
int e = 0; e < epochs.size(); ++e) {
379 for (
int c = 0; c < chIdx.size(); ++c) {
380 dataMat.block(e * ns, c, ns, 1) = epochs[e].row(chIdx[c]).transpose();
385 VectorXd colMean = dataMat.colwise().mean();
386 dataMat.rowwise() -= colMean.transpose();
389 Eigen::JacobiSVD<MatrixXd> svd(dataMat, Eigen::ComputeThinV);
390 MatrixXd V = svd.matrixV();
392 int nComp = qMin(nVec,
static_cast<int>(V.cols()));
394 for (
int v = 0; v < nComp; ++v) {
398 proj.
desc = QString(
"%1-v%2").arg(
desc).arg(v + 1);
401 namedMatrix->nrow = 1;
402 namedMatrix->ncol = nchan;
403 namedMatrix->row_names.clear();
405 namedMatrix->data = MatrixXd::Zero(1, nchan);
407 for (
int c = 0; c < chIdx.size(); ++c) {
408 namedMatrix->data(0, chIdx[c]) = V(c, v);
411 proj.
data = namedMatrix;
415 qInfo() <<
"[FiffProj::compute_from_raw] Created" << nComp <<
desc <<
"projection vector(s)";
418 computeProjForChannels(gradIdx, nGrad,
"PCA-grad");
419 computeProjForChannels(magIdx, nMag,
"PCA-mag");
420 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 >())