{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n\n# Removing muscle ICA components\n\nGross movements produce widespread high-frequency activity across all channels\nthat is usually not recoverable and so the epoch must be rejected as shown in\n`ex-muscle-artifacts`. More ubiquitously than gross movements, muscle\nartifact is produced during postural maintenance. This is more appropriately\nremoved by ICA otherwise there wouldn't be any epochs left! Note that muscle\nartifacts of this kind are much more pronounced in EEG than they are in MEG.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Authors: Alex Rockhill \n#\n# License: BSD-3-Clause\n# Copyright the MNE-Python contributors." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import mne\n\ndata_path = mne.datasets.sample.data_path()\nraw_fname = data_path / \"MEG\" / \"sample\" / \"sample_audvis_raw.fif\"\nraw = mne.io.read_raw_fif(raw_fname)\nraw.crop(tmin=100, tmax=130) # take 30 seconds for speed\n\n# pick only EEG channels, muscle artifact is basically not picked up by MEG\n# if you have a simultaneous recording, you may want to do ICA on MEG and EEG\n# separately\nraw.pick(picks=\"eeg\", exclude=\"bads\")\n\n# ICA works best with a highpass filter applied\nraw.load_data()\nraw.filter(l_freq=1.0, h_freq=None)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Run ICA\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "ica = mne.preprocessing.ICA(\n n_components=15, method=\"picard\", max_iter=\"auto\", random_state=97\n)\nica.fit(raw)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Remove components with postural muscle artifact using ICA\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "ica.plot_sources(raw)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "By inspection, let's select out the muscle-artifact components based on\n:footcite:`DharmapraniEtAl2016` manually.\n\nThe criteria are:\n\n- Positive slope of log-log power spectrum between 7 and 75 Hz\n (here just flat because it's not in log-log)\n- Peripheral focus or dipole/multi-pole foci (the blue and red\n blobs in the topomap are far from the vertex where the most\n muscle is)\n- Single focal point (low spatial smoothness; there is just one focus\n of the topomap compared to components like the first ones that are\n more likely neural which spread across the topomap)\n\nThe other attribute worth noting is that the time course in\n:func:`mne.preprocessing.ICA.plot_sources` looks like EMG; you can\nsee spikes when each motor unit fires so that the time course looks fuzzy\nand sometimes has large spikes that are often at regular intervals.\n\nICA component 13 is a textbook example of what muscle artifact looks like.\nThe focus of the topomap for this component is right on the temporalis\nmuscle near the ears. There is also a minimum in the power spectrum at around\n10 Hz, then a maximum at around 25 Hz, generally resulting in a positive\nslope in log-log units; this is a very typical pattern for muscle artifact.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "muscle_idx = [6, 7, 8, 9, 10, 11, 12, 13, 14]\nica.plot_properties(raw, picks=muscle_idx, log_scale=True)\n\n# first, remove blinks and heartbeat to compare\nblink_idx = [0]\nheartbeat_idx = [5]\nica.apply(raw, exclude=blink_idx + heartbeat_idx)\nica.plot_overlay(raw, exclude=muscle_idx)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, let's try an automated algorithm to find muscle components\nand ensure that it gets the same components we did manually.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "muscle_idx_auto, scores = ica.find_bads_muscle(raw)\nica.plot_scores(scores, exclude=muscle_idx_auto)\nprint(\n f\"Manually found muscle artifact ICA components: {muscle_idx}\\n\"\n f\"Automatically found muscle artifact ICA components: {muscle_idx_auto}\"\n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Let's now replicate this on the EEGBCI dataset\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "for sub in (1, 2):\n raw = mne.io.read_raw_edf(\n mne.datasets.eegbci.load_data(subjects=sub, runs=(1,))[0], preload=True\n )\n mne.datasets.eegbci.standardize(raw) # set channel names\n montage = mne.channels.make_standard_montage(\"standard_1005\")\n raw.set_montage(montage)\n raw.filter(l_freq=1.0, h_freq=None)\n\n # Run ICA\n ica = mne.preprocessing.ICA(\n n_components=15, method=\"picard\", max_iter=\"auto\", random_state=97\n )\n ica.fit(raw)\n ica.plot_sources(raw)\n muscle_idx_auto, scores = ica.find_bads_muscle(raw)\n ica.plot_properties(raw, picks=muscle_idx_auto, log_scale=True)\n ica.plot_scores(scores, exclude=muscle_idx_auto)\n\n print(\n f\"Manually found muscle artifact ICA components: {muscle_idx}\\n\"\n \"Automatically found muscle artifact ICA components: \"\n f\"{muscle_idx_auto}\"\n )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## References\n.. footbibliography::\n\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.2" } }, "nbformat": 4, "nbformat_minor": 0 }