Time-frequency on simulated data (Multitaper vs. Morlet)¶

This examples demonstrates on simulated data the different time-frequency estimation methods. It shows the time-frequency resolution trade-off and the problem of estimation variance.

#          Denis Engemann <denis.engemann@gmail.com>
#

import numpy as np

from mne import create_info, EpochsArray
from mne.time_frequency import tfr_multitaper, tfr_stockwell, tfr_morlet

print(__doc__)

Simulate data

sfreq = 1000.0
ch_names = ['SIM0001', 'SIM0002']
info = create_info(ch_names=ch_names, sfreq=sfreq, ch_types=ch_types)

n_times = int(sfreq)  # 1 second long epochs
n_epochs = 40
seed = 42
rng = np.random.RandomState(seed)
noise = rng.randn(n_epochs, len(ch_names), n_times)

# Add a 50 Hz sinusoidal burst to the noise and ramp it.
t = np.arange(n_times, dtype=np.float) / sfreq
signal = np.sin(np.pi * 2. * 50. * t)  # 50 Hz sinusoid signal
signal[np.logical_or(t < 0.45, t > 0.55)] = 0.  # Hard windowing
on_time = np.logical_and(t >= 0.45, t <= 0.55)
signal[on_time] *= np.hanning(on_time.sum())  # Ramping
data = noise + signal

events = np.empty((n_epochs, 3), dtype=int)
first_event_sample = 100
event_id = dict(sin50hz=1)
for k in range(n_epochs):
events[k, :] = first_event_sample + k * n_times, 0, event_id['sin50hz']

epochs = EpochsArray(data=data, info=info, events=events, event_id=event_id,
reject=reject)

Consider different parameter possibilities for multitaper convolution

freqs = np.arange(5., 100., 3.)

# You can trade time resolution or frequency resolution or both
# in order to get a reduction in variance

# (1) Least smoothing (most variance/background fluctuations).
n_cycles = freqs / 2.
time_bandwidth = 2.0  # Least possible frequency-smoothing (1 taper)
power = tfr_multitaper(epochs, freqs=freqs, n_cycles=n_cycles,
time_bandwidth=time_bandwidth, return_itc=False)
# Plot results. Baseline correct based on first 100 ms.
power.plot(, baseline=(0., 0.1), mode='mean', vmin=-1., vmax=3.,
title='Sim: Least smoothing, most variance')

# (2) Less frequency smoothing, more time smoothing.
n_cycles = freqs  # Increase time-window length to 1 second.
time_bandwidth = 4.0  # Same frequency-smoothing as (1) 3 tapers.
power = tfr_multitaper(epochs, freqs=freqs, n_cycles=n_cycles,
time_bandwidth=time_bandwidth, return_itc=False)
# Plot results. Baseline correct based on first 100 ms.
power.plot(, baseline=(0., 0.1), mode='mean', vmin=-1., vmax=3.,
title='Sim: Less frequency smoothing, more time smoothing')

# (3) Less time smoothing, more frequency smoothing.
n_cycles = freqs / 2.
time_bandwidth = 8.0  # Same time-smoothing as (1), 7 tapers.
power = tfr_multitaper(epochs, freqs=freqs, n_cycles=n_cycles,
time_bandwidth=time_bandwidth, return_itc=False)
# Plot results. Baseline correct based on first 100 ms.
power.plot(, baseline=(0., 0.1), mode='mean', vmin=-1., vmax=3.,
title='Sim: Less time smoothing, more frequency smoothing')

# #############################################################################
# Stockwell (S) transform

# S uses a Gaussian window to balance temporal and spectral resolution
# Importantly, frequency bands are phase-normalized, hence strictly comparable
# with regard to timing, and, the input signal can be recoverd from the
# transform in a lossless way if we disregard numerical errors.

fmin, fmax = freqs[[0, -1]]
for width in (0.7, 3.0):
power = tfr_stockwell(epochs, fmin=fmin, fmax=fmax, width=width)
power.plot(, baseline=(0., 0.1), mode='mean',
title='Sim: Using S transform, width '
'= {:0.1f}'.format(width), show=True)

# #############################################################################
# Finally, compare to morlet wavelet

n_cycles = freqs / 2.
power = tfr_morlet(epochs, freqs=freqs, n_cycles=n_cycles, return_itc=False)
power.plot(, baseline=(0., 0.1), mode='mean', vmin=-1., vmax=3.,
title='Sim: Using Morlet wavelet')

Script output:

Data is 40 trials and 2 channels
Multitaper time-frequency analysis for 32 frequencies
Using 1 tapers
Data is 40 trials and 2 channels
Multitaper time-frequency analysis for 32 frequencies
Using 3 tapers
Data is 40 trials and 2 channels
Multitaper time-frequency analysis for 32 frequencies
Using 7 tapers
The input signal is shorter (1000) than "n_fft" (1024). Applying zero padding.
The input signal is shorter (1000) than "n_fft" (1024). Applying zero padding.

Total running time of the script: (0 minutes 21.373 seconds)