Simulations

This notebook introduces the simulations used in this project.

%matplotlib inline

import numpy as np
import matplotlib.pyplot as plt

from fooof.sim import gen_power_spectrum

from neurodsp.sim import sim_powerlaw, sim_oscillation, sim_synaptic_current, sim_combined
from neurodsp.utils import create_times, set_random_seed
from neurodsp.spectral import compute_spectrum, rotate_powerlaw
from neurodsp.plts import plot_time_series, plot_power_spectra
# Import custom code
import sys; from pathlib import Path
sys.path.append(str(Path('..').resolve()))
from apm.core.db import APMDB
from apm.plts.data import plot_timeseries_and_psd
from apm.plts.psd import custom_psd_style
# Set plot style
import seaborn as sns
sns.set_context('talk')

Settings

First, we will define some settings for the simulations.

# Set random seed
set_random_seed(111)
# General simulation Settings
n_seconds = 10
fs = 500

# Component parameters
default_exp = -1.0
default_freq = 10
f_range = (1, None)
# Collect together parameters for combined signals
comps_osc = {'sim_powerlaw' : {'exponent' : default_exp},
             'sim_oscillation' : {'freq' : default_freq}}
comps_burst = {'sim_powerlaw' : {'exponent' : default_exp},
               'sim_bursty_oscillation' : {'freq' : default_freq}}
# Create a times vector for time series
times = create_times(n_seconds, fs)
# Plot settings
labels = {'xlabel' : '', 'ylabel' : ''}
tskwargs = {**labels, 'xlim' : [0, times[-1]]}
# Settings for saving figures
SAVE_FIG = True
EXT = '.pdf'
FP = APMDB().figs_path + '/sims/'

Time Series Simulations

Time series are simulated using NeuroDSP.

Powerlaw Signal

First, we can simulate a ‘powerlaw’ signal, a 1/f signal that follow a powerlaw in the frequency domain.

# Simulate a powerlaw signal
sig_pow = sim_powerlaw(n_seconds, fs, default_exp, f_range=f_range)
plot_timeseries_and_psd(times, sig_pow, fs)
../_images/02-Simulations_14_0.png

Continuous Oscillation

Next, we can simulate an oscillation, in this case, a continuous sinusoid.

# Simulate an oscillation
sig_osc = sim_oscillation(n_seconds, fs, freq=default_freq)
plot_timeseries_and_psd(times, sig_osc, fs)
../_images/02-Simulations_17_0.png

Combined Signal

Now we can can combine the aperiodic and periodic components from above, and create a combined signal.

# Simulate a combined signal, with an aperiodic and a periodic component
sig_comb = sim_combined(n_seconds, fs, comps_osc)
plot_timeseries_and_psd(times, sig_comb, fs)
../_images/02-Simulations_20_0.png

Synpatic Signal: Aperiodic Activity with a Knee

There are different possible ways to simulate aperiodic activity.

In this next simulation, we will simulate a ‘synpatic current’ model, which creates aperiodic activity with a knee.

# Simulate aperiodic activity from a synaptic current model
sig_kn = sim_synaptic_current(n_seconds, fs)
plot_timeseries_and_psd(times, sig_kn, fs)
../_images/02-Simulations_23_0.png

Bursty Oscillation

Oscillations are also not necessarily continuous. We we will simulate a combined signal with a bursty oscillation.

# Simulate a combined signal with a bursty oscillation
sig_burst = sim_combined(n_seconds, fs, comps_burst)
plot_timeseries_and_psd(times, sig_burst, fs)
../_images/02-Simulations_26_0.png

Example Time Series

In the notebooks that follow, you will see that measures are applied to a set of ‘example’ time series.

These examples are time series that have been pre-computed, using the functions above.

This set of example signals is shown here.

# Import the pre-computed example signals
from apm.sim.examples import TIMES, SIG_AP, SIG_KN, SIG_OSC, SIG_COMB, SIG_BURST
_, axes = plt.subplots(5, 1, figsize=(12, 10))
plt_kwargs = {'xlabel' : '', 'ylabel' : '', 'xlim' : [5, 10]}
plot_time_series(TIMES, SIG_AP, title='Powerlaw Signal', **plt_kwargs, ax=axes[0])
plot_time_series(TIMES, SIG_OSC, title='Oscillatory Signal', **plt_kwargs, ax=axes[1])
plot_time_series(TIMES, SIG_COMB, title='Combined Signal', **plt_kwargs, ax=axes[2])
plot_time_series(TIMES, SIG_KN, title='Knee Signal', **plt_kwargs, ax=axes[3])
plot_time_series(TIMES, SIG_BURST, title='Bursty Signal', **plt_kwargs, ax=axes[4])
../_images/02-Simulations_29_0.png

Power Spectrum Simulations

Power spectra are simulated using SpecParam.

Single Peak & Fixed Mode

First, we can simulate a power spectrum with a single peak with a 1/f aperiodic component.

freqs, powers = gen_power_spectrum([3, 40], [1, 1], [10, 0.3, 1], nlv=0.025)
plot_power_spectra(freqs, powers, lw=5, ylabel='Power', custom_styler=custom_psd_style,
                   save_fig=SAVE_FIG, file_name='psd_fixed' + EXT, file_path=FP)
../_images/02-Simulations_33_0.png

Multi-Peak & Knee Mode

Next, we can simulate a pwoer spectrum that has multiple peaks, and an aperiodic component with a knee.

freqs, powers = gen_power_spectrum([1, 75], [0, 400, 1], [[5, 0.025, 1], [30, 0.02, 4]], nlv=0.001)
plot_power_spectra(freqs, powers, lw=5, custom_styler=custom_psd_style,
                   save_fig=SAVE_FIG, file_name='psd_knee' + EXT, file_path=FP)
../_images/02-Simulations_36_0.png

Simulating Power Law Signals through Spectral Rotation

The aperiodic components of the above time series simulations are created by spectrally rotating white noise.

This section demonstrates how those simulations work.

# Simulate a white noise signal
sig = sim_powerlaw(n_seconds, fs, exponent=0)
plot_time_series(times, sig, **tskwargs, 
                 save_fig=SAVE_FIG, file_name='rot_ts_pre' + EXT, file_path=FP)
../_images/02-Simulations_39_0.png
# Compute the power spectrum of the signal
freqs, pows = compute_spectrum(sig, fs, nperseg=250, noverlap=100)
# Plot the power spectrum of the white noise signal
plot_power_spectra(freqs, pows, **labels, ylim=[0.0001, 0.1], 
                   save_fig=SAVE_FIG, file_name='rot_psd_pre' + EXT, file_path=FP)
../_images/02-Simulations_41_0.png
# Rotate the spectrum to desired aperiodic exponent
pows_rot = rotate_powerlaw(freqs, pows, 1, f_rotation=100)
# Plot the power spectrum of the rotated signal
plot_power_spectra(freqs, pows_rot, **labels, ylim=[0.0001, 0.1], 
                   save_fig=SAVE_FIG, file_name='rot_psd_post' + EXT, file_path=FP)
../_images/02-Simulations_43_0.png
# Get the rotated signal, back in the time domain
#   Note: this step directly uses the NDSP function, which rotates a new signal behind the scenes
sig = sim_powerlaw(n_seconds, fs, exponent=-1)
# Plot the time series of the rotated signal, with the desired aperiodic exponent
plot_time_series(times, sig, **tskwargs, 
                 save_fig=SAVE_FIG, file_name='rot_ts_post' + EXT, file_path=FP)
../_images/02-Simulations_45_0.png