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.0, amplitude=1.0, annot_desc="A", sig_dur=300.0, stim_dur=5.0, isi_min=15.0, isi_max=45.0, 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 not isinstance(amplitude, list): amplitude = [amplitude] if not isinstance(annot_desc, list): annot_desc = [annot_desc] if not isinstance(stim_dur, 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.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.0e-6 a = a.reshape(-1, 1).T raw = RawArray(a, info, verbose=False) raw.set_annotations(annotations, verbose="error") return raw