125 qWarning(
"No channel names specified\n");
131 proj = MatrixXd::Identity(nchan,nchan);
138 if (projs.size() == 0)
143 for (k = 0; k < projs.size(); ++k)
148 nvec += projs[k].data->nrow;
153 qWarning(
"FiffProj::make_projector - No projectors nproj=0\n");
158 qWarning(
"FiffProj::make_projector - No rows in projector matrices found nvec<=0\n");
165 MatrixXd vecs = MatrixXd::Zero(nchan,nvec);
168 qint32 p, c, i, j, v;
171 RowVectorXi sel(nchan);
172 RowVectorXi vecSel(nchan);
174 vecSel.setConstant(-1);
175 for (k = 0; k < projs.size(); ++k)
181 QMap<QString, int> uniqueMap;
182 for(l = 0; l < one.
data->col_names.size(); ++l)
183 uniqueMap[one.
data->col_names[l] ] = 0;
185 if (one.
data->col_names.size() != uniqueMap.keys().size())
187 qWarning(
"Channel name list in projection item %d contains duplicate items",k);
196 vecSel.resize(nchan);
198 vecSel.setConstant(-1);
200 for (c = 0; c < nchan; ++c)
202 for (i = 0; i < one.
data->col_names.size(); ++i)
204 if (QString::compare(ch_names.at(c),one.
data->col_names[i]) == 0)
207 for (j = 0; j < bads.size(); ++j)
209 if (QString::compare(ch_names.at(c),bads.at(j)) == 0)
215 if (!isBad && sel[p] != c)
225 sel.conservativeResize(p);
226 vecSel.conservativeResize(p);
231 for (v = 0; v < one.
data->nrow; ++v)
232 for (i = 0; i < p; ++i)
233 vecs(sel[i],nvec+v) = one.
data->data(v,vecSel[i]);
238 for (v = 0; v < one.
data->nrow; ++v)
240 onesize = sqrt((vecs.col(nvec+v).transpose()*vecs.col(nvec+v))(0,0));
243 vecs.col(nvec+v) = vecs.col(nvec+v)/onesize;
247 nvec += one.
data->nrow;
259 JacobiSVD<MatrixXd> svd(vecs.block(0,0,vecs.rows(),nvec), ComputeFullU);
261 VectorXd S = svd.singularValues();
262 MatrixXd t_U = svd.matrixU();
269 for(k = 0; k < S.size(); ++k)
270 if (S[k]/S[0] > 1e-2)
273 U = t_U.block(0, 0, t_U.rows(), nproj);
278 proj -= U*U.transpose();
286 const MatrixXi &events,
293 const QMap<QString,double> &mapReject)
295 QList<FiffProj> projs;
299 int minSamp =
static_cast<int>(std::round(tmin * sfreq));
300 int maxSamp =
static_cast<int>(std::round(tmax * sfreq));
301 int ns = maxSamp - minSamp + 1;
304 qWarning() <<
"[FiffProj::compute_from_raw] Invalid time window.";
309 QList<int> gradIdx, magIdx, eegIdx;
310 for (
int k = 0; k < nchan; ++k) {
324 QList<MatrixXd> epochs;
325 double gradReject = mapReject.value(
"grad", 0.0);
326 double magReject = mapReject.value(
"mag", 0.0);
327 double eegReject = mapReject.value(
"eeg", 0.0);
329 for (
int k = 0; k < events.rows(); ++k) {
330 if (events(k, 1) != 0 || events(k, 2) != eventCode)
333 int evSample = events(k, 0);
334 int epochStart = evSample + minSamp;
335 int epochEnd = evSample + maxSamp;
337 if (epochStart < raw.first_samp || epochEnd > raw.
last_samp)
340 MatrixXd epochData, epochTimes;
346 for (
int c = 0; c < nchan && ok; ++c) {
349 double pp = epochData.row(c).maxCoeff() - epochData.row(c).minCoeff();
361 epochs.append(epochData);
364 if (epochs.isEmpty()) {
365 qWarning() <<
"[FiffProj::compute_from_raw] No valid epochs found for event" << eventCode;
369 qInfo() <<
"[FiffProj::compute_from_raw]" << epochs.size() <<
"epochs collected for event" << eventCode;
372 auto computeProjForChannels = [&](
const QList<int> &chIdx,
int nVec,
const QString &
desc) {
373 if (nVec <= 0 || chIdx.isEmpty())
376 int nRows = epochs.size() * ns;
377 MatrixXd dataMat(nRows, chIdx.size());
379 for (
int e = 0; e < epochs.size(); ++e) {
380 for (
int c = 0; c < chIdx.size(); ++c) {
381 dataMat.block(e * ns, c, ns, 1) = epochs[e].row(chIdx[c]).transpose();
386 VectorXd colMean = dataMat.colwise().mean();
387 dataMat.rowwise() -= colMean.transpose();
390 Eigen::JacobiSVD<MatrixXd> svd(dataMat, Eigen::ComputeThinV);
391 MatrixXd V = svd.matrixV();
393 int nComp = qMin(nVec,
static_cast<int>(V.cols()));
395 for (
int v = 0; v < nComp; ++v) {
399 proj.
desc = QString(
"%1-v%2").arg(
desc).arg(v + 1);
402 namedMatrix->nrow = 1;
403 namedMatrix->ncol = nchan;
404 namedMatrix->row_names.clear();
406 namedMatrix->data = MatrixXd::Zero(1, nchan);
408 for (
int c = 0; c < chIdx.size(); ++c) {
409 namedMatrix->data(0, chIdx[c]) = V(c, v);
412 proj.
data = namedMatrix;
416 qInfo() <<
"[FiffProj::compute_from_raw] Created" << nComp <<
desc <<
"projection vector(s)";
419 computeProjForChannels(gradIdx, nGrad,
"PCA-grad");
420 computeProjForChannels(magIdx, nMag,
"PCA-mag");
421 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 >())