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 const int nTimes = static_cast<int>(data.cols());
76
77 for (int i = 0; i < nEeg; ++i) {
78 for (int j = i + 1; j < nEeg; ++j) {
79 // Standard deviation of the difference signal
80 RowVectorXd diff = data.row(eegIdx[i]) - data.row(eegIdx[j]);
81 double meanDiff = diff.mean();
82 double varDiff = (diff.array() - meanDiff).square().mean();
83 double stdDiff = std::sqrt(varDiff);
84
85 // Normalise by geometric mean of individual std devs
86 double geoMean = std::sqrt(stdDevs(i) * stdDevs(j));
87 double ed = (geoMean > 1e-30) ? stdDiff / geoMean : 0.0;
88
89 edist(i, j) = ed;
90 edist(j, i) = ed;
91 }
92 }
93
94 return edist;
95}
96
97//=============================================================================================================
98
99QList<QPair<int,int>> UTILSLIB::computeBridgedElectrodes(
100 const MatrixXd& data,
101 const FiffInfo& info,
102 const BridgedElectrodeParams& params)
103{
104 // Find EEG channel indices
105 QList<int> eegIdx;
106 for (int i = 0; i < info.chs.size(); ++i) {
107 if (info.chs[i].kind == FIFFV_EEG_CH) {
108 eegIdx.append(i);
109 }
110 }
111
112 const int nEeg = eegIdx.size();
113 QList<QPair<int,int>> bridged;
114
115 if (nEeg < 2) {
116 return bridged;
117 }
118
119 MatrixXd edist = computeElectricalDistance(data, info);
120
121 // Find pairs below threshold
122 for (int i = 0; i < nEeg; ++i) {
123 for (int j = i + 1; j < nEeg; ++j) {
124 if (edist(i, j) < params.dElectricalDistanceThreshold) {
125 bridged.append(qMakePair(eegIdx[i], eegIdx[j]));
126 }
127 }
128 }
129
130 return bridged;
131}
Symbolic FIFF tag, block, value, unit and channel-type constants shared across FIFFLIB.
#define FIFFV_EEG_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...
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:88
QList< FiffChInfo > chs