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