105 throw std::invalid_argument(
"No channel names specified");
110 proj = MatrixXd::Identity(nchan, nchan);
117 if (projs.size() == 0)
122 for (k = 0; k < projs.size(); ++k) {
125 nvec += projs[k].data->nrow;
130 qWarning(
"FiffProj::make_projector - No projectors nproj=0\n");
135 qWarning(
"FiffProj::make_projector - No rows in projector matrices found nvec<=0\n");
142 MatrixXd vecs = MatrixXd::Zero(nchan, nvec);
145 qint32 p, c, i, j, v;
148 RowVectorXi sel(nchan);
149 RowVectorXi vecSel(nchan);
151 vecSel.setConstant(-1);
152 for (k = 0; k < projs.size(); ++k) {
156 QMap<QString, int> uniqueMap;
157 for (l = 0; l < one.
data->col_names.size(); ++l)
158 uniqueMap[one.
data->col_names[l]] = 0;
160 if (one.
data->col_names.size() != uniqueMap.keys().size()) {
161 qWarning(
"Channel name list in projection item %d contains duplicate items", k);
170 vecSel.resize(nchan);
172 vecSel.setConstant(-1);
174 for (c = 0; c < nchan; ++c) {
175 for (i = 0; i < one.
data->col_names.size(); ++i) {
176 if (QString::compare(ch_names.at(c), one.
data->col_names[i]) == 0) {
178 for (j = 0; j < bads.size(); ++j) {
179 if (QString::compare(ch_names.at(c), bads.at(j)) == 0) {
184 if (!isBad && sel[p] != c) {
192 sel.conservativeResize(p);
193 vecSel.conservativeResize(p);
198 for (v = 0; v < one.
data->nrow; ++v)
199 for (i = 0; i < p; ++i)
200 vecs(sel[i], nvec + v) = one.
data->data(v, vecSel[i]);
205 for (v = 0; v < one.
data->nrow; ++v) {
206 onesize = sqrt((vecs.col(nvec + v).transpose() * vecs.col(nvec + v))(0, 0));
208 vecs.col(nvec + v) = vecs.col(nvec + v) / onesize;
212 nvec += one.
data->nrow;
224 JacobiSVD<MatrixXd>
svd(vecs.block(0, 0, vecs.rows(), nvec), ComputeFullU);
226 VectorXd
S =
svd.singularValues();
227 MatrixXd t_U =
svd.matrixU();
234 for (k = 0; k <
S.size(); ++k)
235 if (
S[k] /
S[0] > 1e-2)
238 U = t_U.block(0, 0, t_U.rows(), nproj);
243 proj -= U * U.transpose();
251 const MatrixXi& events,
258 const QMap<QString, double>& mapReject)
260 QList<FiffProj> projs;
264 int minSamp =
static_cast<int>(std::round(tmin * sfreq));
265 int maxSamp =
static_cast<int>(std::round(tmax * sfreq));
266 int ns = maxSamp - minSamp + 1;
269 qWarning() <<
"[FiffProj::compute_from_raw] Invalid time window.";
274 QList<int> gradIdx, magIdx, eegIdx;
275 for (
int k = 0; k < nchan; ++k) {
289 QList<MatrixXd> epochs;
290 double gradReject = mapReject.value(
"grad", 0.0);
291 double magReject = mapReject.value(
"mag", 0.0);
292 double eegReject = mapReject.value(
"eeg", 0.0);
294 for (
int k = 0; k < events.rows(); ++k) {
295 if (events(k, 1) != 0 || events(k, 2) != eventCode)
298 int evSample = events(k, 0);
299 int epochStart = evSample + minSamp;
300 int epochEnd = evSample + maxSamp;
302 if (epochStart < raw.first_samp || epochEnd > raw.
last_samp)
305 MatrixXd epochData, epochTimes;
311 for (
int c = 0; c < nchan && ok; ++c) {
314 double pp = epochData.row(c).maxCoeff() - epochData.row(c).minCoeff();
327 epochs.append(epochData);
330 if (epochs.isEmpty()) {
331 qWarning() <<
"[FiffProj::compute_from_raw] No valid epochs found for event" << eventCode;
335 qInfo() <<
"[FiffProj::compute_from_raw]" << epochs.size() <<
"epochs collected for event" << eventCode;
338 auto computeProjForChannels = [&](
const QList<int>& chIdx,
int nVec,
const QString&
desc) {
339 if (nVec <= 0 || chIdx.isEmpty())
342 int nRows = epochs.size() * ns;
343 MatrixXd dataMat(nRows, chIdx.size());
345 for (
int e = 0; e < epochs.size(); ++e) {
346 for (
int c = 0; c < chIdx.size(); ++c) {
347 dataMat.block(e * ns, c, ns, 1) = epochs[e].row(chIdx[c]).transpose();
355 Eigen::JacobiSVD<MatrixXd>
svd(dataMat, Eigen::ComputeThinV);
356 MatrixXd V =
svd.matrixV();
358 int nComp = qMin(nVec,
static_cast<int>(V.cols()));
360 for (
int v = 0; v < nComp; ++v) {
364 proj.
desc = QString(
"%1-v%2").arg(
desc).arg(v + 1);
367 namedMatrix->nrow = 1;
368 namedMatrix->ncol = nchan;
369 namedMatrix->row_names.clear();
371 namedMatrix->data = MatrixXd::Zero(1, nchan);
373 for (
int c = 0; c < chIdx.size(); ++c) {
374 namedMatrix->data(0, chIdx[c]) = V(c, v);
377 proj.
data = namedMatrix;
381 qInfo() <<
"[FiffProj::compute_from_raw] Created" << nComp <<
desc <<
"projection vector(s)";
384 computeProjForChannels(gradIdx, nGrad,
"PCA-grad");
385 computeProjForChannels(magIdx, nMag,
"PCA-mag");
386 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