39#include <Eigen/SparseCore>
64 qRegisterMetaType<FIFFLIB::FiffEvokedSet>(
"FIFFLIB::FiffEvokedSet");
65 qRegisterMetaType<FIFFLIB::FiffEvokedSet::SPtr>(
"FIFFLIB::FiffEvokedSet::SPtr");
72 qRegisterMetaType<FIFFLIB::FiffEvokedSet>(
"FIFFLIB::FiffEvokedSet");
73 qRegisterMetaType<FIFFLIB::FiffEvokedSet::SPtr>(
"FIFFLIB::FiffEvokedSet::SPtr");
76 throw std::runtime_error(
"Fiff evoked data set not found");
83: info(p_FiffEvokedSet.info)
84, evoked(p_FiffEvokedSet.evoked)
105 const QStringList& exclude)
const
113 if (sel.cols() > 0) {
116 res.
info = this->info;
119 QList<FiffEvoked>::ConstIterator ev;
120 for (ev = evoked.begin(); ev != evoked.end(); ++ev)
121 res.
evoked.push_back(ev->pick_channels(include, exclude));
135 qInfo(
"Data is already compensated as desired.\n");
142 for (qsizetype i = 0; i < p_FiffEvokedSet.
evoked.size(); ++i) {
156 if (!p_FiffEvokedSet.
evoked.size()) {
157 qWarning(
"No evoked response data sets in %s\n", p_FiffEvokedSet.
info.
filename.toUtf8().constData());
160 qInfo(
"\nFound %lld evoked response data sets in %s :\n",
static_cast<long long>(p_FiffEvokedSet.
evoked.size()), p_FiffEvokedSet.
info.
filename.toUtf8().constData());
162 for (qint32 i = 0; i < p_FiffEvokedSet.
evoked.size(); ++i) {
163 qInfo(
"%s (%s)\n", p_FiffEvokedSet.
evoked.at(i).comment.toUtf8().constData(), p_FiffEvokedSet.
evoked.at(i).aspectKindToString().toUtf8().constBegin());
172 FiffEvokedSet& p_FiffEvokedSet, QPair<float, float> baseline,
175 p_FiffEvokedSet.
clear();
181 QString t_sFileName = t_pStream->streamName();
183 qInfo(
"Exploring %s ...\n", t_sFileName.toUtf8().constData());
185 if (!t_pStream->open())
191 if (!t_pStream->read_meas_info(t_pStream->dirtree(), p_FiffEvokedSet.
info, meas))
198 if (processed.size() == 0) {
199 qWarning(
"Could not find processed data");
203 QList<FiffDirNode::SPtr> evoked_node = meas->dir_tree_find(
FIFFB_EVOKED);
204 if (evoked_node.size() == 0) {
205 qWarning(
"Could not find evoked data");
209 QStringList comments;
210 QList<fiff_int_t> aspect_kinds;
212 if (!t_pStream->get_evoked_entries(evoked_node, comments, aspect_kinds, t))
213 t = QString(
"None found, must use integer");
214 qInfo(
"\tFound %lld datasets\n",
static_cast<long long>(evoked_node.size()));
216 for (qint32 i = 0; i < comments.size(); ++i) {
218 qInfo(
">> Processing %s <<\n", comments[i].toUtf8().constData());
221 p_FiffEvokedSet.
evoked.push_back(t_FiffEvoked);
231 if (fileName.isEmpty()) {
232 qWarning() <<
"[FiffEvokedSet::save] Output file not specified.";
236 QFile file(fileName);
239 qWarning() <<
"[FiffEvokedSet::save] Cannot open" << fileName;
243 pStream->write_evoked_set(*
this);
246 qInfo() <<
"[FiffEvokedSet::save] Saved" << evoked.size()
247 <<
"average(s) to" << fileName;
257 if (evokedSets.isEmpty()) {
258 qWarning() <<
"[FiffEvokedSet::computeGrandAverage] No evoked sets provided.";
262 grandAvg = evokedSets[0];
264 for (
int f = 1; f < evokedSets.size(); ++f) {
266 int nCat = qMin(grandAvg.
evoked.size(), eset.
evoked.size());
267 for (
int j = 0; j < nCat; ++j) {
268 if (grandAvg.
evoked[j].data.cols() == eset.
evoked[j].data.cols() &&
269 grandAvg.
evoked[j].data.rows() == eset.
evoked[j].data.rows()) {
276 for (
int j = 0; j < grandAvg.
evoked.size(); ++j) {
277 grandAvg.
evoked[j].data /=
static_cast<double>(evokedSets.size());
289 if (bmaxSamp >= epoch.cols())
290 bmaxSamp =
static_cast<int>(epoch.cols()) - 1;
291 if (bminSamp >= bmaxSamp)
294 int nBase = bmaxSamp - bminSamp + 1;
295 for (
int c = 0; c < epoch.rows(); ++c) {
296 double baseVal = epoch.row(c).segment(bminSamp, nBase).mean();
297 epoch.row(c).array() -= baseVal;
305 const MatrixXi& events,
315 log += QString(
"Averaging: %1\n").arg(desc.
comment);
318 for (
int j = 0; j < desc.
categories.size(); ++j) {
322 int minSamp =
static_cast<int>(std::round(cat.
tmin * sfreq));
323 int maxSamp =
static_cast<int>(std::round(cat.
tmax * sfreq));
324 int ns = maxSamp - minSamp + 1;
325 int delaySamp =
static_cast<int>(std::round(cat.
delay * sfreq));
328 int bminSamp = 0, bmaxSamp = 0;
330 bminSamp =
static_cast<int>(std::round(cat.
bmin * sfreq)) - minSamp;
331 bmaxSamp =
static_cast<int>(std::round(cat.
bmax * sfreq)) - minSamp;
335 MatrixXd sumData = MatrixXd::Zero(nchan, ns);
336 MatrixXd sumSqData = MatrixXd::Zero(nchan, ns);
339 log += QString(
"\n Category: %1\n").arg(cat.
comment);
340 log += QString(
" t = %1 ... %2 ms\n").arg(1000.0 * cat.
tmin, 0,
'f', 1).arg(1000.0 * cat.
tmax, 0,
'f', 1);
343 for (
int k = 0; k < events.rows(); ++k) {
347 int evSample = events(k, 0);
348 int epochStart = evSample + delaySamp + minSamp;
349 int epochEnd = evSample + delaySamp + maxSamp;
352 if (epochStart < raw.first_samp || epochEnd > raw.
last_samp)
359 log += QString(
" Error reading epoch at sample %1\n").arg(evSample);
365 if (!checkArtifacts(epochData, raw.
info, raw.
info.
bads, desc.
rej, rejReason)) {
366 log += QString(
" %1 %2 %3 %4 [%5] %6 [omit]\n")
368 .arg(
static_cast<float>(evSample) / sfreq, -10,
'f', 3)
369 .arg(events(k, 1), 3)
370 .arg(events(k, 2), 3)
378 subtractBaseline(epochData, bminSamp, bmaxSamp);
383 epochData = epochData.cwiseAbs();
387 sumData += epochData;
389 sumSqData += epochData.cwiseProduct(epochData);
393 log += QString(
" %1 %2 %3 %4 [%5]\n")
395 .arg(
static_cast<float>(evSample) / sfreq, -10,
'f', 3)
396 .arg(events(k, 1), 3)
397 .arg(events(k, 2), 3)
404 evoked.
first = minSamp;
405 evoked.
last = maxSamp;
409 RowVectorXf times(ns);
410 for (
int s = 0; s < ns; ++s)
411 times(s) =
static_cast<float>(minSamp + s) / sfreq;
412 evoked.
times = times;
415 evoked.
data = sumData /
static_cast<double>(nave);
417 evoked.
data = MatrixXd::Zero(nchan, ns);
422 evokedSet.
evoked.append(evoked);
423 log += QString(
" nave = %1\n").arg(nave);
433 const QStringList& bads,
437 for (
int c = 0; c < epoch.rows(); ++c) {
439 if (bads.contains(info.
ch_names[c]))
442 double minVal = epoch.row(c).minCoeff();
443 double maxVal = epoch.row(c).maxCoeff();
444 double pp = maxVal - minVal;
446 int chKind = info.
chs[c].kind;
447 int chUnit = info.
chs[c].unit;
453 reason = QString(
"%1 : %2 fT > %3 fT")
455 .arg(pp * 1e15, 0,
'f', 1)
460 reason = QString(
"%1 : %2 fT < %3 fT (flat)")
462 .arg(pp * 1e15, 0,
'f', 1)
469 reason = QString(
"%1 : %2 fT/cm > %3 fT/cm")
471 .arg(pp * 1e13, 0,
'f', 1)
476 reason = QString(
"%1 : %2 fT/cm < %3 fT/cm (flat)")
478 .arg(pp * 1e13, 0,
'f', 1)
485 reason = QString(
"%1 : %2 uV > %3 uV")
487 .arg(pp * 1e6, 0,
'f', 1)
492 reason = QString(
"%1 : %2 uV < %3 uV (flat)")
494 .arg(pp * 1e6, 0,
'f', 1)
495 .arg(rej.
eegFlat * 1e6, 0,
'f', 1);
500 reason = QString(
"%1 : %2 uV > %3 uV (EOG)")
502 .arg(pp * 1e6, 0,
'f', 1)
507 reason = QString(
"%1 : EOG flat").arg(info.
ch_names[c]);
512 reason = QString(
"%1 : %2 mV > %3 mV (ECG)")
514 .arg(pp * 1e3, 0,
'f', 2)
519 reason = QString(
"%1 : ECG flat").arg(info.
ch_names[c]);
Symbolic FIFF tag, block, value, unit and channel-type constants shared across FIFFLIB.
FIFF tag: the 16-byte tag header (kind, type, size, next) plus its decoded payload.
Set of averaged evoked responses sharing a FiffInfo, plus the ave-style category / rejection descript...
FIFF binary tag-stream layer: wraps a QIODevice to read and write FIFF tags, directories,...
FIFF tag-kind, block-kind and type-code numerical definitions, authoritative for FIFFLIB.
#define FIFFB_PROCESSED_DATA
Recursive node of the parsed FIFF block tree (FIFFB_* hierarchy with directory entries and children).
Stim-channel event list (sample, previous value, new value triples) with FIFF read/write helpers.
FIFF continuous raw recording: FiffInfo plus a directory of FIFF_DATA_BUFFER tags for random-access s...
FIFF file I/O, in-memory data structures and high-level readers/writers.
One CTF software-gradient compensation matrix: grade kind, calibration flag and the gradiometer × ref...
QSharedPointer< FiffDirNode > SPtr
static bool matchEvent(const AverageCategory &cat, const Eigen::MatrixXi &events, int eventIdx)
Single averaged evoked response: time axis, data, baseline, channel info and averaging metadata.
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)
Artifact-rejection thresholds for the MNE-C batch averaging pipeline (gradiometer / magnetometer / EE...
One averaging category in an MNE-C ave-description file: trigger logic, timing window,...
Top-level MNE-C ave-description record: comment, category list, shared rejection limits and output fi...
QList< AverageCategory > categories
Set of FiffEvoked instances sharing one FiffInfo, plus channel-picking and compensation helpers.
bool compensate_to(FiffEvokedSet &p_FiffEvokedSet, fiff_int_t to) const
static FiffEvokedSet computeAverages(const FiffRawData &raw, const AverageDescription &desc, const Eigen::MatrixXi &events, QString &log)
bool find_evoked(const FiffEvokedSet &p_FiffEvokedSet) const
static FiffEvokedSet computeGrandAverage(const QList< FiffEvokedSet > &evokedSets)
static bool checkArtifacts(const Eigen::MatrixXd &epoch, const FiffInfo &info, const QStringList &bads, const RejectionParams &rej, QString &reason)
static void subtractBaseline(Eigen::MatrixXd &epoch, int bminSamp, int bmaxSamp)
Subtract baseline from each channel of an epoch.
FiffEvokedSet pick_channels(const QStringList &include=defaultQStringList, const QStringList &exclude=defaultQStringList) const
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
Full FIFF measurement info: per-channel descriptors, sampling and filter setup, projectors,...
FiffInfo pick_info(const Eigen::RowVectorXi &sel=defaultVectorXi) const
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)
Continuous FIFF raw recording: FiffInfo plus a random-access directory of FIFF_DATA_BUFFER tags.
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
FIFF tag-stream reader/writer: wraps a QIODevice and exposes typed read_* / write_* methods for every...
QSharedPointer< FiffStream > SPtr
static FiffStream::SPtr start_file(QIODevice &p_IODevice)