v2.0.0
Loading...
Searching...
No Matches
bad_channels_maxwell.cpp
Go to the documentation of this file.
1//=============================================================================================================
12
13//=============================================================================================================
14// INCLUDES
15//=============================================================================================================
16
18#include "sss.h"
19
20//=============================================================================================================
21// QT INCLUDES
22//=============================================================================================================
23
24#include <QDebug>
25
26//=============================================================================================================
27// EIGEN INCLUDES
28//=============================================================================================================
29
30#include <Eigen/Dense>
31
32//=============================================================================================================
33// STL INCLUDES
34//=============================================================================================================
35
36#include <cmath>
37#include <algorithm>
38#include <numeric>
39
40//=============================================================================================================
41// USED NAMESPACES
42//=============================================================================================================
43
44using namespace UTILSLIB;
45using namespace FIFFLIB;
46using namespace Eigen;
47
48//=============================================================================================================
49// DEFINE FUNCTIONS
50//=============================================================================================================
51
53 const MatrixXd& matData,
54 const FiffInfo& info,
55 const BadChannelsMaxwellParams& params)
56{
58
59 // Build SSS basis
60 SSSParams sssParams;
61 sssParams.iOrderIn = params.iOrderIn;
62 sssParams.iOrderOut = params.iOrderOut;
63 sssParams.origin = params.origin;
64
65 SSS::Basis basis = SSS::computeBasis(info, sssParams);
66
67 if (basis.megChannelIdx.isEmpty()) {
68 qWarning() << "[findBadChannelsMaxwell] No MEG channels found.";
69 return result;
70 }
71
72 const int nMeg = basis.megChannelIdx.size();
73
74 // Extract MEG data
75 int nTimes = static_cast<int>(matData.cols());
76 MatrixXd megData(nMeg, nTimes);
77 for (int i = 0; i < nMeg; ++i) {
78 megData.row(i) = matData.row(basis.megChannelIdx[i]);
79 }
80
81 // Apply SSS reconstruction
82 MatrixXd reconData = SSS::apply(matData, basis);
83
84 // Extract reconstructed MEG channels
85 MatrixXd megRecon(nMeg, nTimes);
86 for (int i = 0; i < nMeg; ++i) {
87 megRecon.row(i) = reconData.row(basis.megChannelIdx[i]);
88 }
89
90 // Compute per-channel residual (RMS of difference)
91 result.residuals.resize(nMeg);
92 for (int i = 0; i < nMeg; ++i) {
93 VectorXd diff = megData.row(i) - megRecon.row(i);
94 result.residuals(i) = std::sqrt(diff.squaredNorm() / nTimes);
95 }
96
97 // Compute z-scores
98 // Use median/MAD for robustness
99 VectorXd sorted = result.residuals;
100 std::sort(sorted.data(), sorted.data() + sorted.size());
101
102 double median = sorted(nMeg / 2);
103 if (nMeg % 2 == 0 && nMeg > 1) {
104 median = (sorted(nMeg / 2 - 1) + sorted(nMeg / 2)) / 2.0;
105 }
106
107 VectorXd absDev(nMeg);
108 for (int i = 0; i < nMeg; ++i) {
109 absDev(i) = std::abs(result.residuals(i) - median);
110 }
111 std::sort(absDev.data(), absDev.data() + absDev.size());
112
113 double mad = absDev(nMeg / 2);
114 if (nMeg % 2 == 0 && nMeg > 1) {
115 mad = (absDev(nMeg / 2 - 1) + absDev(nMeg / 2)) / 2.0;
116 }
117
118 // Robust scale: MAD * 1.4826 (consistency constant for normal distribution)
119 double scale = mad * 1.4826;
120 if (scale < 1e-30) scale = 1e-30;
121
122 result.zScores.resize(nMeg);
123 for (int i = 0; i < nMeg; ++i) {
124 result.zScores(i) = (result.residuals(i) - median) / scale;
125 }
126
127 // Flag channels exceeding threshold
128 for (int i = 0; i < nMeg; ++i) {
129 if (result.zScores(i) > params.dZThreshold) {
130 int origIdx = basis.megChannelIdx[i];
131 result.badIndices.append(origIdx);
132 if (origIdx < info.ch_names.size()) {
133 result.badChannels.append(info.ch_names[origIdx]);
134 }
135 }
136 }
137
138qInfo("[findBadChannelsMaxwell] Detected %lld bad channel(s) out of %d MEG channels.",
139 static_cast<long long>(result.badChannels.size()), nMeg);
140
141 return result;
142}
Bad channel detection via SSS reconstruction residuals.
Signal-Space Separation (SSS) and temporal SSS (tSSS) for MEG data.
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 BadChannelsMaxwellResult findBadChannelsMaxwell(const Eigen::MatrixXd &matData, const FIFFLIB::FiffInfo &info, const BadChannelsMaxwellParams &params=BadChannelsMaxwellParams())
Detect bad MEG channels using SSS reconstruction residuals.
Parameters for SSS-based bad channel detection.
Result of SSS-based bad channel detection.
Implements Signal Space Separation (SSS) and temporal SSS (tSSS) for MEG data.
Definition sss.h:100
Eigen::Vector3d origin
Definition sss.h:103
static Basis computeBasis(const FIFFLIB::FiffInfo &fiffInfo, const Params &params=Params())
Definition sss.cpp:280
static Eigen::MatrixXd apply(const Eigen::MatrixXd &matData, const Basis &basis)
Definition sss.cpp:403
Precomputed SSS basis and projectors for a given sensor array.
Definition sss.h:119
QVector< int > megChannelIdx
Definition sss.h:124
Full FIFF measurement info: per-channel descriptors, sampling and filter setup, projectors,...
Definition fiff_info.h:88