# Combine the signals from the two conditions signal = signal_A + signal_B # Combine the stim functions stimfunction = list(np.add(stimfunction_A, stimfunction_B)) stimfunction_tr = stimfunction[::int(tr_duration * temporal_res)] # Generate the mask of the signal mask, template = sim.mask_brain(signal, mask_threshold=0.2) # Mask the signal to the shape of a brain (attenuates signal according to grey # matter likelihood) signal *= mask.reshape(dimensions[0], dimensions[1], dimensions[2], 1) # Generate original noise dict for comparison later orig_noise_dict = sim._noise_dict_update({}) # Create the noise volumes (using the default parameters noise = sim.generate_noise(dimensions=dimensions, stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, mask=mask, template=template, noise_dict=orig_noise_dict, ) # Standardize the signal activity to make it percent signal change mean_act = (mask * orig_noise_dict['max_activity']).sum() / (mask > 0).sum() signal = signal * mean_act / 100 # Combine the signal and the noise
def test_calc_noise(): # Inputs for functions onsets = [10, 30, 50, 70, 90] event_durations = [6] tr_duration = 2 duration = 200 temporal_res = 100 tr_number = int(np.floor(duration / tr_duration)) dimensions_tr = np.array([10, 10, 10, tr_number]) # Preset the noise dict nd_orig = sim._noise_dict_update({}) # Create the time course for the signal to be generated stimfunction = sim.generate_stimfunction( onsets=onsets, event_durations=event_durations, total_time=duration, temporal_resolution=temporal_res, ) # Mask the volume to be the same shape as a brain mask, template = sim.mask_brain(dimensions_tr, mask_self=None) stimfunction_tr = stimfunction[::int(tr_duration * temporal_res)] nd_orig['matched'] = 0 noise = sim.generate_noise( dimensions=dimensions_tr[0:3], stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, template=template, mask=mask, noise_dict=nd_orig, ) # Check the spatial noise match nd_orig['matched'] = 1 noise_matched = sim.generate_noise(dimensions=dimensions_tr[0:3], stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, template=template, mask=mask, noise_dict=nd_orig, iterations=[50, 0]) # Calculate the noise parameters from this newly generated volume nd_new = sim.calc_noise(noise, mask, template) nd_matched = sim.calc_noise(noise_matched, mask, template) # Check the values are reasonable" assert nd_new['snr'] > 0, 'snr out of range' assert nd_new['sfnr'] > 0, 'sfnr out of range' assert nd_new['auto_reg_rho'][0] > 0, 'ar out of range' # Check that the dilation increases SNR no_dilation_snr = sim._calc_snr( noise_matched, mask, dilation=0, reference_tr=tr_duration, ) assert nd_new['snr'] > no_dilation_snr, "Dilation did not increase SNR" # Check that template size is in bounds with pytest.raises(ValueError): sim.calc_noise(noise, mask, template * 2) # Check that Mask is set is checked with pytest.raises(ValueError): sim.calc_noise(noise, None, template) # Check that it can deal with missing noise parameters temp_nd = sim.calc_noise(noise, mask, template, noise_dict={}) assert temp_nd['voxel_size'][0] == 1, 'Default voxel size not set' temp_nd = sim.calc_noise(noise, mask, template, noise_dict=None) assert temp_nd['voxel_size'][0] == 1, 'Default voxel size not set' # Check that the fitting worked snr_diff = abs(nd_orig['snr'] - nd_new['snr']) snr_diff_match = abs(nd_orig['snr'] - nd_matched['snr']) assert snr_diff > snr_diff_match, 'snr fit incorrectly' # Test that you can generate rician and exponential noise sim._generate_noise_system( dimensions_tr, 1, 1, spatial_noise_type='exponential', temporal_noise_type='rician', ) # Check the temporal noise match nd_orig['matched'] = 1 noise_matched = sim.generate_noise(dimensions=dimensions_tr[0:3], stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, template=template, mask=mask, noise_dict=nd_orig, iterations=[0, 50]) nd_matched = sim.calc_noise(noise_matched, mask, template) sfnr_diff = abs(nd_orig['sfnr'] - nd_new['sfnr']) sfnr_diff_match = abs(nd_orig['sfnr'] - nd_matched['sfnr']) assert sfnr_diff > sfnr_diff_match, 'sfnr fit incorrectly' ar1_diff = abs(nd_orig['auto_reg_rho'][0] - nd_new['auto_reg_rho'][0]) ar1_diff_match = abs(nd_orig['auto_reg_rho'][0] - nd_matched['auto_reg_rho'][0]) assert ar1_diff > ar1_diff_match, 'AR1 fit incorrectly' # Check that you can calculate ARMA for a single voxel vox = noise[5, 5, 5, :] arma = sim._calc_ARMA_noise( vox, None, sample_num=2, ) assert len(arma) == 2, "Two outputs not given by ARMA"
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, )
def test_calc_noise(): # Inputs for functions onsets = [10, 30, 50, 70, 90] event_durations = [6] tr_duration = 2 duration = 200 temporal_res = 100 tr_number = int(np.floor(duration / tr_duration)) dimensions_tr = np.array([10, 10, 10, tr_number]) # Preset the noise dict nd_orig = sim._noise_dict_update({}) # Create the time course for the signal to be generated stimfunction = sim.generate_stimfunction(onsets=onsets, event_durations=event_durations, total_time=duration, temporal_resolution=temporal_res, ) # Mask the volume to be the same shape as a brain mask, template = sim.mask_brain(dimensions_tr, mask_self=None) stimfunction_tr = stimfunction[::int(tr_duration * temporal_res)] nd_orig['matched'] = 0 noise = sim.generate_noise(dimensions=dimensions_tr[0:3], stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, template=template, mask=mask, noise_dict=nd_orig, ) # Check the spatial noise match nd_orig['matched'] = 1 noise_matched = sim.generate_noise(dimensions=dimensions_tr[0:3], stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, template=template, mask=mask, noise_dict=nd_orig, iterations=[50, 0] ) # Calculate the noise parameters from this newly generated volume nd_new = sim.calc_noise(noise, mask, template) nd_matched = sim.calc_noise(noise_matched, mask, template) # Check the values are reasonable" assert nd_new['snr'] > 0, 'snr out of range' assert nd_new['sfnr'] > 0, 'sfnr out of range' assert nd_new['auto_reg_rho'][0] > 0, 'ar out of range' # Check that the dilation increases SNR no_dilation_snr = sim._calc_snr(noise_matched, mask, dilation=0, reference_tr=tr_duration, ) assert nd_new['snr'] > no_dilation_snr, "Dilation did not increase SNR" # Check that template size is in bounds with pytest.raises(ValueError): sim.calc_noise(noise, mask, template * 2) # Check that Mask is set is checked with pytest.raises(ValueError): sim.calc_noise(noise, None, template) # Check that it can deal with missing noise parameters temp_nd = sim.calc_noise(noise, mask, template, noise_dict={}) assert temp_nd['voxel_size'][0] == 1, 'Default voxel size not set' temp_nd = sim.calc_noise(noise, mask, template, noise_dict=None) assert temp_nd['voxel_size'][0] == 1, 'Default voxel size not set' # Check that the fitting worked snr_diff = abs(nd_orig['snr'] - nd_new['snr']) snr_diff_match = abs(nd_orig['snr'] - nd_matched['snr']) assert snr_diff > snr_diff_match, 'snr fit incorrectly' # Test that you can generate rician and exponential noise sim._generate_noise_system(dimensions_tr, 1, 1, spatial_noise_type='exponential', temporal_noise_type='rician', ) # Check the temporal noise match nd_orig['matched'] = 1 noise_matched = sim.generate_noise(dimensions=dimensions_tr[0:3], stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, template=template, mask=mask, noise_dict=nd_orig, iterations=[0, 50] ) nd_matched = sim.calc_noise(noise_matched, mask, template) sfnr_diff = abs(nd_orig['sfnr'] - nd_new['sfnr']) sfnr_diff_match = abs(nd_orig['sfnr'] - nd_matched['sfnr']) assert sfnr_diff > sfnr_diff_match, 'sfnr fit incorrectly' ar1_diff = abs(nd_orig['auto_reg_rho'][0] - nd_new['auto_reg_rho'][0]) ar1_diff_match = abs(nd_orig['auto_reg_rho'][0] - nd_matched[ 'auto_reg_rho'][0]) assert ar1_diff > ar1_diff_match, 'AR1 fit incorrectly' # Check that you can calculate ARMA for a single voxel vox = noise[5, 5, 5, :] arma = sim._calc_ARMA_noise(vox, None, sample_num=2, ) assert len(arma) == 2, "Two outputs not given by ARMA"
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, )
# Combine the signals from the two conditions signal = signal_A + signal_B # Combine the stim functions stimfunction = list(np.add(stimfunction_A, stimfunction_B)) stimfunction_tr = stimfunction[::int(tr_duration * temporal_res)] # Generate the mask of the signal mask = sim.mask_brain(signal) # Mask the signal to the shape of a brain (attenuates signal according to grey # matter likelihood) signal *= mask # Generate original noise dict for comparison later orig_noise_dict = sim._noise_dict_update({}) # Create the noise volumes (using the default parameters noise = sim.generate_noise( dimensions=dimensions, stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, mask=mask, noise_dict=orig_noise_dict, ) # Standardize the signal activity to make it percent signal change mean_act = (mask * orig_noise_dict['max_activity']).sum() / (mask > 0).sum() signal = signal * mean_act / 100 # Combine the signal and the noise