Source code for mne_nirs.simulation._simulation
# Authors: Robert Luke <mail@robertluke.net>
#
# License: BSD (3-clause)
import numpy as np
from mne import Annotations, create_info
from mne.io import RawArray
[docs]
def simulate_nirs_raw(sfreq=3.,
amplitude=1.,
annot_desc='A',
sig_dur=300.,
stim_dur=5.,
isi_min=15.,
isi_max=45.,
ch_name='Simulated',
hrf_model='glover'):
"""
Create simulated fNIRS data.
The returned data is of type `hbo`.
One or more conditions can be simulated.
To simulate multiple conditions pass in a description and amplitude
for each
`amplitude=[0., 2., 4.], annot_desc=['Control', 'Cond_A', 'Cond_B']`.
Parameters
----------
sfreq : Number
The sample rate.
amplitude : Number, Array of numbers
The amplitude of the signal to simulate in uM.
Pass in an array to simulate multiple conditions.
annot_desc : str, Array of str
The name of the annotations for simulated amplitudes.
Pass in an array to simulate multiple conditions,
must be the same length as amplitude.
sig_dur : Number
The length of the boxcar signal to generate in seconds that will
be convolved with the HRF.
stim_dur : Number, Array of numbers
The length of the stimulus to generate in seconds.
isi_min : Number
The minimum duration of the inter stimulus interval in seconds.
isi_max : Number
The maximum duration of the inter stimulus interval in seconds.
ch_name : str
Channel name to be used in returned raw instance.
hrf_model : str
Specifies the hemodynamic response function. See nilearn docs.
Returns
-------
raw : instance of Raw
The generated raw instance.
"""
from nilearn.glm.first_level import make_first_level_design_matrix
from pandas import DataFrame
if type(amplitude) is not list:
amplitude = [amplitude]
if type(annot_desc) is not list:
annot_desc = [annot_desc]
if type(stim_dur) is not list:
stim_dur = [stim_dur]
frame_times = np.arange(sig_dur * sfreq) / sfreq
assert len(amplitude) == len(annot_desc), "Same number of amplitudes as " \
"annotations required."
assert len(amplitude) == len(stim_dur), "Same number of amplitudes as " \
"durations required."
onset = 0.
onsets = []
conditions = []
durations = []
while onset < sig_dur - 60:
c_idx = np.random.randint(0, len(amplitude))
onset += np.random.uniform(isi_min, isi_max) + stim_dur[c_idx]
onsets.append(onset)
conditions.append(annot_desc[c_idx])
durations.append(stim_dur[c_idx])
events = DataFrame({'trial_type': conditions,
'onset': onsets,
'duration': durations})
dm = make_first_level_design_matrix(frame_times, events,
hrf_model=hrf_model,
drift_model='polynomial',
drift_order=0)
dm = dm.drop(columns='constant')
annotations = Annotations(onsets, durations, conditions)
info = create_info(ch_names=[ch_name], sfreq=sfreq, ch_types=['hbo'])
for idx, annot in enumerate(annot_desc):
if annot in dm.columns:
dm[annot] *= amplitude[idx]
a = np.sum(dm.to_numpy(), axis=1) * 1.e-6
a = a.reshape(-1, 1).T
raw = RawArray(a, info, verbose=False)
raw.set_annotations(annotations, verbose='error')
return raw