Skip to content

Artifact / Bad Channel Detectors — MEG, EEG, sEEG

A family of three signal plugins that review the channels of the current montage for suspicious channels/contacts and localized transient artifacts — one plugin per modality:

  • MEG Artifact Detector — menu Process → Signal → MEG Artifact Detector 1.0.0
  • EEG Artifact Detector — menu Process → Signal → EEG Artifact Detector 1.0.0
  • SEEG Artifact Detector — menu Process → Signal → SEEG Artifact Detector 1.0.0

All three share the same statistical methodology and parameter names, described on this page. What differs between them — most importantly the definition of "neighbor" — is described on the modality-specific pages linked at the bottom.

A review tool, not an automatic bad-channel marker

Flagged channels are simply colored red in the signal view so the user can inspect them and decide what to do. Nothing is written to the .bad sidecar, and no channel is removed from the montage automatically. Only genuinely localized (transient) events get a proper AwMarker — see criterion 5 below.

The five criteria

Each criterion is evaluated independently over the whole recording. A channel can match more than one; it is only flagged (colored) once.

Robust z-score, used throughout

Rather than a classic mean/standard-deviation z-score — sensitive to the very outliers it's meant to detect — every criterion below scores channels with a robust z-score based on the median and the Median Absolute Deviation (MAD):

MAD  = median( |x_i - median(x)| )
z_i  = 0.6745 * (x_i - median(x)) / MAD

The 0.6745 constant makes z comparable to a standard normal z-score for Gaussian data. This matters more as the number of bad channels/contacts grows relative to the population: with a plain mean/std, a couple of genuinely bad channels inflate the standard deviation enough to hide themselves (and smaller defects) from the rest of the population.

Criterion 1 — Flat channel (persistent, whole recording)

The recording is split into fixed-length windows (window_length_s, default 5 s). For each channel, the RMS amplitude is averaged across all windows, log-transformed (RMS is a positive, right-skewed quantity, and the log keeps the robust z-score from understating an unusually low value), then scored against the rest of the channel population. Only an abnormally low level counts (one-sided) — a flat, disconnected, or high-impedance channel, not simply a louder one.

Criterion 2 — Poor correlation with neighbors (persistent)

For each window, the channel's signal is correlated (Pearson) against the average signal of its neighbors (what counts as a "neighbor" is modality-specific, see below). The per-window correlations are averaged over the recording, then Fisher-transformed (atanh) before the robust z-score: real correlation coefficients bunch up close to 1 for healthy channels, so scoring the raw r values directly would understate how unusual a low outlier really is. Only an abnormally low correlation counts.

Criterion 3 — Broadband power vs. neighbors, "most" aggregation (persistent)

A Welch-style power spectral density (PSD, see below) is computed per channel and averaged, in dB, over a broadband frequency range (modality-specific). For every (channel, neighbor) pair, the dB difference is computed; all pairwise differences, across every channel, are pooled into one robust z-score. A channel is flagged only if a strict majority of its own neighbor pairs exceed psd_pair_zscore_threshold — the same "most" aggregation strategy as FieldTrip's ft_badchannel (cfg.nbdetect = 'most'). Comparing against a single aggregate neighbor value (e.g. the neighbors' median) would let one unusually noisy or badly-positioned neighbor single-handedly swing the verdict; requiring most individual neighbors to agree is more robust to that.

Criterion 4 — Narrow spectral peak above the channel's own baseline (persistent)

Purely intra-channel, no neighbor comparison: the channel's own PSD (dB) is median-filtered across frequency, inside a modality-specific search range, to estimate its local baseline shape, and the largest residual above that baseline is kept. These values are scored across channels with the robust z-score, one-sided high. This catches line-like interference (e.g. powerline hum and its harmonics) that the other criteria miss entirely: it doesn't make the channel flat, doesn't reduce its correlation with neighbors, and doesn't necessarily raise its broadband power enough to stand out, since the extra energy sits in a few narrow frequency bins.

Criterion 5 — Transient amplitude outliers (the only criterion producing markers)

For each window (independently), the robust z-score of RMS is computed across channels. A window/channel pair is "flagged" if |z| > zscore_threshold. Per channel:

  • if the fraction of flagged windows is ≥ global_bad_ratio (default 0.8): treated as a persistent trait of the whole recording — colored red like criteria 1-4, no marker.
  • otherwise: the flagged windows are a localized event (e.g. a brief movement or electrode-pop artifact) — one AwMarker labeled "artifact" is created per contiguous run of flagged windows, its value set to that run's largest |z|.

Markers are global, not channel-specific

The "artifact" markers created by criterion 5 are global: they carry no target channels. In AnyWave, a marker with an empty target-channel list applies to the whole recording at that time range, not to one channel. This is deliberate: it lets any downstream process that excludes marked time ranges — most importantly ICA, via its skip-marker list (the skip list in the ICA settings dialog, or --skip_markers on the command line) — exclude that time range for every channel, not just the one that originally tripped the threshold. A transient artifact localized to one channel (movement, muscle burst, electrode pop) plausibly contaminates neighboring channels too at that same instant — exactly the kind of data ICA should not be trained on.

Running one of these detectors only creates the markers; getting ICA (or any other marker-aware process) to actually skip the "artifact" label still requires adding it to that run's skip list — this doesn't happen automatically.

Spectral estimation (Welch PSD)

Criteria 3 and 4 share the same PSD estimate. Each analysis window is itself split into overlapping (50%) sub-segments, Hamming-windowed and detrended, then FFT'd and accumulated — a genuine Welch estimate, not a single FFT per window (a single long FFT is much noisier for this purpose). The sub-segment length is derived per file from its own sampling rate and rounded to the nearest power of two. This avoids two independent pitfalls: a segment length with large prime factors can make the FFT dramatically slower, and a segment length that doesn't fit inside the analysis window at all would silently produce zero data for these two criteria on a lower-sampling-rate file.

Common parameters

Parameter Default Meaning
window_length_s 5.0 Length (s) of the fixed analysis window used by criteria 1/2/5.
zscore_threshold 5.0 Robust z-score threshold for criteria 1/2/5.
global_bad_ratio 0.8 Fraction of flagged windows (criterion 5) above which a channel is treated as persistently bad rather than localized.
neighbor_count 5 (MEG/EEG), 2 (sEEG) Number of neighbors used by criteria 2/3 — see the modality pages for what "neighbor" means.
psd_pair_zscore_threshold 3.0 Robust z-score threshold for criterion 3's pairwise neighbor comparison.
psd_peak_zscore_threshold 3.0 Robust z-score threshold for criterion 4's own-baseline peak.

EEG and sEEG additionally expose the PSD frequency bands as parameters; MEG uses fixed, validated values instead — see the modality pages.

Modality-specific behaviour

Validation status

Plugin Status
MEG Artifact Detector Validated against a real recording with a known set of bad channels.
EEG Artifact Detector Functional, but its PSD frequency bands and z-score thresholds have not yet been checked against a real EEG recording with known bad channels — treat the defaults as a reasoned starting point.
sEEG Artifact Detector Functional, but has not yet been run against a real sEEG recording with known bad contacts — treat every default, including the same-shaft neighbor logic itself, as unverified.