168 VectorXi C_ch_idx = VectorXi::Zero(p_NoiseCov.
names.size());
170 for (qint32 i = 0; i < p_ChNames.size(); ++i) {
171 qint32 idx = p_NoiseCov.
names.indexOf(p_ChNames[i]);
173 C_ch_idx[count] = idx;
177 C_ch_idx.conservativeResize(count);
179 MatrixXd C(count, count);
181 if (!p_NoiseCov.
diag)
182 for (qint32 i = 0; i < count; ++i)
183 for (qint32 j = 0; j < count; ++j)
184 C(i, j) = p_NoiseCov.
data(C_ch_idx(i), C_ch_idx(j));
186 qWarning(
"Warning in FiffCov::prepare_noise_cov: This has to be debugged - not done before!");
187 C = MatrixXd::Zero(count, count);
188 for (qint32 i = 0; i < count; ++i)
189 C.diagonal()[i] = p_NoiseCov.
data(C_ch_idx(i), 0);
196 if (ncomp > 0 && proj.rows() == count) {
197 qInfo(
"Created an SSP operator (subspace dimension = %d)\n", ncomp);
198 C = proj * (C * proj.transpose());
200 qWarning(
"Warning in FiffCov::prepare_noise_cov: No projections applied since no projectors specified or projector dimensions do not match!");
203 RowVectorXi pick_meg = p_Info.
pick_types(
true,
false,
false, defaultQStringList, p_Info.
bads);
204 RowVectorXi pick_eeg = p_Info.
pick_types(
false,
true,
false, defaultQStringList, p_Info.
bads);
206 QStringList meg_names, eeg_names;
208 for (qint32 i = 0; i < pick_meg.size(); ++i)
209 meg_names << p_Info.
chs[pick_meg[i]].ch_name;
210 VectorXi C_meg_idx = VectorXi::Zero(p_NoiseCov.
names.size());
212 for (qint32 k = 0; k < C.rows(); ++k) {
213 if (meg_names.indexOf(p_ChNames[k]) > -1) {
214 C_meg_idx[count] = k;
219 C_meg_idx.conservativeResize(count);
221 C_meg_idx = VectorXi();
224 for (qint32 i = 0; i < pick_eeg.size(); ++i)
225 eeg_names << p_Info.
chs[pick_eeg(0, i)].ch_name;
226 VectorXi C_eeg_idx = VectorXi::Zero(p_NoiseCov.
names.size());
228 for (qint32 k = 0; k < C.rows(); ++k) {
229 if (eeg_names.indexOf(p_ChNames[k]) > -1) {
230 C_eeg_idx[count] = k;
236 C_eeg_idx.conservativeResize(count);
238 C_eeg_idx = VectorXi();
240 bool has_meg = C_meg_idx.size() > 0;
241 bool has_eeg = C_eeg_idx.size() > 0;
243 MatrixXd C_meg, C_eeg;
244 VectorXd C_meg_eig, C_eeg_eig;
245 MatrixXd C_meg_eigvec, C_eeg_eigvec;
247 count = C_meg_idx.rows();
248 C_meg = MatrixXd(count, count);
249 for (qint32 i = 0; i < count; ++i)
250 for (qint32 j = 0; j < count; ++j)
251 C_meg(i, j) = C(C_meg_idx(i), C_meg_idx(j));
256 count = C_eeg_idx.rows();
257 C_eeg = MatrixXd(count, count);
258 for (qint32 i = 0; i < count; ++i)
259 for (qint32 j = 0; j < count; ++j)
260 C_eeg(i, j) = C(C_eeg_idx(i), C_eeg_idx(j));
264 qint32 n_chan = p_ChNames.size();
265 p_NoiseCov.
eigvec = MatrixXd::Zero(n_chan, n_chan);
266 p_NoiseCov.
eig = VectorXd::Zero(n_chan);
269 for (qint32 i = 0; i < C_meg_idx.rows(); ++i)
270 for (qint32 j = 0; j < C_meg_idx.rows(); ++j)
271 p_NoiseCov.
eigvec(C_meg_idx[i], C_meg_idx[j]) = C_meg_eigvec(i, j);
272 for (qint32 i = 0; i < C_meg_idx.rows(); ++i)
273 p_NoiseCov.
eig(C_meg_idx[i]) = C_meg_eig[i];
276 for (qint32 i = 0; i < C_eeg_idx.rows(); ++i)
277 for (qint32 j = 0; j < C_eeg_idx.rows(); ++j)
278 p_NoiseCov.
eigvec(C_eeg_idx[i], C_eeg_idx[j]) = C_eeg_eigvec(i, j);
279 for (qint32 i = 0; i < C_eeg_idx.rows(); ++i)
280 p_NoiseCov.
eig(C_eeg_idx[i]) = C_eeg_eig[i];
283 if (C_meg_idx.size() + C_eeg_idx.size() != n_chan) {
284 qWarning(
"FiffCov::prepare_noise_cov: %lld MEG + %lld EEG channels != %d total (unclassified channels present)",
285 (
long long)C_meg_idx.size(), (
long long)C_eeg_idx.size(), n_chan);
289 p_NoiseCov.
dim = p_ChNames.size();
290 p_NoiseCov.
diag =
false;
291 p_NoiseCov.
names = p_ChNames;
302 if (p_exclude.size() == 0) {
303 p_exclude = p_info.
bads;
304 for (qint32 i = 0; i < cov.
bads.size(); ++i)
305 if (!p_exclude.contains(cov.
bads[i]))
306 p_exclude << cov.
bads[i];
310 for (
int i = 0; i < p_info.
chs.size(); i++) {
312 p_exclude << p_info.
chs[i].ch_name;
316 RowVectorXi sel_eeg = p_info.
pick_types(
false,
true,
false, defaultQStringList, p_exclude);
317 RowVectorXi sel_mag = p_info.
pick_types(QString(
"mag"),
false,
false, defaultQStringList, p_exclude);
318 RowVectorXi sel_grad = p_info.
pick_types(QString(
"grad"),
false,
false, defaultQStringList, p_exclude);
320 QStringList info_ch_names = p_info.
ch_names;
321 QStringList ch_names_eeg, ch_names_mag, ch_names_grad;
322 for (qint32 i = 0; i < sel_eeg.size(); ++i)
323 ch_names_eeg << info_ch_names[sel_eeg(i)];
324 for (qint32 i = 0; i < sel_mag.size(); ++i)
325 ch_names_mag << info_ch_names[sel_mag(i)];
326 for (qint32 i = 0; i < sel_grad.size(); ++i)
327 ch_names_grad << info_ch_names[sel_grad(i)];
332 QStringList ch_names = cov_good.
names;
334 std::vector<qint32> idx_eeg, idx_mag, idx_grad;
335 for (qint32 i = 0; i < ch_names.size(); ++i) {
336 if (ch_names_eeg.contains(ch_names[i]))
337 idx_eeg.push_back(i);
338 else if (ch_names_mag.contains(ch_names[i]))
339 idx_mag.push_back(i);
340 else if (ch_names_grad.contains(ch_names[i]))
341 idx_grad.push_back(i);
344 MatrixXd C(cov_good.
data);
347 if (
static_cast<unsigned>(C.rows()) != idx_eeg.size() + idx_mag.size() + idx_grad.size()) {
348 qWarning(
"FiffCov::regularize: %lld channels in cov but only %zu classified as EEG/MAG/GRAD (others will not be regularized)",
349 static_cast<long long>(C.rows()), idx_eeg.size() + idx_mag.size() + idx_grad.size());
352 QList<FiffProj> t_listProjs;
359 QMap<QString, QPair<double, std::vector<qint32>>> regData;
360 regData.insert(
"EEG", QPair<
double, std::vector<qint32>>(p_fRegEeg, idx_eeg));
361 regData.insert(
"MAG", QPair<
double, std::vector<qint32>>(p_fRegMag, idx_mag));
362 regData.insert(
"GRAD", QPair<
double, std::vector<qint32>>(p_fRegGrad, idx_grad));
367 QMap<QString, QPair<double, std::vector<qint32>>>::Iterator it;
368 for (it = regData.begin(); it != regData.end(); ++it) {
369 QString desc(it.key());
370 double reg = it.value().first;
371 std::vector<qint32> idx = it.value().second;
373 if (idx.size() == 0 || reg == 0.0)
374 qInfo(
"\tNothing to regularize within %s data.\n", desc.toUtf8().constData());
376 qInfo(
"\tRegularize %s: %f\n", desc.toUtf8().constData(), reg);
377 MatrixXd this_C(idx.size(), idx.size());
378 for (quint32 i = 0; i < idx.size(); ++i)
379 for (quint32 j = 0; j < idx.size(); ++j)
380 this_C(i, j) = cov_good.
data(idx[i], idx[j]);
388 QStringList this_ch_names;
389 for (quint32 k = 0; k < idx.size(); ++k)
390 this_ch_names << ch_names[idx[k]];
395 JacobiSVD<MatrixXd>
svd(P, ComputeFullU);
397 VectorXd t_s =
svd.singularValues();
398 MatrixXd t_U =
svd.matrixU();
401 U = t_U.block(0, 0, t_U.rows(), t_U.cols() - ncomp);
404 qInfo(
"\tCreated an SSP operator for %s (dimension = %d).\n", desc.toUtf8().constData(), ncomp);
405 this_C = U.transpose() * (this_C * U);
409 double sigma = this_C.diagonal().mean();
410 this_C.diagonal() = this_C.diagonal().array() + reg * sigma;
411 if (p_bProj && ncomp > 0)
412 this_C = U * (this_C * U.transpose());
414 for (qint32 i = 0; i < this_C.rows(); ++i)
415 for (qint32 j = 0; j < this_C.cols(); ++j)
416 C(idx[i], idx[j]) = this_C(i, j);
422 for (qint32 i = 0; i < idx.size(); ++i)
423 for (qint32 j = 0; j < idx.size(); ++j)
424 cov.
data(idx[i], idx[j]) = C(i, j);
453 const MatrixXi& events,
454 const QList<int>& eventCodes,
461 unsigned int ignoreMask,
469 int minSamp =
static_cast<int>(std::round(tmin * sfreq));
470 int maxSamp =
static_cast<int>(std::round(tmax * sfreq));
471 int ns = maxSamp - minSamp + 1;
472 int delaySamp =
static_cast<int>(std::round(delay * sfreq));
475 qWarning() <<
"[FiffCov::compute_from_epochs] Invalid time window.";
479 int bminSamp = 0, bmaxSamp = 0;
481 bminSamp =
static_cast<int>(std::round(bmin * sfreq)) - minSamp;
482 bmaxSamp =
static_cast<int>(std::round(bmax * sfreq)) - minSamp;
485 MatrixXd covAccum = MatrixXd::Zero(nchan, nchan);
486 VectorXd meanAccum = VectorXd::Zero(nchan);
487 int totalSamples = 0;
490 for (
int k = 0; k < events.rows(); ++k) {
491 int evFrom = events(k, 1) & ~static_cast<int>(ignoreMask);
492 int evTo = events(k, 2) & ~static_cast<int>(ignoreMask);
496 for (
int ec = 0; ec < eventCodes.size(); ++ec) {
497 if (evFrom == 0 && evTo == eventCodes[ec]) {
505 int evSample = events(k, 0);
506 int epochStart = evSample + delaySamp + minSamp;
507 int epochEnd = evSample + delaySamp + maxSamp;
509 if (epochStart < raw.first_samp || epochEnd > raw.
last_samp)
518 qInfo().noquote() <<
"[FiffCov::compute_from_epochs] Rejected epoch at" << evSample << reason;
524 int bminIdx = qMax(0, bminSamp);
525 int bmaxIdx = qMin(
static_cast<int>(epochData.cols()) - 1, bmaxSamp);
526 if (bmaxIdx >= bminIdx) {
527 int nBase = bmaxIdx - bminIdx + 1;
528 for (
int c = 0; c < nchan; ++c) {
529 double baseVal = epochData.row(c).segment(bminIdx, nBase).mean();
530 epochData.row(c).array() -= baseVal;
537 VectorXd epochMean = epochData.rowwise().mean();
538 meanAccum += epochMean *
static_cast<double>(ns);
540 covAccum += epochData * epochData.transpose();
545 if (totalSamples < 2) {
546 qWarning() <<
"[FiffCov::compute_from_epochs] Not enough data.";
551 VectorXd grandMean = meanAccum /
static_cast<double>(totalSamples);
552 cov.
data = (covAccum /
static_cast<double>(totalSamples - 1)) - (grandMean * grandMean.transpose()) * (
static_cast<double>(totalSamples) / (totalSamples - 1));
554 cov.
data = covAccum /
static_cast<double>(totalSamples - 1);
560 cov.
nfree = totalSamples - 1;
564 qInfo() <<
"[FiffCov::compute_from_epochs] Computed:" << nchan <<
"channels,"
565 << nAccepted <<
"epochs," << totalSamples <<
"total samples.";
static FiffCov compute_from_epochs(const FiffRawData &raw, const Eigen::MatrixXi &events, const QList< int > &eventCodes, float tmin, float tmax, float bmin=0.0f, float bmax=0.0f, bool doBaseline=false, bool removeMean=true, unsigned int ignoreMask=0, float delay=0.0f, const RejectionParams *rej=nullptr)