v2.0.0
Loading...
Searching...
No Matches
fiff_epochs.cpp
Go to the documentation of this file.
1//=============================================================================================================
16
17//=============================================================================================================
18// INCLUDES
19//=============================================================================================================
20
21#include "fiff_epochs.h"
22#include "fiff_evoked.h"
23
24//=============================================================================================================
25// QT INCLUDES
26//=============================================================================================================
27
28#include <QDebug>
29
30//=============================================================================================================
31// STD INCLUDES
32//=============================================================================================================
33
34#include <cmath>
35
36//=============================================================================================================
37// USED NAMESPACES
38//=============================================================================================================
39
40using namespace FIFFLIB;
41using namespace Eigen;
42
43//=============================================================================================================
44// DEFINE MEMBER METHODS
45//=============================================================================================================
46
47QList<FiffEpochData> FiffEpochs::makeFixedLengthEpochs(const MatrixXd& matData,
48 double dSFreq,
49 double dDuration,
50 double dOverlap,
51 bool bDropLast)
52{
53 QList<FiffEpochData> epochs;
54
55 if (matData.size() == 0 || dSFreq <= 0.0 || dDuration <= 0.0) {
56 qWarning() << "[FiffEpochs::makeFixedLengthEpochs] Invalid input parameters.";
57 return epochs;
58 }
59
60 if (dOverlap >= dDuration) {
61 qWarning() << "[FiffEpochs::makeFixedLengthEpochs] Overlap must be less than duration.";
62 return epochs;
63 }
64
65 const int nCh = static_cast<int>(matData.rows());
66 const int nTimes = static_cast<int>(matData.cols());
67 const int epochSamples = static_cast<int>(std::round(dDuration * dSFreq));
68 const int stepSamples = static_cast<int>(std::round((dDuration - dOverlap) * dSFreq));
69
70 if (epochSamples <= 0 || stepSamples <= 0)
71 return epochs;
72
73 int start = 0;
74 while (start + epochSamples <= nTimes) {
75 FiffEpochData epoch;
76 epoch.data = matData.block(0, start, nCh, epochSamples);
77 epoch.tmin = static_cast<double>(start) / dSFreq;
78 epoch.tmax = static_cast<double>(start + epochSamples - 1) / dSFreq;
79 epochs.append(epoch);
80 start += stepSamples;
81 }
82
83 // Handle remaining samples if not dropping last
84 if (!bDropLast && start < nTimes) {
85 int remaining = nTimes - start;
86 FiffEpochData epoch;
87 epoch.data = matData.block(0, start, nCh, remaining);
88 epoch.tmin = static_cast<double>(start) / dSFreq;
89 epoch.tmax = static_cast<double>(nTimes - 1) / dSFreq;
90 epochs.append(epoch);
91 }
92
93 return epochs;
94}
95
96//=============================================================================================================
97
98QList<FiffEpochData> FiffEpochs::concatenateEpochs(const QList<QList<FiffEpochData>>& epochSets)
99{
100 QList<FiffEpochData> result;
101
102 for (const auto& epochSet : epochSets)
103 result.append(epochSet);
104
105 return result;
106}
107
108//=============================================================================================================
109
110FiffEvoked FiffEpochs::averageEpochs(const QList<FiffEpochData>& epochs,
111 double dSFreq,
112 const QString& comment)
113{
114 FiffEvoked evoked;
115
116 if (epochs.isEmpty()) {
117 qWarning() << "[FiffEpochs::averageEpochs] Empty epoch list.";
118 return evoked;
119 }
120
121 const int nCh = static_cast<int>(epochs[0].data.rows());
122 const int nTimes = static_cast<int>(epochs[0].data.cols());
123 const int nEpochs = epochs.size();
124
125 MatrixXd avg = MatrixXd::Zero(nCh, nTimes);
126
127 for (const auto& epoch : epochs) {
128 if (epoch.data.rows() != nCh || epoch.data.cols() != nTimes) {
129 qWarning() << "[FiffEpochs::averageEpochs] Inconsistent epoch dimensions; skipping.";
130 continue;
131 }
132 avg += epoch.data;
133 }
134
135 avg /= static_cast<double>(nEpochs);
136
137 // Populate the evoked
138 evoked.data = avg;
139 evoked.nave = nEpochs;
141 evoked.comment = comment;
142
143 // Compute times vector from the first epoch
144 const double tmin = epochs[0].tmin;
145 evoked.first = static_cast<fiff_int_t>(std::round(tmin * dSFreq));
146 evoked.last = evoked.first + nTimes - 1;
147
148 RowVectorXf times(nTimes);
149 for (int i = 0; i < nTimes; ++i)
150 times(i) = static_cast<float>(tmin + static_cast<double>(i) / dSFreq);
151 evoked.times = times;
152
153 return evoked;
154}
155
156//=============================================================================================================
157
158QList<MatrixXd> FiffEpochs::toMatrixList(const QList<FiffEpochData>& epochs)
159{
160 QList<MatrixXd> result;
161 result.reserve(epochs.size());
162
163 for (const auto& epoch : epochs)
164 result.append(epoch.data);
165
166 return result;
167}
Static epoching utilities: cut a FiffRawData stream into fixed-length, event-aligned epochs.
#define FIFFV_ASPECT_AVERAGE
Definition fiff_file.h:431
Single averaged evoked response: time axis, samples, baseline, channel info and processing history.
FIFF file I/O, in-memory data structures and high-level readers/writers.
Eigen::MatrixXd data
Definition fiff_epochs.h:62
static QList< FiffEpochData > makeFixedLengthEpochs(const Eigen::MatrixXd &matData, double dSFreq, double dDuration, double dOverlap=0.0, bool bDropLast=true)
Create fixed-length epochs from continuous data.
static QList< FiffEpochData > concatenateEpochs(const QList< QList< FiffEpochData > > &epochSets)
Concatenate multiple epoch sets into a single list.
static QList< Eigen::MatrixXd > toMatrixList(const QList< FiffEpochData > &epochs)
Extract data matrices from epoch structures.
static FiffEvoked averageEpochs(const QList< FiffEpochData > &epochs, double dSFreq, const QString &comment="Average")
Compute the average (evoked response) across epochs.
Single averaged evoked response: time axis, data, baseline, channel info and averaging metadata.
Definition fiff_evoked.h:75
Eigen::RowVectorXf times
Eigen::MatrixXd data
fiff_int_t aspect_kind