v2.0.0
Loading...
Searching...
No Matches
bridged_electrodes.cpp
Go to the documentation of this file.
1//=============================================================================================================
12
13//=============================================================================================================
14// INCLUDES
15//=============================================================================================================
16
17#include "bridged_electrodes.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// STL INCLUDES
31//=============================================================================================================
32
33#include <cmath>
34
35//=============================================================================================================
36// USED NAMESPACES
37//=============================================================================================================
38
39using namespace UTILSLIB;
40using namespace FIFFLIB;
41using namespace Eigen;
42
43//=============================================================================================================
44// DEFINE FUNCTIONS
45//=============================================================================================================
46
47MatrixXd UTILSLIB::computeElectricalDistance(const MatrixXd& data,
48 const FiffInfo& info)
49{
50 // Find EEG channel indices
51 QList<int> eegIdx;
52 for (int i = 0; i < info.chs.size(); ++i) {
53 if (info.chs[i].kind == FIFFV_EEG_CH) {
54 eegIdx.append(i);
55 }
56 }
57
58 const int nEeg = eegIdx.size();
59 if (nEeg < 2) {
60 qWarning() << "[computeElectricalDistance] Need at least 2 EEG channels, found" << nEeg;
61 return MatrixXd::Zero(nEeg, nEeg);
62 }
63
64 // Compute per-channel standard deviations
65 VectorXd stdDevs(nEeg);
66 for (int i = 0; i < nEeg; ++i) {
67 const RowVectorXd row = data.row(eegIdx[i]);
68 double mean = row.mean();
69 double variance = (row.array() - mean).square().mean();
70 stdDevs(i) = std::sqrt(variance);
71 }
72
73 // Compute electrical distance matrix
74 MatrixXd edist = MatrixXd::Zero(nEeg, nEeg);
75
76 for (int i = 0; i < nEeg; ++i) {
77 for (int j = i + 1; j < nEeg; ++j) {
78 // Standard deviation of the difference signal
79 RowVectorXd diff = data.row(eegIdx[i]) - data.row(eegIdx[j]);
80 double meanDiff = diff.mean();
81 double varDiff = (diff.array() - meanDiff).square().mean();
82 double stdDiff = std::sqrt(varDiff);
83
84 // Normalise by geometric mean of individual std devs
85 double geoMean = std::sqrt(stdDevs(i) * stdDevs(j));
86 double ed = (geoMean > 1e-30) ? stdDiff / geoMean : 0.0;
87
88 edist(i, j) = ed;
89 edist(j, i) = ed;
90 }
91 }
92
93 return edist;
94}
95
96//=============================================================================================================
97
98QList<QPair<int, int>> UTILSLIB::computeBridgedElectrodes(
99 const MatrixXd& data,
100 const FiffInfo& info,
101 const BridgedElectrodeParams& params)
102{
103 // Find EEG channel indices
104 QList<int> eegIdx;
105 for (int i = 0; i < info.chs.size(); ++i) {
106 if (info.chs[i].kind == FIFFV_EEG_CH) {
107 eegIdx.append(i);
108 }
109 }
110
111 const int nEeg = eegIdx.size();
112 QList<QPair<int, int>> bridged;
113
114 if (nEeg < 2) {
115 return bridged;
116 }
117
118 MatrixXd edist = computeElectricalDistance(data, info);
119
120 // Find pairs below threshold
121 for (int i = 0; i < nEeg; ++i) {
122 for (int j = i + 1; j < nEeg; ++j) {
123 if (edist(i, j) < params.dElectricalDistanceThreshold) {
124 bridged.append(qMakePair(eegIdx[i], eegIdx[j]));
125 }
126 }
127 }
128
129 return bridged;
130}
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.
#define FIFFV_EEG_CH
Full FIFF measurement metadata: everything from FIFFB_MEAS / FIFFB_MEAS_INFO needed to interpret a re...
Detection of electrically bridged EEG electrodes via the Electrical Distance metric.
FIFF file I/O, in-memory data structures and high-level readers/writers.
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
DSPSHARED_EXPORT QList< QPair< int, int > > computeBridgedElectrodes(const Eigen::MatrixXd &data, const FIFFLIB::FiffInfo &info, const BridgedElectrodeParams &params=BridgedElectrodeParams())
Detect bridged EEG electrodes.
DSPSHARED_EXPORT Eigen::MatrixXd computeElectricalDistance(const Eigen::MatrixXd &data, const FIFFLIB::FiffInfo &info)
Compute electrical distance matrix between EEG channels.
Full FIFF measurement info: per-channel descriptors, sampling and filter setup, projectors,...
Definition fiff_info.h:90
QList< FiffChInfo > chs