Skip to main content

Segment Rejection Artifact Detection Peer Review

This peer-review walk-through inspects the three artifact cleaning steps that run in our baseline EEG tasks: annotate_noisy_epochs, annotate_uncorrelated_epochs, and detect_dense_oscillatory_artifacts. The goal is to document how each routine behaves, highlight correctness and maintainability findings, and capture practical guidance for operators who must justify these detections to stakeholders.【F:src/autoclean/mixins/signal_processing/segment_rejection.py†L20-L204】【F:src/autoclean/functions/segment_rejection/dense_oscillatory.py†L13-L200】

Segment Rejection Overview

The segment rejection mixin executes three denoising routines in sequence to protect downstream feature extraction and QC dashboards. Together they:
  • Epoch continuous raw EEG into fixed windows shared by all detectors
  • Annotate noisy amplitude dispersion, spatially incoherent segments, and dense oscillatory bursts
  • Persist artifact metadata so reviewers can reconcile automatic flags with technician notes

Baseline flow

Epoch Denoising Bundle

The following sections drill into the three routines that share the epoching scaffold. Treat them as a bundle: tuning one detector’s window or pick set usually means re-validating the others on the same segmentation.
Verify that recording spans cover the chosen epoch durations and that montages load correctly before scheduling batch jobs. When prerequisites fail, the mixin aborts early and silently returns a copy of the input raw object.【F:src/autoclean/mixins/signal_processing/segment_rejection.py†L98-L155】【F:src/autoclean/mixins/signal_processing/segment_rejection.py†L284-L347】

Step-by-step reasoning

1
1. annotate_noisy_epochs: amplitude dispersion sweep
2
  • Mechanics – The routine epochs the raw stream, converts the result into an xarray tensor, and measures per-channel standard deviations per epoch. Epochs are flagged when more than quantile_flag_crit of picked channels exceed an interquartile-range (IQR) outlier fence scaled by quantile_k.【F:src/autoclean/mixins/signal_processing/segment_rejection.py†L98-L155】
  • Annotation write-back – Flagged epochs become BAD_noisy_epoch annotations with durations equal to the epoch window. Onsets subtract raw.first_samp/sfreq, matching MNE’s expectation when the original recording started before the current buffer.【F:src/autoclean/mixins/signal_processing/segment_rejection.py†L160-L203】
  • Code review callouts
    • Strength: relies on channel-wise statistics so low-SNR channels cannot dominate the metric.【F:src/autoclean/mixins/signal_processing/segment_rejection.py†L139-L155】
    • ⚠️ Concern: the IQR fence only checks high variance (init_dir="pos"). Extremely flat-lined channels will not be caught even though they are undesirable for evoked analyses. Consider adding init_dir="both" or a secondary detector for low variance epochs.
    • ⚠️ Concern: The onset correction assumes raw.annotations.orig_time is valid. Import pipelines that drop measurement metadata may produce misaligned annotations. Documented in Notes but not enforced; we could warn when orig_time is None.
  • 3
    2. annotate_uncorrelated_epochs: spatial coherence monitor
    4
  • Mechanics – After epoching, the mixin computes pairwise Euclidean distances from the montage and gathers the n_nearest_neighbors per channel. It aggregates neighbor correlations per epoch (max/mean/trimmed-mean) and flags epochs where too many channels fall below the IQR-based low-correlation fence (init_dir="neg").【F:src/autoclean/mixins/signal_processing/segment_rejection.py†L301-L343】【F:src/autoclean/mixins/signal_processing/segment_rejection.py†L493-L518】
  • Annotation write-back – Onsets correct for first_samp offsets before saving BAD_uncorrelated_epoch spans, followed by metadata updates for downstream reporting.【F:src/autoclean/mixins/signal_processing/segment_rejection.py†L349-L384】
  • Code review callouts
    • Strength: explicit montage check prevents correlation math without spatial context, failing fast with a clear error message.【F:src/autoclean/mixins/signal_processing/segment_rejection.py†L319-L323】
    • ⚠️ Concern: _chan_neighbour_r recomputes the full distance matrix every call. For high-density nets, caching channel geometry could reduce quadratic costs.
    • ⚠️ Concern: The trim-mean branch relies on SciPy’s trim_mean, but upper-bound validation for corr_trim_percent happens in wrapper functions, not here. Future refactors should consolidate parameter checks.
  • 5
    3. detect_dense_oscillatory_artifacts: reference artifact tracer
    6
  • Mechanics – Slides a fixed window (default 100 ms) without overlap, counts channels whose peak-to-peak amplitudes exceed channel_threshold_uv, and annotates padded spans when min_channels channels are involved. Padding protects against fencepost errors around the oscillatory burst.【F:src/autoclean/functions/segment_rejection/dense_oscillatory.py†L141-L198】
  • Code review callouts
    • Strength: defensive input validation catches negative durations, thresholds, and ensures an MNE Raw object before any heavy computation.【F:src/autoclean/functions/segment_rejection/dense_oscillatory.py†L123-L139】
    • ⚠️ Concern: The stride equals the window size (range(0, n_samples - window_size, window_size)), so artifacts shorter than the window or straddling boundaries may be missed. Consider an overlap factor or half-window hop.
    • ⚠️ Concern: Multiple consecutive windows append overlapping annotations rather than merging. Downstream duration reports may double-count unless annotations are consolidated.
    • ⚠️ Concern: Default min_channels=75 exceeds electrode counts for 64-channel systems. Users must override or risk silent failure to flag genuine events.
  • Validation checklist

      Deployment playbooks

      Reviewer concerns & follow-up items

      • Introduce optional overlap in the dense oscillatory detector to avoid blind spots; couple with annotation merging to prevent duplicate spans.【F:src/autoclean/functions/segment_rejection/dense_oscillatory.py†L154-L189】
      • Evaluate adding a low-variance branch to annotate_noisy_epochs so flat-lined electrodes are surfaced for technician review.【F:src/autoclean/mixins/signal_processing/segment_rejection.py†L147-L155】
      • Cache montage-derived neighbor indices to reduce the quadratic cost in repeated calls, especially in sliding-window pipelines.【F:src/autoclean/mixins/signal_processing/segment_rejection.py†L493-L518】
      Despite the improvement opportunities, the implementations correctly guard against empty epoch sets, preserve original annotation timing, and serialize metadata for reporting dashboards, making them production-ready once the noted edge cases are addressed.【F:src/autoclean/mixins/signal_processing/segment_rejection.py†L98-L203】【F:src/autoclean/mixins/signal_processing/segment_rejection.py†L349-L384】【F:src/autoclean/functions/segment_rejection/dense_oscillatory.py†L180-L198】