54#include <Eigen/SparseCore>
79 qRegisterMetaType<FIFFLIB::FiffEvokedSet>(
"FIFFLIB::FiffEvokedSet");
80 qRegisterMetaType<FIFFLIB::FiffEvokedSet::SPtr>(
"FIFFLIB::FiffEvokedSet::SPtr");
87 qRegisterMetaType<FIFFLIB::FiffEvokedSet>(
"FIFFLIB::FiffEvokedSet");
88 qRegisterMetaType<FIFFLIB::FiffEvokedSet::SPtr>(
"FIFFLIB::FiffEvokedSet::SPtr");
92 throw std::runtime_error(
"Fiff evoked data set not found");
121 const QStringList& exclude)
const
129 if (sel.cols() > 0) {
130 res.
info = this->
info.pick_info(sel);
135 QList<FiffEvoked>::ConstIterator ev;
137 res.
evoked.push_back(ev->pick_channels(include, exclude));
152 qInfo(
"Data is already compensated as desired.\n");
159 for(qint16 i=0; i < p_FiffEvokedSet.
evoked.size(); ++i)
174 if(!p_FiffEvokedSet.
evoked.size()) {
175 qWarning(
"No evoked response data sets in %s\n",p_FiffEvokedSet.
info.
filename.toUtf8().constData());
179 qInfo(
"\nFound %lld evoked response data sets in %s :\n",p_FiffEvokedSet.
evoked.size(),p_FiffEvokedSet.
info.
filename.toUtf8().constData());
181 for(qint32 i = 0; i < p_FiffEvokedSet.
evoked.size(); ++i) {
182 qInfo(
"%s (%s)\n",p_FiffEvokedSet.
evoked.at(i).comment.toUtf8().constData(),p_FiffEvokedSet.
evoked.at(i).aspectKindToString().toUtf8().constBegin());
194 p_FiffEvokedSet.
clear();
200 QString t_sFileName = t_pStream->streamName();
202 qInfo(
"Exploring %s ...\n",t_sFileName.toUtf8().constData());
204 if(!t_pStream->open())
210 if(!t_pStream->read_meas_info(t_pStream->dirtree(), p_FiffEvokedSet.
info, meas))
217 if (processed.size() == 0)
219 qWarning(
"Could not find processed data");
223 QList<FiffDirNode::SPtr> evoked_node = meas->dir_tree_find(
FIFFB_EVOKED);
224 if (evoked_node.size() == 0)
226 qWarning(
"Could not find evoked data");
230 QStringList comments;
231 QList<fiff_int_t> aspect_kinds;
233 if(!t_pStream->get_evoked_entries(evoked_node, comments, aspect_kinds, t))
234 t = QString(
"None found, must use integer");
235 qInfo(
"\tFound %lld datasets\n", evoked_node.size());
237 for(qint32 i = 0; i < comments.size(); ++i)
240 qInfo(
">> Processing %s <<\n", comments[i].toUtf8().constData());
243 p_FiffEvokedSet.
evoked.push_back(t_FiffEvoked);
253 if (fileName.isEmpty()) {
254 qWarning() <<
"[FiffEvokedSet::save] Output file not specified.";
258 QFile file(fileName);
261 qWarning() <<
"[FiffEvokedSet::save] Cannot open" << fileName;
265 pStream->write_evoked_set(*
this);
268 qInfo() <<
"[FiffEvokedSet::save] Saved" <<
evoked.size()
269 <<
"average(s) to" << fileName;
279 if (evokedSets.isEmpty()) {
280 qWarning() <<
"[FiffEvokedSet::computeGrandAverage] No evoked sets provided.";
284 grandAvg = evokedSets[0];
286 for (
int f = 1; f < evokedSets.size(); ++f) {
288 int nCat = qMin(grandAvg.
evoked.size(), eset.
evoked.size());
289 for (
int j = 0; j < nCat; ++j) {
290 if (grandAvg.
evoked[j].data.cols() == eset.
evoked[j].data.cols() &&
291 grandAvg.
evoked[j].data.rows() == eset.
evoked[j].data.rows()) {
298 for (
int j = 0; j < grandAvg.
evoked.size(); ++j) {
299 grandAvg.
evoked[j].data /=
static_cast<double>(evokedSets.size());
309 if (bminSamp < 0) bminSamp = 0;
310 if (bmaxSamp >= epoch.cols()) bmaxSamp =
static_cast<int>(epoch.cols()) - 1;
311 if (bminSamp >= bmaxSamp)
return;
313 int nBase = bmaxSamp - bminSamp + 1;
314 for (
int c = 0; c < epoch.rows(); ++c) {
315 double baseVal = epoch.row(c).segment(bminSamp, nBase).mean();
316 epoch.row(c).array() -= baseVal;
324 const MatrixXi &events,
334 log += QString(
"Averaging: %1\n").arg(desc.
comment);
337 for (
int j = 0; j < desc.
categories.size(); ++j) {
341 int minSamp =
static_cast<int>(std::round(cat.
tmin * sfreq));
342 int maxSamp =
static_cast<int>(std::round(cat.
tmax * sfreq));
343 int ns = maxSamp - minSamp + 1;
344 int delaySamp =
static_cast<int>(std::round(cat.
delay * sfreq));
347 int bminSamp = 0, bmaxSamp = 0;
349 bminSamp =
static_cast<int>(std::round(cat.
bmin * sfreq)) - minSamp;
350 bmaxSamp =
static_cast<int>(std::round(cat.
bmax * sfreq)) - minSamp;
354 MatrixXd sumData = MatrixXd::Zero(nchan, ns);
355 MatrixXd sumSqData = MatrixXd::Zero(nchan, ns);
358 log += QString(
"\n Category: %1\n").arg(cat.
comment);
359 log += QString(
" t = %.1f ... %.1f ms\n").arg(1000.0 * cat.
tmin).arg(1000.0 * cat.
tmax);
362 for (
int k = 0; k < events.rows(); ++k) {
366 int evSample = events(k, 0);
367 int epochStart = evSample + delaySamp + minSamp;
368 int epochEnd = evSample + delaySamp + maxSamp;
371 if (epochStart < raw.first_samp || epochEnd > raw.
last_samp)
378 log += QString(
" Error reading epoch at sample %1\n").arg(evSample);
385 log += QString(
" %1 %2 %3 %4 [%5] %6 [omit]\n")
387 .arg(
static_cast<float>(evSample) / sfreq, -10,
'f', 3)
388 .arg(events(k, 1), 3)
389 .arg(events(k, 2), 3)
402 epochData = epochData.cwiseAbs();
406 sumData += epochData;
408 sumSqData += epochData.cwiseProduct(epochData);
412 log += QString(
" %1 %2 %3 %4 [%5]\n")
414 .arg(
static_cast<float>(evSample) / sfreq, -10,
'f', 3)
415 .arg(events(k, 1), 3)
416 .arg(events(k, 2), 3)
428 RowVectorXf times(ns);
429 for (
int s = 0; s < ns; ++s)
430 times(s) =
static_cast<float>(minSamp + s) / sfreq;
434 evoked.data = sumData /
static_cast<double>(nave);
436 evoked.data = MatrixXd::Zero(nchan, ns);
442 log += QString(
" nave = %1\n").arg(nave);
452 const QStringList &bads,
456 for (
int c = 0; c < epoch.rows(); ++c) {
458 if (bads.contains(
info.ch_names[c]))
461 double minVal = epoch.row(c).minCoeff();
462 double maxVal = epoch.row(c).maxCoeff();
463 double pp = maxVal - minVal;
465 int chKind =
info.chs[c].kind;
466 int chUnit =
info.chs[c].unit;
472 reason = QString(
"%1 : %.1f fT > %.1f fT")
473 .arg(
info.ch_names[c])
478 reason = QString(
"%1 : %.1f fT < %.1f fT (flat)")
479 .arg(
info.ch_names[c])
486 reason = QString(
"%1 : %.1f fT/cm > %.1f fT/cm")
487 .arg(
info.ch_names[c])
492 reason = QString(
"%1 : %.1f fT/cm < %.1f fT/cm (flat)")
493 .arg(
info.ch_names[c])
500 reason = QString(
"%1 : %.1f uV > %.1f uV")
501 .arg(
info.ch_names[c])
506 reason = QString(
"%1 : %.1f uV < %.1f uV (flat)")
507 .arg(
info.ch_names[c])
508 .arg(pp * 1e6).arg(rej.
eegFlat * 1e6);
513 reason = QString(
"%1 : %.1f uV > %.1f uV (EOG)")
514 .arg(
info.ch_names[c])
519 reason = QString(
"%1 : EOG flat").arg(
info.ch_names[c]);
524 reason = QString(
"%1 : %.2f mV > %.2f mV (ECG)")
525 .arg(
info.ch_names[c])
530 reason = QString(
"%1 : ECG flat").arg(
info.ch_names[c]);
FiffRawData class declaration.
FiffEvents class declaration.
FiffEvokedSet class declaration.
FiffDirNode class declaration, which provides fiff dir tree processing methods.
Header file describing the numerical values used in fif files.
#define FIFFB_PROCESSED_DATA
FiffStream class declaration.
FiffTag class declaration, which provides fiff tag I/O and processing methods.
FIFF file I/O and data structures (raw, epochs, evoked, covariance, forward).
CTF software compensation data.
QSharedPointer< FiffDirNode > SPtr
static bool matchEvent(const AverageCategory &cat, const Eigen::MatrixXi &events, int eventIdx)
static bool read(QIODevice &p_IODevice, FiffEvoked &p_FiffEvoked, QVariant setno=0, QPair< float, float > t_baseline=defaultFloatPair, bool proj=true, fiff_int_t p_aspect_kind=FIFFV_ASPECT_AVERAGE)
QList< AverageCategory > categories
bool compensate_to(FiffEvokedSet &p_FiffEvokedSet, fiff_int_t to) const
bool find_evoked(const FiffEvokedSet &p_FiffEvokedSet) const
static FiffEvokedSet computeAverages(const FiffRawData &raw, const AverageDescription &desc, const Eigen::MatrixXi &events, QString &log)
static void subtractBaseline(Eigen::MatrixXd &epoch, int bminSamp, int bmaxSamp)
Subtract baseline from each channel of an epoch.
static bool checkArtifacts(const Eigen::MatrixXd &epoch, const FiffInfo &info, const QStringList &bads, const RejectionParams &rej, QString &reason)
FiffEvokedSet pick_channels(const QStringList &include=defaultQStringList, const QStringList &exclude=defaultQStringList) const
static FiffEvokedSet computeGrandAverage(const QList< FiffEvokedSet > &evokedSets)
static bool read(QIODevice &p_IODevice, FiffEvokedSet &p_FiffEvokedSet, QPair< float, float > baseline=defaultFloatPair, bool proj=true)
QList< FiffEvoked > evoked
bool save(const QString &fileName) const
FIFF measurement file information.
void set_current_comp(fiff_int_t value)
qint32 get_current_comp()
bool make_compensator(fiff_int_t from, fiff_int_t to, FiffCtfComp &ctf_comp, bool exclude_comp_chs=false) const
static Eigen::RowVectorXi pick_channels(const QStringList &ch_names, const QStringList &include=defaultQStringList, const QStringList &exclude=defaultQStringList)
FIFF raw measurement data.
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
QSharedPointer< FiffStream > SPtr
static FiffStream::SPtr start_file(QIODevice &p_IODevice)