64double BadChannelDetect::pearsonCorr(
const RowVectorXd& a,
const RowVectorXd& b)
66 if (a.size() != b.size() || a.size() == 0)
return 0.0;
68 RowVectorXd ac = a.array() - a.mean();
69 RowVectorXd bc = b.array() - b.mean();
71 double normA = ac.norm();
72 double normB = bc.norm();
73 if (normA < 1e-30 || normB < 1e-30)
return 0.0;
75 return ac.dot(bc) / (normA * normB);
80double BadChannelDetect::median(QVector<double> values)
82 if (values.isEmpty())
return 0.0;
83 std::sort(values.begin(), values.end());
84 const int n = values.size();
85 if (n % 2 == 1)
return values[n / 2];
86 return 0.5 * (values[n / 2 - 1] + values[n / 2]);
101 QVector<bool> flagged(
static_cast<int>(matData.rows()),
false);
102 for (
int i : flat)
if (i >= 0 && i < matData.rows()) flagged[i] =
true;
103 for (
int i : noisy)
if (i >= 0 && i < matData.rows()) flagged[i] =
true;
104 for (
int i : low)
if (i >= 0 && i < matData.rows()) flagged[i] =
true;
107 for (
int i = 0; i < static_cast<int>(matData.rows()); ++i) {
108 if (flagged[i]) result.append(i);
119 for (
int ch = 0; ch < matData.rows(); ++ch) {
120 const RowVectorXd row = matData.row(ch);
121 double ptp = row.maxCoeff() - row.minCoeff();
122 if (ptp < dThreshold) bad.append(ch);
132 const int nCh =
static_cast<int>(matData.rows());
133 if (nCh < 3)
return {};
136 QVector<double> stds(nCh);
137 for (
int ch = 0; ch < nCh; ++ch) {
138 const RowVectorXd row = matData.row(ch);
139 double mean = row.mean();
140 double var = (row.array() - mean).square().mean();
141 stds[ch] = std::sqrt(var);
145 double med = median(stds);
147 QVector<double> absDevs(nCh);
148 for (
int ch = 0; ch < nCh; ++ch)
149 absDevs[ch] = std::abs(stds[ch] - med);
150 double mad = median(absDevs);
153 double sigma = 1.4826 * mad;
158 double meanStd = 0.0;
159 for (
double value : stds) {
162 meanStd /=
static_cast<double>(nCh);
165 for (
double value : stds) {
166 const double diff = value - meanStd;
167 varStd += diff * diff;
169 sigma = std::sqrt(varStd /
static_cast<double>(nCh));
172 if (sigma < 1e-30)
return {};
175 for (
int ch = 0; ch < nCh; ++ch) {
176 double z = (stds[ch] - med) / sigma;
177 if (z > dZThresh) bad.append(ch);
188 const int nCh =
static_cast<int>(matData.rows());
189 if (nCh < 2)
return {};
193 for (
int ch = 0; ch < nCh; ++ch) {
197 int lo = std::max(0, ch - iNeighbours);
198 int hi = std::min(nCh - 1, ch + iNeighbours);
200 for (
int nb = lo; nb <= hi; ++nb) {
201 if (nb == ch)
continue;
202 double c = std::abs(pearsonCorr(matData.row(ch), matData.row(nb)));
207 if (nValid == 0)
continue;
209 double meanCorr = sumC /
static_cast<double>(nValid);
210 if (meanCorr < dCorrThresh) bad.append(ch);
Declaration of BadChannelDetect — automated detection of bad MEG/EEG channels.
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
BadChannelDetectParams Params
static QVector< int > detect(const Eigen::MatrixXd &matData, const Params ¶ms=Params())
static QVector< int > detectHighVariance(const Eigen::MatrixXd &matData, double dZThresh=4.0)
static QVector< int > detectLowCorrelation(const Eigen::MatrixXd &matData, double dCorrThresh=0.4, int iNeighbours=5)
static QVector< int > detectFlat(const Eigen::MatrixXd &matData, double dThreshold=1e-13)