# Muscle artifact detection (annotate\_muscle\_zscore) placement in vMMR preprocessing pipeline

**URL:** <https://mne.discourse.group/t/muscle-artifact-detection-annotate-muscle-zscore-placement-in-vmmr-preprocessing-pipeline/11721>\
**Category:** Support & Discussions\
**Tags:** preprocessing, evoked, epochs\
**Created:** [March 2, 2026, 4:58pm UTC](https://mne.discourse.group/t/muscle-artifact-detection-annotate-muscle-zscore-placement-in-vmmr-preprocessing-pipeline/11721 "2026-03-02T16:58:12Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![omertzuk](https://yyz2.discourse-cdn.com/free1/user_avatar/mne.discourse.group/omertzuk/32/4557_2.png) [@omertzuk](https://mne.discourse.group/u/omertzuk)\
**Post date:** [March 2, 2026, 4:58pm UTC](https://mne.discourse.group/t/muscle-artifact-detection-annotate-muscle-zscore-placement-in-vmmr-preprocessing-pipeline/11721/1 "2026-03-02T16:58:12Z")

</div>

Hello everyone, I’m working on preprocessing an EEG dataset for a visual mismatch response (vMMR) ERP experiment. I have a specific question: where should `mne.preprocessing.annotate_muscle_zscore()` be placed in my epoching and preprocessing pipeline - before ICA, after ICA, or should I skip it entirely?

## Current Pipeline

1. Load raw data + montage + average-reference projector

2. Filter (HP 0.1 Hz only, no LP filter) + downsample to 512 Hz + event alignment

3. Parse trials (standard and deviant separately)

4. RANSAC global bad channel detection

5. Epoching with broadband data (`baseline=None`)

6. AutoReject-1 on broadband epochs

7. ICA fit + ICLabel classification

8. Apply ICA + AutoReject-2 on broadband epochs + LP 30 Hz filter

I’m using 64-channel BioSemi data.

**Minimal reproducible example:**

```python
raw.filter(0.1, None, l_trans_bandwidth=0.08)
raw.resample(512)

Where to add annotate_muscle_zscore()?

raw = mne.preprocessing.annotate_muscle_zscore(raw, threshold=2.)

epochs = mne.Epochs(raw, events, event_ids, tmin=-0.2, tmax=1.5,
baseline=None, preload=True,
reject_by_annotation=False)

ar1 = autoreject.AutoReject(n_interpolate=[1, 4, 32], random_state=42)
epochs, reject_log1 = ar1.fit_transform(epochs, return_log=True)

ica = mne.preprocessing.ICA(method=‘infomax’, n_components=0.99, random_state=99)
ica.fit(epochs)

ic_labels = label_components(epochs, ica, method=“iclabel”)
exclude_idx = [idx for idx, label in enumerate(ic_labels[“labels”])
if label not in [“brain”, “other”]]
ica.apply(epochs, exclude=exclude_idx)

Or here instead?

epochs = mne.preprocessing.annotate_muscle_zscore(epochs, threshold=2.)

epochs.apply_baseline((None, 0))
epochs.filter(None, 30)

ar2 = autoreject.AutoReject(n_interpolate=[1, 4, 32], random_state=42)
epochs_clean, reject_log2 = ar2.fit_transform(epochs, return_log=True)

```

---

<div class="post-metadata">

**Author:** ![wmvanvliet](https://yyz2.discourse-cdn.com/free1/user_avatar/mne.discourse.group/wmvanvliet/32/100_2.png) [@wmvanvliet](https://mne.discourse.group/u/wmvanvliet)\
**Post date:** [March 4, 2026, 11:32am UTC](https://mne.discourse.group/t/muscle-artifact-detection-annotate-muscle-zscore-placement-in-vmmr-preprocessing-pipeline/11721/2 "2026-03-04T11:32:30Z")

</div>

If your evokeds look clean enough for the purposes of your study, there is no need to include `annotate_muscle_zscore` at all. If the subject was moving during epochs, I think I would perform this step on the `raw` data, so even before epoching. When creating epochs, any stretches of data annotated with a label that starts with `BAD_` will be ignored by default (the function annotates muscle movements with `BAD_muscle`).

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/free1/uploads/mne/original/1X/85cc6bd2b69cb698a166dc6d880fb550510d0144.jpeg) [@system](https://mne.discourse.group/u/system)\
**Post date:** [March 11, 2026, 11:32am UTC](https://mne.discourse.group/t/muscle-artifact-detection-annotate-muscle-zscore-placement-in-vmmr-preprocessing-pipeline/11721/3 "2026-03-11T11:32:58Z")

</div>

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.
