v2.0.0
Loading...
Searching...
No Matches
eog_regression.cpp
Go to the documentation of this file.
1//=============================================================================================================
12
13//=============================================================================================================
14// INCLUDES
15//=============================================================================================================
16
17#include "eog_regression.h"
18
19#include <fiff/fiff_info.h>
20#include <fiff/fiff_ch_info.h>
21#include <fiff/fiff_constants.h>
22
23//=============================================================================================================
24// QT INCLUDES
25//=============================================================================================================
26
27#include <QDebug>
28
29//=============================================================================================================
30// EIGEN INCLUDES
31//=============================================================================================================
32
33#include <Eigen/Cholesky>
34
35//=============================================================================================================
36// USED NAMESPACES
37//=============================================================================================================
38
39using namespace UTILSLIB;
40using namespace FIFFLIB;
41using namespace Eigen;
42
43//=============================================================================================================
44// DEFINE MEMBER METHODS
45//=============================================================================================================
46
47void EogRegression::fit(const MatrixXd& data,
48 const FiffInfo& info,
49 const QStringList& eogChannels)
50{
51 //
52 // Determine EOG channel indices
53 //
54 m_vecEogIndices.clear();
55 m_vecTargetIndices.clear();
56 m_bFitted = false;
57
58 if (eogChannels.isEmpty()) {
59 // Auto-detect EOG channels from info
60 for (int i = 0; i < info.chs.size(); ++i) {
61 if (info.chs[i].kind == FIFFV_EOG_CH) {
62 m_vecEogIndices.append(i);
63 }
64 }
65 } else {
66 // Use explicitly specified channel names
67 for (const QString& name : eogChannels) {
68 int idx = info.ch_names.indexOf(name);
69 if (idx >= 0) {
70 m_vecEogIndices.append(idx);
71 } else {
72 qWarning() << "[EogRegression::fit] EOG channel not found:" << name;
73 }
74 }
75 }
76
77 if (m_vecEogIndices.isEmpty()) {
78 qWarning() << "[EogRegression::fit] No EOG channels found. Data will not be modified.";
79 return;
80 }
81
82 //
83 // Build target index list: all channels NOT in the EOG set
84 //
85 for (int i = 0; i < info.chs.size(); ++i) {
86 if (!m_vecEogIndices.contains(i)) {
87 m_vecTargetIndices.append(i);
88 }
89 }
90
91 const int nEog = m_vecEogIndices.size();
92 const int nTargets = m_vecTargetIndices.size();
93 const int nTimes = static_cast<int>(data.cols());
94
95 //
96 // Extract EOG submatrix E (n_eog x n_times)
97 //
98 MatrixXd E(nEog, nTimes);
99 for (int i = 0; i < nEog; ++i) {
100 E.row(i) = data.row(m_vecEogIndices[i]);
101 }
102
103 //
104 // Extract target submatrix T (n_targets x n_times)
105 //
106 MatrixXd T(nTargets, nTimes);
107 for (int i = 0; i < nTargets; ++i) {
108 T.row(i) = data.row(m_vecTargetIndices[i]);
109 }
110
111 //
112 // Compute beta via least squares:
113 // beta = T * E^T * (E * E^T)^{-1}
114 //
115 // More numerically stable: solve (E * E^T) * X = E * T^T, then beta = X^T
116 //
117 MatrixXd EET = E * E.transpose(); // n_eog x n_eog
118 MatrixXd ETT = E * T.transpose(); // n_eog x n_targets
119
120 m_matBeta = EET.ldlt().solve(ETT).transpose(); // n_targets x n_eog
121
122 m_bFitted = true;
123}
124
125//=============================================================================================================
126
127void EogRegression::apply(MatrixXd& data,
128 const FiffInfo& info) const
129{
130 Q_UNUSED(info)
131
132 if (!m_bFitted) {
133 qWarning() << "[EogRegression::apply] Not fitted yet. Call fit() first.";
134 return;
135 }
136
137 const int nEog = m_vecEogIndices.size();
138 const int nTargets = m_vecTargetIndices.size();
139 const int nTimes = static_cast<int>(data.cols());
140
141 //
142 // Extract EOG submatrix E (n_eog x n_times)
143 //
144 MatrixXd E(nEog, nTimes);
145 for (int i = 0; i < nEog; ++i) {
146 E.row(i) = data.row(m_vecEogIndices[i]);
147 }
148
149 //
150 // Subtract: for each target channel i, data.row(targetIdx) -= beta.row(i) * E
151 //
152 for (int i = 0; i < nTargets; ++i) {
153 data.row(m_vecTargetIndices[i]) -= m_matBeta.row(i) * E;
154 }
155}
156
157//=============================================================================================================
158
159void EogRegression::fitApply(MatrixXd& data,
160 const FiffInfo& info,
161 const QStringList& eogChannels)
162{
163 EogRegression reg;
164 reg.fit(data, info, eogChannels);
165 reg.apply(data, info);
166}
Symbolic FIFF tag, block, value, unit and channel-type constants shared across FIFFLIB.
#define FIFFV_EOG_CH
FIFF channel descriptor record (FIFF_CH_INFO): per-channel logical/scanner numbers,...
Full FIFF measurement metadata: everything from FIFFB_MEAS / FIFFB_MEAS_INFO needed to interpret a re...
Declaration of EogRegression — EOG artifact removal via linear regression.
FIFF file I/O, in-memory data structures and high-level readers/writers.
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
void apply(Eigen::MatrixXd &data, const FIFFLIB::FiffInfo &info) const
Apply the fitted regression to remove EOG artifacts in-place.
static void fitApply(Eigen::MatrixXd &data, const FIFFLIB::FiffInfo &info, const QStringList &eogChannels=QStringList())
Convenience: fit and apply in one step.
void fit(const Eigen::MatrixXd &data, const FIFFLIB::FiffInfo &info, const QStringList &eogChannels=QStringList())
Fit regression coefficients from EOG to all other channels.
Full FIFF measurement info: per-channel descriptors, sampling and filter setup, projectors,...
Definition fiff_info.h:88
QList< FiffChInfo > chs