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// STATIC HELPERS
45//=============================================================================================================
46
47namespace
48{
49
50MatrixXd demeanedRows(const MatrixXd& data, const QVector<int>& rows)
51{
52 MatrixXd out(rows.size(), data.cols());
53 for (int i = 0; i < rows.size(); ++i)
54 out.row(i) = data.row(rows[i]).array() - data.row(rows[i]).mean();
55 return out;
56}
57
58} // namespace
59
60//=============================================================================================================
61// DEFINE MEMBER METHODS
62//=============================================================================================================
63
64void EogRegression::fit(const MatrixXd& data,
65 const FiffInfo& info,
66 const QStringList& eogChannels)
67{
68 m_vecEogIndices.clear();
69 m_vecTargetIndices.clear();
70 m_bFitted = false;
71
72 if (eogChannels.isEmpty()) {
73 for (int i = 0; i < info.chs.size(); ++i) {
74 if (info.chs[i].kind == FIFFV_EOG_CH && !info.bads.contains(info.ch_names[i]))
75 m_vecEogIndices.append(i);
76 }
77 } else {
78 for (const QString& name : eogChannels) {
79 const int idx = static_cast<int>(info.ch_names.indexOf(name));
80 if (idx >= 0)
81 m_vecEogIndices.append(idx);
82 else
83 qWarning() << "[EogRegression::fit] EOG channel not found:" << name;
84 }
85 }
86 if (m_vecEogIndices.isEmpty()) {
87 qWarning() << "[EogRegression::fit] No EOG channels found. Data will not be modified.";
88 return;
89 }
90
91 // mne's default picks: the good data channels
92 for (const int i : info.pick_data_channels(info.bads))
93 m_vecTargetIndices.append(i);
94
95 // Least squares on the time-demeaned signals, as mne.preprocessing.EOGRegression
96 const MatrixXd E = demeanedRows(data, m_vecEogIndices);
97 const MatrixXd T = demeanedRows(data, m_vecTargetIndices);
98 m_matBeta = (E * E.transpose()).ldlt().solve(E * T.transpose()).transpose();
99 m_bFitted = true;
100}
101
102//=============================================================================================================
103
104void EogRegression::apply(MatrixXd& data,
105 const FiffInfo& info) const
106{
107 Q_UNUSED(info)
108
109 if (!m_bFitted) {
110 qWarning() << "[EogRegression::apply] Not fitted yet. Call fit() first.";
111 return;
112 }
113 const MatrixXd E = demeanedRows(data, m_vecEogIndices);
114 for (int i = 0; i < m_vecTargetIndices.size(); ++i)
115 data.row(m_vecTargetIndices[i]) -= m_matBeta.row(i) * E;
116}
117
118//=============================================================================================================
119
120void EogRegression::fitApply(MatrixXd& data,
121 const FiffInfo& info,
122 const QStringList& eogChannels)
123{
124 EogRegression reg;
125 reg.fit(data, info, eogChannels);
126 reg.apply(data, info);
127}
FIFF channel descriptor record (FIFF_CH_INFO): per-channel logical/scanner numbers,...
Symbolic FIFF tag, block, value, unit and channel-type constants shared across FIFFLIB.
constexpr auto FIFFV_EOG_CH
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:90
QList< FiffChInfo > chs
Eigen::RowVectorXi pick_data_channels(const QStringList &exclude=defaultQStringList) const