question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Confusion surrounding Epochs.plot_psd() units

See original GitHub issue

Consider the following MWE:

# %%
import numpy as np
import matplotlib.pyplot as plt

import mne
from mne.time_frequency import psd_array_multitaper, psd_multitaper
from mne.datasets import somato

data_path = somato.data_path()
subject = '01'
task = 'somato'
raw_fname = op.join(data_path, 'sub-{}'.format(subject), 'meg',
                    'sub-{}_task-{}_meg.fif'.format(subject, task))

raw = mne.io.read_raw_fif(raw_fname)
events = mne.find_events(raw, stim_channel='STI 014')

picks = mne.pick_types(raw.info, meg='grad', eeg=False, eog=True, stim=False)
event_id, tmin, tmax = 1, -1., 3.
baseline = (None, 0)
epochs = mne.Epochs(raw, events, event_id, tmin, tmax, picks=picks,
                    baseline=baseline, reject=dict(grad=4000e-13, eog=350e-6),
                    preload=True)

epochs.resample(200., npad='auto')  # resample to reduce computation time


# %%
fmin = 1
fmax = 40

epochs.plot_psd(fmin=fmin, fmax=fmax, average=True, dB=True, area_mode=None)

This produces the following PSD plot: plot_psd

Trying to reproduce this figure manually, I ran:

# %%
psds, freqs = psd_array_multitaper(
    epochs.get_data(),
    sfreq=epochs.info['sfreq'],
    fmin=fmin,
    fmax=fmax,
    n_jobs=8
)

psds_scaled = psds * 1e15**2  # T/cm -> fT/cm
psds_scaled_dB = (10 * np.log10(psds_scaled)).mean(axis=0).mean(axis=0)

_, ax = plt.subplots()
ax.plot(freqs, psds_scaled_dB)

This produces: psd_array_scaled

The magnitude of the signal clearly differs from what we saw above.

Adjusting the scaling factor to 1e13, I’m finally able to reproduce the output from epochs.plot_psd:

# %%
psds_scaled = psds * 1e13**2  # T/cm -> 100 fT/cm (?!)
psds_scaled_dB = (10 * np.log10(psds_scaled)).mean(axis=0).mean(axis=0)

_, ax = plt.subplots()
ax.plot(freqs, psds_scaled_dB)

psd_array_scaled_2

Where’s my mistake?

cc @cbrnr @agramfort

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:10 (10 by maintainers)

github_iconTop GitHub Comments

1reaction
guiomarcommented, Oct 21, 2021

Ok. I think I finally understood. I’ll explain here in case it can be helpful for others (not sure I’m correct so please go ahead if I say something wrong). I’m new to the tool so I appreciate your patience:

  • There’s your raw data. With info about the channels with: raw.ch_names (or equivalents)
  • There’s your epoched data. With info about the channels with: epochs.ch_names (or equivalents)
  • However, there’s no channel information on the outputs of the psd functions, so one can assume it is the same as the raw or epochs passed as inputs. But this is not always true.

CASE 1: if you have specified the picks parameter inside the psd functions

  • In this case an equivalent selection have to be done in the raw/epochs.ch_names list.
  • Since this selection may not be straight forward having just the list of names, something useful could be to create a copy of the epoch just containing the channels you want, e.g. epochs_grad = epochs.copy().pick('grad')
  • Then you apply the psd function just to the epochs_grad and can ensure that the channels in epochs_grad.ch_names are the ones matching.
  • An equivalent thing can be done for the raw.

CASE 2: picks parameter is not specified or set to None

  • By default the psd is not necessarily computed in all the channels passed e.g. meg_ref channels are excluded, even when the picks parameter is not specified or set to None, as stated in the documentation. So the channels obtained by raw/epochs.ch_names will may not match the ones obtained with the psd functions.
  • The solution proposed before additionally solves this issue that was making my code crash all the time.

So:

  • Pre-selecting your channels before hand creating a copy with .pick (e.g. epochs_grad = epochs.copy().pick('grad')) may help to solve this issue, given that the psd functions don’t provide channel information on the output.
1reaction
drammockcommented, Oct 19, 2021

The question about channel names was already answered here: https://mne.discourse.group/t/channel-information-in-psd-functions/3222/3?u=drammock

For keeping track of channel names, one approach is to store raw.ch_names (or epochs.ch_names or evoked.ch_names) in a list, then use mne.pick_info to get your pick indices. You can then use the pick indices for both the PSD function and for indexing the channel name list.

Read more comments on GitHub >

github_iconTop Results From Across the Web

mne.Epochs — MNE 1.2.2 documentation - MNE-Python
Iterate over epochs as a sequence of Evoked objects. load_data (). Load the data if not already preloaded. next ...
Read more >
psd_multitaper output conversion to dB (Welch) - MNE Forum
The plot_psd (from Welch) results in +30 dB for low frequencies, ... See also : Confusion surrounding Epochs.plot_psd() units · Issue #9868 ...
Read more >
psd: Adaptive, Sine-Multitaper Power Spectral Density and ...
This program restricts the rate of growth of the number of tapers so that a neighboring covering interval estimate is never completely contained...
Read more >
Tutorials/AllIntroduction - Brainstorm
This dataset (MEG and MRI data) was collected by the MEG Unit Lab, ... Import MEG/EEG: Extract segments of recordings (epochs) from an...
Read more >
Package 'psd' - Microsoft R Application Network
given by R-S must be modified since it gives an unbounded result near points ... plot(PSD <- psdcore(mts.p, ntaper=ntap), log=ylog, lwd=2, ylim=c(-5,35)).
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found