54#include <Eigen/SparseCore>
78 qRegisterMetaType<FIFFLIB::FiffEvokedSet>(
"FIFFLIB::FiffEvokedSet");
79 qRegisterMetaType<FIFFLIB::FiffEvokedSet::SPtr>(
"FIFFLIB::FiffEvokedSet::SPtr");
86 qRegisterMetaType<FIFFLIB::FiffEvokedSet>(
"FIFFLIB::FiffEvokedSet");
87 qRegisterMetaType<FIFFLIB::FiffEvokedSet::SPtr>(
"FIFFLIB::FiffEvokedSet::SPtr");
91 qWarning(
"\tFiff evoked data set not found.\n");
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;
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]);
FiffTag class declaration, which provides fiff tag I/O and processing methods.
FiffStream class declaration.
FiffRawData class declaration.
FiffDirNode class declaration, which provides fiff dir tree processing methods.
FiffEvokedSet class declaration.
Header file describing the numerical values used in fif files.
#define FIFFB_PROCESSED_DATA
FiffEvents class declaration.
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)