def generate_ROIs(ROI_file, stimfunc, noise, scale_percentage, data_dict):
    # Create the signal in the ROI as specified.

    print('Loading', ROI_file)

    nii = nibabel.load(ROI_file)
    ROI = nii.get_data()

    # Find all the indices that contain signal
    idx_list = np.where(ROI == 1)

    idxs = np.zeros([len(idx_list[0]), 3])
    for idx_counter in list(range(0, len(idx_list[0]))):
        idxs[idx_counter, 0] = int(idx_list[0][idx_counter])
        idxs[idx_counter, 1] = int(idx_list[1][idx_counter])
        idxs[idx_counter, 2] = int(idx_list[2][idx_counter])

    idxs = idxs.astype('int8')

    # How many voxels per ROI
    voxels = int(ROI.sum())

    # Create a pattern of activity across the two voxels
    if data_dict['multivariate_pattern'] is True:
        pattern = np.random.rand(voxels).reshape((voxels, 1))
    else:  # Just make a univariate increase
        pattern = np.tile(1, voxels).reshape((voxels, 1))

    # Multiply each pattern by each voxel time course
    weights = np.tile(stimfunc, voxels) * pattern.T

    # Convolve the onsets with the HRF
    temporal_res = 1 / data_dict['trDuration']
    signal_func = sim.convolve_hrf(
        stimfunction=weights,
        tr_duration=data_dict['trDuration'],
        temporal_resolution=temporal_res,
        scale_function=1,
    )

    # Change the type of noise
    noise = noise.astype('double')

    # Create a noise function (same voxels for signal function as for noise)
    noise_function = noise[idxs[:, 0], idxs[:, 1], idxs[:, 2], :].T

    # Compute the signal magnitude for the data
    sf_scaled = sim.compute_signal_change(
        signal_function=signal_func,
        noise_function=noise_function,
        noise_dict=data_dict['noise_dict'],
        magnitude=[scale_percentage],
        method='PSC',
    )

    # Combine the signal time course with the signal volume
    signal = sim.apply_signal(
        sf_scaled,
        ROI,
    )

    # Return signal needed
    return signal
                               template=template,
                               mask=mask,
                               noise_dict=noise_dict,
                               )

    # Change the type of noise
    noise = noise.astype('double')

    # Create a noise function (same voxels for signal function as for noise)
    noise_function = noise[idxs[:, 0], idxs[:, 1], idxs[:, 2], :].T

    # Compute the signal magnitude for the data
    signal_func_scaled = sim.compute_signal_change(signal_function=signal_func,
                                                   noise_function=noise_function,
                                                   noise_dict=noise_dict,
                                                   magnitude=[
                                                       scale_percentage],
                                                   method='PSC',
                                                   )
    
    # Multiply the voxels with signal by the HRF function
    brain_signal = sim.apply_signal(signal_function=signal_func_scaled,
                                    volume_signal=signal_mask,
                                    )

    # Convert any nans to 0s
    brain_signal[np.isnan(brain_signal)] = 0

    # Combine the signal and the noise
    brain = brain_signal + noise
Example #3
0
def test_apply_signal():

    dimensions = np.array([10, 10, 10])  # What is the size of the brain
    feature_size = [2]
    feature_type = ['cube']
    feature_coordinates = np.array(
        [[5, 5, 5]])
    signal_magnitude = [30]

    # Generate a volume representing the location and quality of the signal
    volume = sim.generate_signal(dimensions=dimensions,
                                 feature_coordinates=feature_coordinates,
                                 feature_type=feature_type,
                                 feature_size=feature_size,
                                 signal_magnitude=signal_magnitude,
                                 )

    # Inputs for generate_stimfunction
    onsets = [10, 30, 50, 70, 90]
    event_durations = [6]
    tr_duration = 2
    duration = 100

    # Create the time course for the signal to be generated
    stimfunction = sim.generate_stimfunction(onsets=onsets,
                                             event_durations=event_durations,
                                             total_time=duration,
                                             )

    signal_function = sim.convolve_hrf(stimfunction=stimfunction,
                                       tr_duration=tr_duration,
                                       )

    # Check that you can compute signal change appropriately
    # Preset a bunch of things
    stimfunction_tr = stimfunction[::int(tr_duration * 100)]
    mask, template = sim.mask_brain(dimensions, mask_self=False)
    noise_dict = sim._noise_dict_update({})
    noise = sim.generate_noise(dimensions=dimensions,
                               stimfunction_tr=stimfunction_tr,
                               tr_duration=tr_duration,
                               template=template,
                               mask=mask,
                               noise_dict=noise_dict,
                               iterations=[0, 0]
                               )
    coords = feature_coordinates[0]
    noise_function_a = noise[coords[0], coords[1], coords[2], :]
    noise_function_a = noise_function_a.reshape(duration // tr_duration, 1)

    noise_function_b = noise[coords[0] + 1, coords[1], coords[2], :]
    noise_function_b = noise_function_b.reshape(duration // tr_duration, 1)

    # Create the calibrated signal with PSC
    method = 'PSC'
    sig_a = sim.compute_signal_change(signal_function,
                                      noise_function_a,
                                      noise_dict,
                                      [0.5],
                                      method,
                                      )
    sig_b = sim.compute_signal_change(signal_function,
                                      noise_function_a,
                                      noise_dict,
                                      [1.0],
                                      method,
                                      )

    assert sig_b.max() / sig_a.max() == 2, 'PSC modulation failed'

    # Create the calibrated signal with SFNR
    method = 'SFNR'
    sig_a = sim.compute_signal_change(signal_function,
                                      noise_function_a,
                                      noise_dict,
                                      [0.5],
                                      method,
                                      )
    scaled_a = sig_a / (noise_function_a.mean() / noise_dict['sfnr'])
    sig_b = sim.compute_signal_change(signal_function,
                                      noise_function_b,
                                      noise_dict,
                                      [1.0],
                                      method,
                                      )
    scaled_b = sig_b / (noise_function_b.mean() / noise_dict['sfnr'])

    assert scaled_b.max() / scaled_a.max() == 2, 'SFNR modulation failed'

    # Create the calibrated signal with CNR_Amp/Noise-SD
    method = 'CNR_Amp/Noise-SD'
    sig_a = sim.compute_signal_change(signal_function,
                                      noise_function_a,
                                      noise_dict,
                                      [0.5],
                                      method,
                                      )
    scaled_a = sig_a / noise_function_a.std()
    sig_b = sim.compute_signal_change(signal_function,
                                      noise_function_b,
                                      noise_dict,
                                      [1.0],
                                      method,
                                      )
    scaled_b = sig_b / noise_function_b.std()

    assert scaled_b.max() / scaled_a.max() == 2, 'CNR_Amp modulation failed'

    # Create the calibrated signal with CNR_Amp/Noise-Var_dB
    method = 'CNR_Amp2/Noise-Var_dB'
    sig_a = sim.compute_signal_change(signal_function,
                                      noise_function_a,
                                      noise_dict,
                                      [0.5],
                                      method,
                                      )
    scaled_a = np.log(sig_a.max() / noise_function_a.std())
    sig_b = sim.compute_signal_change(signal_function,
                                      noise_function_b,
                                      noise_dict,
                                      [1.0],
                                      method,
                                      )
    scaled_b = np.log(sig_b.max() / noise_function_b.std())

    assert np.round(scaled_b / scaled_a) == 2, 'CNR_Amp dB modulation failed'

    # Create the calibrated signal with CNR_Signal-SD/Noise-SD
    method = 'CNR_Signal-SD/Noise-SD'
    sig_a = sim.compute_signal_change(signal_function,
                                      noise_function_a,
                                      noise_dict,
                                      [0.5],
                                      method,
                                      )
    scaled_a = sig_a.std() / noise_function_a.std()
    sig_b = sim.compute_signal_change(signal_function,
                                      noise_function_a,
                                      noise_dict,
                                      [1.0],
                                      method,
                                      )
    scaled_b = sig_b.std() / noise_function_a.std()

    assert (scaled_b / scaled_a) == 2, 'CNR signal modulation failed'

    # Create the calibrated signal with CNR_Amp/Noise-Var_dB
    method = 'CNR_Signal-Var/Noise-Var_dB'
    sig_a = sim.compute_signal_change(signal_function,
                                      noise_function_a,
                                      noise_dict,
                                      [0.5],
                                      method,
                                      )

    scaled_a = np.log(sig_a.std() / noise_function_a.std())
    sig_b = sim.compute_signal_change(signal_function,
                                      noise_function_b,
                                      noise_dict,
                                      [1.0],
                                      method,
                                      )
    scaled_b = np.log(sig_b.std() / noise_function_b.std())

    assert np.round(scaled_b / scaled_a) == 2, 'CNR signal dB modulation ' \
                                               'failed'

    # Convolve the HRF with the stimulus sequence
    signal = sim.apply_signal(signal_function=signal_function,
                              volume_signal=volume,
                              )

    assert signal.shape == (dimensions[0], dimensions[1], dimensions[2],
                            duration / tr_duration), "The output is the " \
                                                     "wrong size"

    signal = sim.apply_signal(signal_function=stimfunction,
                              volume_signal=volume,
                              )

    assert np.any(signal == signal_magnitude), "The stimfunction is not binary"

    # Check that there is an error if the number of signal voxels doesn't
    # match the number of non zero brain voxels
    with pytest.raises(IndexError):
        sig_vox = (volume > 0).sum()
        vox_pattern = np.tile(stimfunction, (1, sig_vox - 1))
        sim.apply_signal(signal_function=vox_pattern,
                         volume_signal=volume,
                         )
Example #4
0
def test_apply_signal():

    dimensions = np.array([10, 10, 10])  # What is the size of the brain
    feature_size = [2]
    feature_type = ['cube']
    feature_coordinates = np.array([[5, 5, 5]])
    signal_magnitude = [30]

    # Generate a volume representing the location and quality of the signal
    volume = sim.generate_signal(
        dimensions=dimensions,
        feature_coordinates=feature_coordinates,
        feature_type=feature_type,
        feature_size=feature_size,
        signal_magnitude=signal_magnitude,
    )

    # Inputs for generate_stimfunction
    onsets = [10, 30, 50, 70, 90]
    event_durations = [6]
    tr_duration = 2
    duration = 100

    # Create the time course for the signal to be generated
    stimfunction = sim.generate_stimfunction(
        onsets=onsets,
        event_durations=event_durations,
        total_time=duration,
    )

    signal_function = sim.convolve_hrf(
        stimfunction=stimfunction,
        tr_duration=tr_duration,
    )

    # Check that you can compute signal change appropriately
    # Preset a bunch of things
    stimfunction_tr = stimfunction[::int(tr_duration * 100)]
    mask, template = sim.mask_brain(dimensions, mask_self=False)
    noise_dict = sim._noise_dict_update({})
    noise = sim.generate_noise(dimensions=dimensions,
                               stimfunction_tr=stimfunction_tr,
                               tr_duration=tr_duration,
                               template=template,
                               mask=mask,
                               noise_dict=noise_dict,
                               iterations=[0, 0])
    coords = feature_coordinates[0]
    noise_function_a = noise[coords[0], coords[1], coords[2], :]
    noise_function_a = noise_function_a.reshape(duration // tr_duration, 1)

    noise_function_b = noise[coords[0] + 1, coords[1], coords[2], :]
    noise_function_b = noise_function_b.reshape(duration // tr_duration, 1)

    # Create the calibrated signal with PSC
    method = 'PSC'
    sig_a = sim.compute_signal_change(
        signal_function,
        noise_function_a,
        noise_dict,
        [0.5],
        method,
    )
    sig_b = sim.compute_signal_change(
        signal_function,
        noise_function_a,
        noise_dict,
        [1.0],
        method,
    )

    assert sig_b.max() / sig_a.max() == 2, 'PSC modulation failed'

    # Create the calibrated signal with SFNR
    method = 'SFNR'
    sig_a = sim.compute_signal_change(
        signal_function,
        noise_function_a,
        noise_dict,
        [0.5],
        method,
    )
    scaled_a = sig_a / (noise_function_a.mean() / noise_dict['sfnr'])
    sig_b = sim.compute_signal_change(
        signal_function,
        noise_function_b,
        noise_dict,
        [1.0],
        method,
    )
    scaled_b = sig_b / (noise_function_b.mean() / noise_dict['sfnr'])

    assert scaled_b.max() / scaled_a.max() == 2, 'SFNR modulation failed'

    # Create the calibrated signal with CNR_Amp/Noise-SD
    method = 'CNR_Amp/Noise-SD'
    sig_a = sim.compute_signal_change(
        signal_function,
        noise_function_a,
        noise_dict,
        [0.5],
        method,
    )
    scaled_a = sig_a / noise_function_a.std()
    sig_b = sim.compute_signal_change(
        signal_function,
        noise_function_b,
        noise_dict,
        [1.0],
        method,
    )
    scaled_b = sig_b / noise_function_b.std()

    assert scaled_b.max() / scaled_a.max() == 2, 'CNR_Amp modulation failed'

    # Create the calibrated signal with CNR_Amp/Noise-Var_dB
    method = 'CNR_Amp2/Noise-Var_dB'
    sig_a = sim.compute_signal_change(
        signal_function,
        noise_function_a,
        noise_dict,
        [0.5],
        method,
    )
    scaled_a = np.log(sig_a.max() / noise_function_a.std())
    sig_b = sim.compute_signal_change(
        signal_function,
        noise_function_b,
        noise_dict,
        [1.0],
        method,
    )
    scaled_b = np.log(sig_b.max() / noise_function_b.std())

    assert np.round(scaled_b / scaled_a) == 2, 'CNR_Amp dB modulation failed'

    # Create the calibrated signal with CNR_Signal-SD/Noise-SD
    method = 'CNR_Signal-SD/Noise-SD'
    sig_a = sim.compute_signal_change(
        signal_function,
        noise_function_a,
        noise_dict,
        [0.5],
        method,
    )
    scaled_a = sig_a.std() / noise_function_a.std()
    sig_b = sim.compute_signal_change(
        signal_function,
        noise_function_a,
        noise_dict,
        [1.0],
        method,
    )
    scaled_b = sig_b.std() / noise_function_a.std()

    assert (scaled_b / scaled_a) == 2, 'CNR signal modulation failed'

    # Create the calibrated signal with CNR_Amp/Noise-Var_dB
    method = 'CNR_Signal-Var/Noise-Var_dB'
    sig_a = sim.compute_signal_change(
        signal_function,
        noise_function_a,
        noise_dict,
        [0.5],
        method,
    )

    scaled_a = np.log(sig_a.std() / noise_function_a.std())
    sig_b = sim.compute_signal_change(
        signal_function,
        noise_function_b,
        noise_dict,
        [1.0],
        method,
    )
    scaled_b = np.log(sig_b.std() / noise_function_b.std())

    assert np.round(scaled_b / scaled_a) == 2, 'CNR signal dB modulation ' \
                                               'failed'

    # Convolve the HRF with the stimulus sequence
    signal = sim.apply_signal(
        signal_function=signal_function,
        volume_signal=volume,
    )

    assert signal.shape == (dimensions[0], dimensions[1], dimensions[2],
                            duration / tr_duration), "The output is the " \
                                                     "wrong size"

    signal = sim.apply_signal(
        signal_function=stimfunction,
        volume_signal=volume,
    )

    assert np.any(signal == signal_magnitude), "The stimfunction is not binary"

    # Check that there is an error if the number of signal voxels doesn't
    # match the number of non zero brain voxels
    with pytest.raises(IndexError):
        sig_vox = (volume > 0).sum()
        vox_pattern = np.tile(stimfunction, (1, sig_vox - 1))
        sim.apply_signal(
            signal_function=vox_pattern,
            volume_signal=volume,
        )
Example #5
0
def _generate_ROIs(ROI_file, stimfunc, noise, scale_percentage, data_dict):
    """Make signal activity for an ROI of data
        Creates the specified evoked response time course, calibrated to the
        expected signal change, for a given ROI

    Parameters
    ----------

    ROI_file : str
        Path to the file of the ROI being loaded in

    stimfunc : 1 dimensional array
        Time course of evoked response. Output from
        fmrisim.generate_stimfunction

    noise : 4 dimensional array
        Volume of noise generated from fmrisim.generate_noise. Although this
        is needed as an input, this is only so that the percent signal change
        can be calibrated. This is not combined with the signal generated.

    scale_percentage : float
        What is the percent signal change for the evoked response

    data_dict : dict
        A dictionary to specify the parameters used for making data,
        specifying the following keys
        numTRs - int - Specify the number of time points
        multivariate_patterns - bool - Is the difference between conditions
        univariate (0) or multivariate (1)
        different_ROIs - bool - Are there different ROIs for each condition (
        1) or is it in the same ROI (0). If it is the same ROI and you are
        using univariate differences, the second condition will have a
        smaller evoked response than the other.
        event_duration - int - How long, in seconds, is each event
        scale_percentage - float - What is the percent signal change
        trDuration - float - How many seconds per volume
        save_dicom - bool - Save to data as a dicom (1) or numpy (0)
        save_realtime - bool - Do you want to save the data in real time (1)
        or as fast as possible (0)?
        isi - float - What is the time between each event (in seconds)
        burn_in - int - How long before the first event (in seconds)

    Returns
    ----------

    signal : 4 dimensional array
    Volume of signal in the specified ROI (noise has not yet been added)

    """

    # Create the signal in the ROI as specified.

    # Load in the template data (it may already be loaded if doing a test)
    if isinstance(ROI_file, str):
        logger.info('Loading', ROI_file)
        nii = nibabel.load(ROI_file)
        ROI = nii.get_data()
    else:
        ROI = ROI_file

    # Find all the indices that contain signal
    idx_list = np.where(ROI == 1)

    idxs = np.zeros([len(idx_list[0]), 3])
    for idx_counter in list(range(0, len(idx_list[0]))):
        idxs[idx_counter, 0] = int(idx_list[0][idx_counter])
        idxs[idx_counter, 1] = int(idx_list[1][idx_counter])
        idxs[idx_counter, 2] = int(idx_list[2][idx_counter])

    idxs = idxs.astype('int8')

    # How many voxels per ROI
    voxels = int(ROI.sum())

    # Create a pattern of activity across the two voxels
    if data_dict['multivariate_pattern'] is True:
        pattern = np.random.rand(voxels).reshape((voxels, 1))
    else:  # Just make a univariate increase
        pattern = np.tile(1, voxels).reshape((voxels, 1))

    # Multiply each pattern by each voxel time course
    weights = np.tile(stimfunc, voxels) * pattern.T

    # Convolve the onsets with the HRF
    temporal_res = 1 / data_dict['trDuration']
    signal_func = sim.convolve_hrf(
        stimfunction=weights,
        tr_duration=data_dict['trDuration'],
        temporal_resolution=temporal_res,
        scale_function=1,
    )

    # Change the type of noise
    noise = noise.astype('double')

    # Create a noise function (same voxels for signal function as for noise)
    noise_function = noise[idxs[:, 0], idxs[:, 1], idxs[:, 2], :].T

    # Compute the signal magnitude for the data
    sf_scaled = sim.compute_signal_change(
        signal_function=signal_func,
        noise_function=noise_function,
        noise_dict=data_dict['noise_dict'],
        magnitude=[scale_percentage],
        method='PSC',
    )

    # Combine the signal time course with the signal volume
    signal = sim.apply_signal(
        sf_scaled,
        ROI,
    )

    # Return signal needed
    return signal