v2.0.0
Loading...
Searching...
No Matches
epoch_extractor.cpp
Go to the documentation of this file.
1//=============================================================================================================
12
13//=============================================================================================================
14// INCLUDES
15//=============================================================================================================
16
17#include "epoch_extractor.h"
18
19//=============================================================================================================
20// EIGEN INCLUDES
21//=============================================================================================================
22
23#include <Eigen/Core>
24
25//=============================================================================================================
26// QT INCLUDES
27//=============================================================================================================
28
29#include <QDebug>
30
31//=============================================================================================================
32// C++ INCLUDES
33//=============================================================================================================
34
35#include <cmath>
36#include <algorithm>
37
38//=============================================================================================================
39// USED NAMESPACES
40//=============================================================================================================
41
42using namespace UTILSLIB;
43using namespace MNELIB;
44using namespace Eigen;
45
46//=============================================================================================================
47// PRIVATE
48//=============================================================================================================
49
50void EpochExtractor::applyBaseline(MatrixXd& matEpoch, int iBase0, int iBase1)
51{
52 if (iBase0 > iBase1 || iBase0 < 0 || iBase1 >= matEpoch.cols())
53 return;
54 const int nBaseSamp = iBase1 - iBase0 + 1;
55 // Per-channel baseline mean
56 VectorXd baseline = matEpoch.block(0, iBase0, matEpoch.rows(), nBaseSamp).rowwise().mean();
57 matEpoch.colwise() -= baseline;
58}
59
60//=============================================================================================================
61// PUBLIC
62//=============================================================================================================
63
64QVector<MNEEpochData> EpochExtractor::extract(const MatrixXd& matData,
65 const QVector<int>& eventSamples,
66 double dSFreq,
67 const Params& params,
68 const QVector<int>& eventCodes)
69{
70 QVector<MNEEpochData> epochs;
71
72 if (matData.size() == 0 || eventSamples.isEmpty())
73 return epochs;
74 if (dSFreq <= 0.0) {
75 qWarning() << "EpochExtractor::extract: invalid sampling frequency.";
76 return epochs;
77 }
78
79 const int nSamp = static_cast<int>(matData.cols());
80 const int nCh = static_cast<int>(matData.rows());
81
82 // Convert time to sample offsets
83 const int iOffset0 = static_cast<int>(std::round(params.dTmin * dSFreq));
84 const int iOffset1 = static_cast<int>(std::round(params.dTmax * dSFreq));
85 const int epochLen = iOffset1 - iOffset0 + 1;
86
87 if (epochLen <= 0) {
88 qWarning() << "EpochExtractor::extract: tmax must be > tmin.";
89 return epochs;
90 }
91
92 // Baseline window sample indices within the epoch (0-based)
93 const int iBase0 = static_cast<int>(std::round((params.dBaseMin - params.dTmin) * dSFreq));
94 const int iBase1 = static_cast<int>(std::round((params.dBaseMax - params.dTmin) * dSFreq));
95
96 const bool bHaveCodes = (eventCodes.size() == eventSamples.size());
97
98 for (int ev = 0; ev < eventSamples.size(); ++ev) {
99 const int evSamp = eventSamples[ev];
100 const int s0 = evSamp + iOffset0;
101 const int s1 = evSamp + iOffset1;
102
103 // Skip if epoch extends outside the recording
104 if (s0 < 0 || s1 >= nSamp)
105 continue;
106
107 MNEEpochData epoch;
108 epoch.epoch = matData.block(0, s0, nCh, epochLen);
109 epoch.tmin = static_cast<float>(params.dTmin);
110 epoch.tmax = static_cast<float>(params.dTmax);
111 epoch.event = bHaveCodes ? eventCodes[ev] : 1;
112 epoch.bReject = false;
113
114 // Baseline correction
115 if (params.bApplyBaseline) {
116 applyBaseline(epoch.epoch, iBase0, iBase1);
117 }
118
119 // Amplitude rejection: peak-to-peak per channel
120 if (params.dThreshold > 0.0) {
121 for (int ch = 0; ch < nCh; ++ch) {
122 const RowVectorXd row = epoch.epoch.row(ch);
123 double ptp = row.maxCoeff() - row.minCoeff();
124 if (ptp > params.dThreshold) {
125 epoch.bReject = true;
126 break;
127 }
128 }
129 }
130
131 epochs.append(epoch);
132 }
133
134 return epochs;
135}
136
137//=============================================================================================================
138
139MatrixXd EpochExtractor::average(const QVector<MNEEpochData>& epochs)
140{
141 MatrixXd result;
142 int nGood = 0;
143
144 for (const MNEEpochData& ep : epochs) {
145 if (ep.bReject)
146 continue;
147 if (result.size() == 0) {
148 result = ep.epoch;
149 } else {
150 if (ep.epoch.rows() != result.rows() || ep.epoch.cols() != result.cols()) {
151 qWarning() << "EpochExtractor::average: epoch dimension mismatch, skipping.";
152 continue;
153 }
154 result += ep.epoch;
155 }
156 ++nGood;
157 }
158
159 if (nGood > 1)
160 result /= static_cast<double>(nGood);
161 return result;
162}
163
164//=============================================================================================================
165
166QVector<MNEEpochData> EpochExtractor::rejectMarked(const QVector<MNEEpochData>& epochs)
167{
168 QVector<MNEEpochData> good;
169 good.reserve(epochs.size());
170 for (const MNEEpochData& ep : epochs) {
171 if (!ep.bReject)
172 good.append(ep);
173 }
174 return good;
175}
Declaration of EpochExtractor — segments continuous MEG/EEG data into trials.
Core MNE data structures (source spaces, source estimates, hemispheres).
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
static QVector< MNELIB::MNEEpochData > rejectMarked(const QVector< MNELIB::MNEEpochData > &epochs)
static QVector< MNELIB::MNEEpochData > extract(const Eigen::MatrixXd &matData, const QVector< int > &eventSamples, double dSFreq, const Params &params=Params(), const QVector< int > &eventCodes=QVector< int >())
EpochExtractorParams Params
static Eigen::MatrixXd average(const QVector< MNELIB::MNEEpochData > &epochs)
Single epoch (trial slice) of sensor data with timing and rejection metadata.
Eigen::MatrixXd epoch
FIFFLIB::fiff_int_t event