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()) return;
53 const int nBaseSamp = iBase1 - iBase0 + 1;
54 // Per-channel baseline mean
55 VectorXd baseline = matEpoch.block(0, iBase0, matEpoch.rows(), nBaseSamp).rowwise().mean();
56 matEpoch.colwise() -= baseline;
57}
58
59//=============================================================================================================
60// PUBLIC
61//=============================================================================================================
62
63QVector<MNEEpochData> EpochExtractor::extract(const MatrixXd& matData,
64 const QVector<int>& eventSamples,
65 double dSFreq,
66 const Params& params,
67 const QVector<int>& eventCodes)
68{
69 QVector<MNEEpochData> epochs;
70
71 if (matData.size() == 0 || eventSamples.isEmpty()) return epochs;
72 if (dSFreq <= 0.0) {
73 qWarning() << "EpochExtractor::extract: invalid sampling frequency.";
74 return epochs;
75 }
76
77 const int nSamp = static_cast<int>(matData.cols());
78 const int nCh = static_cast<int>(matData.rows());
79
80 // Convert time to sample offsets
81 const int iOffset0 = static_cast<int>(std::round(params.dTmin * dSFreq));
82 const int iOffset1 = static_cast<int>(std::round(params.dTmax * dSFreq));
83 const int epochLen = iOffset1 - iOffset0 + 1;
84
85 if (epochLen <= 0) {
86 qWarning() << "EpochExtractor::extract: tmax must be > tmin.";
87 return epochs;
88 }
89
90 // Baseline window sample indices within the epoch (0-based)
91 const int iBase0 = static_cast<int>(std::round((params.dBaseMin - params.dTmin) * dSFreq));
92 const int iBase1 = static_cast<int>(std::round((params.dBaseMax - params.dTmin) * dSFreq));
93
94 const bool bHaveCodes = (eventCodes.size() == eventSamples.size());
95
96 for (int ev = 0; ev < eventSamples.size(); ++ev) {
97 const int evSamp = eventSamples[ev];
98 const int s0 = evSamp + iOffset0;
99 const int s1 = evSamp + iOffset1;
100
101 // Skip if epoch extends outside the recording
102 if (s0 < 0 || s1 >= nSamp) continue;
103
104 MNEEpochData epoch;
105 epoch.epoch = matData.block(0, s0, nCh, epochLen);
106 epoch.tmin = static_cast<float>(params.dTmin);
107 epoch.tmax = static_cast<float>(params.dTmax);
108 epoch.event = bHaveCodes ? eventCodes[ev] : 1;
109 epoch.bReject = false;
110
111 // Baseline correction
112 if (params.bApplyBaseline) {
113 applyBaseline(epoch.epoch, iBase0, iBase1);
114 }
115
116 // Amplitude rejection: peak-to-peak per channel
117 if (params.dThreshold > 0.0) {
118 for (int ch = 0; ch < nCh; ++ch) {
119 const RowVectorXd row = epoch.epoch.row(ch);
120 double ptp = row.maxCoeff() - row.minCoeff();
121 if (ptp > params.dThreshold) {
122 epoch.bReject = true;
123 break;
124 }
125 }
126 }
127
128 epochs.append(epoch);
129 }
130
131 return epochs;
132}
133
134//=============================================================================================================
135
136MatrixXd EpochExtractor::average(const QVector<MNEEpochData>& epochs)
137{
138 MatrixXd result;
139 int nGood = 0;
140
141 for (const MNEEpochData& ep : epochs) {
142 if (ep.bReject) continue;
143 if (result.size() == 0) {
144 result = ep.epoch;
145 } else {
146 if (ep.epoch.rows() != result.rows() || ep.epoch.cols() != result.cols()) {
147 qWarning() << "EpochExtractor::average: epoch dimension mismatch, skipping.";
148 continue;
149 }
150 result += ep.epoch;
151 }
152 ++nGood;
153 }
154
155 if (nGood > 1) result /= static_cast<double>(nGood);
156 return result;
157}
158
159//=============================================================================================================
160
161QVector<MNEEpochData> EpochExtractor::rejectMarked(const QVector<MNEEpochData>& epochs)
162{
163 QVector<MNEEpochData> good;
164 good.reserve(epochs.size());
165 for (const MNEEpochData& ep : epochs) {
166 if (!ep.bReject) good.append(ep);
167 }
168 return good;
169}
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