def test_calc_noise(): # Inputs for functions onsets = [10, 30, 50, 70, 90] event_durations = [6] tr_duration = 2 duration = 200 tr_number = int(np.floor(duration / tr_duration)) dimensions_tr = np.array([10, 10, 10, tr_number]) # Preset the noise dict nd_orig = { 'auto_reg_sigma': 0.6, 'drift_sigma': 0.4, 'snr': 30, 'sfnr': 30, 'max_activity': 1000, 'fwhm': 4, } # Create the time course for the signal to be generated stimfunction = sim.generate_stimfunction( onsets=onsets, event_durations=event_durations, total_time=duration, ) # Mask the volume to be the same shape as a brain mask, template = sim.mask_brain(dimensions_tr, mask_threshold=0.2) stimfunction_tr = stimfunction[::int(tr_duration * 100)] 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 that noise_system is being calculated correctly spatial_sd = 5 temporal_sd = 5 noise_system = sim._generate_noise_system(dimensions_tr, spatial_sd, temporal_sd) precision = abs(noise_system[0, 0, 0, :].std() - spatial_sd) assert precision < spatial_sd, 'noise_system calculated incorrectly' precision = abs(noise_system[:, :, :, 0].std() - temporal_sd) assert precision < spatial_sd, 'noise_system calculated incorrectly' # Calculate the noise nd_calc = sim.calc_noise(volume=noise, mask=mask) # How precise are these estimates precision = abs(nd_calc['snr'] - nd_orig['snr']) assert precision < nd_orig['snr'], 'snr calculated incorrectly' precision = abs(nd_calc['sfnr'] - nd_orig['sfnr']) assert precision < nd_orig['sfnr'], 'sfnr calculated incorrectly'
def test_calc_noise(): # Inputs for functions onsets = [10, 30, 50, 70, 90] event_durations = [6] tr_duration = 2 duration = 200 tr_number = int(np.floor(duration / tr_duration)) dimensions_tr = np.array([10, 10, 10, tr_number]) # Preset the noise dict nd_orig = {'auto_reg_sigma': 0.6, 'drift_sigma': 0.4, 'snr': 30, 'sfnr': 30, 'max_activity': 1000, 'fwhm': 4, } # Create the time course for the signal to be generated stimfunction = sim.generate_stimfunction(onsets=onsets, event_durations=event_durations, total_time=duration, ) # Mask the volume to be the same shape as a brain mask, template = sim.mask_brain(dimensions_tr, mask_threshold=0.2) stimfunction_tr = stimfunction[::int(tr_duration * 100)] 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 that noise_system is being calculated correctly spatial_sd = 5 temporal_sd = 5 noise_system = sim._generate_noise_system(dimensions_tr, spatial_sd, temporal_sd) precision = abs(noise_system[0, 0, 0, :].std() - spatial_sd) assert precision < spatial_sd, 'noise_system calculated incorrectly' precision = abs(noise_system[:, :, :, 0].std() - temporal_sd) assert precision < spatial_sd, 'noise_system calculated incorrectly' # Calculate the noise nd_calc = sim.calc_noise(volume=noise, mask=mask) # How precise are these estimates precision = abs(nd_calc['snr'] - nd_orig['snr']) assert precision < nd_orig['snr'], 'snr calculated incorrectly' precision = abs(nd_calc['sfnr'] - nd_orig['sfnr']) assert precision < nd_orig['sfnr'], 'sfnr calculated incorrectly'
def test_generate_stimfunction(): # 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, ) assert stimfunction.shape[0] == duration * 100, "stimfunc incorrect length" eventNumber = np.sum(event_durations * len(onsets)) * 100 assert np.sum(stimfunction) == eventNumber, "Event number" # Create the signal function signal_function = sim.convolve_hrf( stimfunction=stimfunction, tr_duration=tr_duration, ) stim_dur = stimfunction.shape[0] / (tr_duration * 100) assert signal_function.shape[0] == stim_dur, "The length did not change" # Test onsets = [0] tr_duration = 1 event_durations = [1] stimfunction = sim.generate_stimfunction( onsets=onsets, event_durations=event_durations, total_time=duration, ) signal_function = sim.convolve_hrf( stimfunction=stimfunction, tr_duration=tr_duration, ) max_response = np.where(signal_function != 0)[0].max() assert 25 < max_response <= 30, "HRF has the incorrect length" assert np.sum(signal_function < 0) > 0, "No values below zero"
def test_generate_stimfunction(): # 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, ) assert stimfunction.shape[0] == duration * 100, "stimfunc incorrect length" eventNumber = np.sum(event_durations * len(onsets)) * 100 assert np.sum(stimfunction) == eventNumber, "Event number" # Create the signal function signal_function = sim.convolve_hrf(stimfunction=stimfunction, tr_duration=tr_duration, ) stim_dur = stimfunction.shape[0] / (tr_duration * 100) assert signal_function.shape[0] == stim_dur, "The length did not change" # Test onsets = [0] tr_duration = 1 event_durations = [1] stimfunction = sim.generate_stimfunction(onsets=onsets, event_durations=event_durations, total_time=duration, ) signal_function = sim.convolve_hrf(stimfunction=stimfunction, tr_duration=tr_duration, ) max_response = np.where(signal_function != 0)[0].max() assert 25 < max_response <= 30, "HRF has the incorrect length" assert np.sum(signal_function < 0) > 0, "No values below zero"
def test_generate_stimfunction(): # 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, ) assert len(stimfunction) == duration * 1000, "stimfunction incorrect " \ "length" eventNumber = np.sum(event_durations * len(onsets)) * 1000 assert np.sum(stimfunction) == eventNumber, "Event number" # Create the signal function signal_function = sim.double_gamma_hrf( stimfunction=stimfunction, tr_duration=tr_duration, ) assert len(signal_function) == len(stimfunction) / (tr_duration * 1000), \ "The length did not change" onsets = [10] stimfunction = sim.generate_stimfunction( onsets=onsets, event_durations=event_durations, total_time=duration, ) signal_function = sim.double_gamma_hrf( stimfunction=stimfunction, tr_duration=tr_duration, ) assert np.sum(signal_function < 0) > 0, "No values below zero"
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.double_gamma_hrf( stimfunction=stimfunction, tr_duration=tr_duration, ) # Convolve the HRF with the stimulus sequence signal = sim.apply_signal( signal_function=signal_function, volume_static=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_static=volume, ) assert np.any(signal == signal_magnitude), "The stimfunction is not binary"
def test_calc_noise(): # Inputs for functions onsets = [10, 30, 50, 70, 90] event_durations = [6] tr_duration = 2 duration = 100 tr_number = int(np.floor(duration / tr_duration)) dimensions_tr = np.array([10, 10, 10, tr_number]) # Preset the noise dict nd_orig = { 'auto_reg_sigma': 1, 'drift_sigma': 0.5, 'overall': 0.1, 'snr': 30, 'spatial_sigma': 0.15, 'system_sigma': 1, } # Create the time course for the signal to be generated stimfunction = sim.generate_stimfunction( onsets=onsets, event_durations=event_durations, total_time=duration, ) # Mask the volume to be the same shape as a brain mask = sim.mask_brain(dimensions_tr) noise = sim.generate_noise( dimensions=dimensions_tr[0:3], stimfunction=stimfunction, tr_duration=tr_duration, mask=mask, noise_dict=nd_orig, ) # Calculate the noise nd_calc = sim.calc_noise(noise, mask) assert abs(nd_calc['overall'] - nd_orig['overall']) < 0.1, 'overall ' \ 'calculated ' \ 'incorrectly' assert abs(nd_calc['snr'] - nd_orig['snr']) < 10, 'snr calculated ' \ 'incorrectly' assert abs(nd_calc['system_sigma'] - nd_orig['system_sigma']) < 1, \ 'snr calculated incorrectly'
def test_generate_stimfunction(): # 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, tr_duration=tr_duration, ) assert len(stimfunction) == duration / tr_duration, "stimfunction incorrect " \ "length" assert np.sum(stimfunction) == np.sum(event_durations * len(onsets)) / \ tr_duration, "Event number" # Create the signal function signal_function = sim.double_gamma_hrf(stimfunction=stimfunction, ) assert len(signal_function) == len(stimfunction), "The length did not change" onsets = [10] stimfunction = sim.generate_stimfunction(onsets=onsets, event_durations=event_durations, total_time=duration, tr_duration=tr_duration, ) signal_function = sim.double_gamma_hrf(stimfunction=stimfunction, ) assert np.sum(signal_function < 0) > 0, "No values below zero"
def univ_neural_signal(spec, tr, nvolumes): """ For each event/condition in the input spec, generate a neural signal function (e.g. boxcar) and append it to the spec """ for event in spec: # TODO: add option for lag if event['signal_type'] == 'boxcar': event['neural_signal'] = generate_stimfunction( event['onsets'], event['durations'], (nvolumes * tr), weights=event['amplitudes']) return spec
def test_calc_noise(): # Inputs for functions onsets = [10, 30, 50, 70, 90] event_durations = [6] tr_duration = 2 duration = 100 tr_number = int(np.floor(duration / tr_duration)) dimensions_tr = np.array([10, 10, 10, tr_number]) # Preset the noise dict nd_orig = { 'auto_reg_sigma': 0.6, 'drift_sigma': 0.4, 'temporal_noise': 5, 'sfnr': 30, 'max_activity': 1000, 'fwhm': 4, } # Create the time course for the signal to be generated stimfunction = sim.generate_stimfunction( onsets=onsets, event_durations=event_durations, total_time=duration, ) # Mask the volume to be the same shape as a brain mask = sim.mask_brain(dimensions_tr) stimfunction_tr = stimfunction[::int(tr_duration * 1000)] noise = sim.generate_noise( dimensions=dimensions_tr[0:3], stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, mask=mask, noise_dict=nd_orig, ) # Calculate the noise nd_calc = sim.calc_noise(noise, mask) # How precise are these estimates precision = abs(nd_calc['temporal_noise'] - nd_orig['temporal_noise']) assert precision < 1, 'temporal_noise calculated incorrectly' precision = abs(nd_calc['sfnr'] - nd_orig['sfnr']) assert precision < 5, 'sfnr calculated incorrectly'
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, ) # 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"
def test_calc_noise(): # Inputs for functions onsets = [10, 30, 50, 70, 90] event_durations = [6] tr_duration = 2 duration = 100 tr_number = int(np.floor(duration / tr_duration)) dimensions_tr = np.array([10, 10, 10, tr_number]) # Preset the noise dict nd_orig = {'auto_reg_sigma': 1, 'drift_sigma': 0.5, 'overall': 0.1, 'snr': 30, 'spatial_sigma': 0.15, 'system_sigma': 1, } # Create the time course for the signal to be generated stimfunction = sim.generate_stimfunction(onsets=onsets, event_durations=event_durations, total_time=duration, ) # Mask the volume to be the same shape as a brain mask = sim.mask_brain(dimensions_tr) noise = sim.generate_noise(dimensions=dimensions_tr[0:3], stimfunction=stimfunction, tr_duration=tr_duration, mask=mask, noise_dict=nd_orig, ) # Calculate the noise nd_calc = sim.calc_noise(noise, mask) assert abs(nd_calc['overall'] - nd_orig['overall']) < 0.1, 'overall ' \ 'calculated ' \ 'incorrectly' assert abs(nd_calc['snr'] - nd_orig['snr']) < 10, 'snr calculated ' \ 'incorrectly' assert abs(nd_calc['system_sigma'] - nd_orig['system_sigma']) < 1, \ 'snr calculated incorrectly'
def test_generate_noise(): 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 = [1] # 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.double_gamma_hrf( stimfunction=stimfunction, tr_duration=tr_duration, ) # Convolve the HRF with the stimulus sequence signal = sim.apply_signal( signal_function=signal_function, volume_static=volume, ) # Generate the mask of the signal mask = sim.mask_brain(signal, mask_threshold=0.1) assert min(mask[mask > 0]) > 0.1, "Mask thresholding did not work" stimfunction_tr = stimfunction[::int(tr_duration * 1000)] # Create the noise volumes (using the default parameters) noise = sim.generate_noise( dimensions=dimensions, stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, mask=mask, ) assert signal.shape == noise.shape, "The dimensions of signal and noise " \ "the same" assert np.std(signal) < np.std(noise), "Noise was not created" noise = sim.generate_noise( dimensions=dimensions, stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, mask=mask, noise_dict={ 'temporal_noise': 0, 'sfnr': 10000 }, ) temporal_noise = np.std(noise[mask[:, :, :, 0] > 0], 1).mean() assert temporal_noise <= 0.1, "Noise strength could not be manipulated"
dimensions=dimensions, feature_coordinates=feature_coordinates_B, feature_type=feature_type, feature_size=feature_size, signal_magnitude=signal_magnitude, ) # Visualize the signal that was generated for condition A fig = plt.figure() sim.plot_brain(fig, volume_static_A) plt.show() # Create the time course for the signal to be generated stimfunction_A = sim.generate_stimfunction( onsets=onsets_A, event_durations=event_durations, total_time=duration, tr_duration=tr_duration ) stimfunction_B = sim.generate_stimfunction( onsets=onsets_B, event_durations=event_durations, total_time=duration, tr_duration=tr_duration ) # Convolve the HRF with the stimulus sequence signal_function_A = sim.double_gamma_hrf(stimfunction=stimfunction_A) signal_function_B = sim.double_gamma_hrf(stimfunction=stimfunction_B) # Multiply the HRF timecourse with the signal signal_A = sim.apply_signal(signal_function=signal_function_A, volume_static=volume_static_A) signal_B = sim.apply_signal(signal_function=signal_function_B, volume_static=volume_static_B)
def test_generate_noise(): 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 = [1] # 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.double_gamma_hrf(stimfunction=stimfunction, tr_duration=tr_duration, ) # Convolve the HRF with the stimulus sequence signal = sim.apply_signal(signal_function=signal_function, volume_static=volume, ) # Generate the mask of the signal mask = sim.mask_brain(signal, mask_threshold=0.1) assert min(mask[mask > 0]) > 0.1, "Mask thresholding did not work" # Create the noise volumes (using the default parameters) noise = sim.generate_noise(dimensions=dimensions, stimfunction=stimfunction, tr_duration=tr_duration, mask=mask, ) assert signal.shape == noise.shape, "The dimensions of signal and noise " \ "the same" assert np.std(signal) < np.std(noise), "Noise was not created" noise = sim.generate_noise(dimensions=dimensions, stimfunction=stimfunction, tr_duration=tr_duration, mask=mask, noise_dict={'overall': 0}, ) assert np.sum(noise) == 0, "Noise strength could not be manipulated" assert np.std(noise) == 0, "Noise strength could not be manipulated"
randoized_label = np.repeat([1, 2], int(events / 2)).tolist() random.shuffle(randoized_label) for event_counter, cond in enumerate(randoized_label): # Flip a coin for each epoch to determine whether it is A or B if cond == 1: onsets_A.append(event_counter * (event_duration + isi)) elif cond == 2: onsets_B.append(event_counter * (event_duration + isi)) temporal_res = 1 # How many timepoints per second of the stim function are to be generated? # Create a time course of events stimfunc_A = sim.generate_stimfunction( onsets=onsets_A, event_durations=[event_duration], total_time=total_time, temporal_resolution=temporal_res, ) stimfunc_B = sim.generate_stimfunction( onsets=onsets_B, event_durations=[event_duration], total_time=total_time, temporal_resolution=temporal_res, ) # stimfunc per subject stimfunc_ppt = np.concatenate((stimfunc_A, stimfunc_B), axis=1) stimfunc_all.append(stimfunc_ppt) print('Load ROIs')
def test_generate_noise(): dimensions = np.array([64, 64, 36]) # What is the size of the brain feature_size = [2] feature_type = ['cube'] feature_coordinates = np.array( [[32, 32, 18]]) signal_magnitude = [30] # Generate a volume representing the location and quality of the signal volume_static = 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, tr_duration=tr_duration, ) signal_function = sim.double_gamma_hrf(stimfunction=stimfunction, ) # Convolve the HRF with the stimulus sequence signal = sim.apply_signal(signal_function=signal_function, volume_static=volume_static, ) # Create the noise volumes (using the default parameters) noise = sim.generate_noise(dimensions=dimensions, stimfunction=stimfunction, tr_duration=tr_duration, ) assert signal.shape == noise.shape, "The dimensions of signal " \ "and noise the same" Z_noise = sim._generate_noise_temporal(stimfunction, tr_duration, 1) noise = sim._generate_noise_temporal(stimfunction, tr_duration, 0) assert np.std(Z_noise) < np.std(noise), "Z scoring is not working" # Combine the signal and the noise volume = signal + noise assert np.std(signal) < np.std(noise), "Noise was not created" noise = sim.generate_noise(dimensions=dimensions, stimfunction=stimfunction, tr_duration=tr_duration, noise_strength=[0, 0, 0] ) assert np.sum(noise) == 0, "Noise strength could not be manipulated" assert np.std(noise) == 0, "Noise strength could not be manipulated"
def test_generate_stimfunction(): # 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, ) assert stimfunction.shape[0] == duration * 100, "stimfunc incorrect length" eventNumber = np.sum(event_durations * len(onsets)) * 100 assert np.sum(stimfunction) == eventNumber, "Event number" # Create the signal function signal_function = sim.convolve_hrf(stimfunction=stimfunction, tr_duration=tr_duration, ) stim_dur = stimfunction.shape[0] / (tr_duration * 100) assert signal_function.shape[0] == stim_dur, "The length did not change" # Test onsets = [0] tr_duration = 1 event_durations = [1] stimfunction = sim.generate_stimfunction(onsets=onsets, event_durations=event_durations, total_time=duration, ) signal_function = sim.convolve_hrf(stimfunction=stimfunction, tr_duration=tr_duration, ) max_response = np.where(signal_function != 0)[0].max() assert 25 < max_response <= 30, "HRF has the incorrect length" assert np.sum(signal_function < 0) > 0, "No values below zero" # Export a stimfunction sim.export_3_column(stimfunction, 'temp.txt', ) # Load in the stimfunction stimfunc_new = sim.generate_stimfunction(onsets=None, event_durations=None, total_time=duration, timing_file='temp.txt', ) assert np.all(stimfunc_new == stimfunction), "Export/import failed" # Break the timing precision of the generation stimfunc_new = sim.generate_stimfunction(onsets=None, event_durations=None, total_time=duration, timing_file='temp.txt', temporal_resolution=0.5, ) assert stimfunc_new.sum() == 0, "Temporal resolution not working right" # Set the duration to be too short so you should get an error onsets = [10, 30, 50, 70, 90] event_durations = [5] with pytest.raises(ValueError): sim.generate_stimfunction(onsets=onsets, event_durations=event_durations, total_time=89, ) # Clip the event offset stimfunc_new = sim.generate_stimfunction(onsets=onsets, event_durations=event_durations, total_time=95, ) assert stimfunc_new[-1] == 1, 'Event offset was not clipped' # Test exporting a group of participants to an epoch file cond_a = sim.generate_stimfunction(onsets=onsets, event_durations=event_durations, total_time=110, ) cond_b = sim.generate_stimfunction(onsets=[x + 5 for x in onsets], event_durations=event_durations, total_time=110, ) stimfunction_group = [np.hstack((cond_a, cond_b))] * 2 sim.export_epoch_file(stimfunction_group, 'temp.txt', tr_duration, ) # Check that convolve throws a warning when the shape is wrong sim.convolve_hrf(stimfunction=np.hstack((cond_a, cond_b)).T, tr_duration=tr_duration, temporal_resolution=1, )
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_generate_noise(): 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 = [1] # 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 = 200 # 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, ) # Convolve the HRF with the stimulus sequence signal = sim.apply_signal(signal_function=signal_function, volume_signal=volume, ) # Generate the mask of the signal mask, template = sim.mask_brain(signal, mask_self=None) assert min(mask[mask > 0]) > 0.1, "Mask thresholding did not work" assert len(np.unique(template) > 2), "Template creation did not work" stimfunction_tr = stimfunction[::int(tr_duration * 100)] # Create the noise volumes (using the default parameters) noise = sim.generate_noise(dimensions=dimensions, stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, template=template, mask=mask, iterations=[1, 0], ) assert signal.shape == noise.shape, "The dimensions of signal and noise " \ "the same" noise_high = sim.generate_noise(dimensions=dimensions, stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, template=template, mask=mask, noise_dict={'sfnr': 50, 'snr': 25}, iterations=[1, 0], ) noise_low = sim.generate_noise(dimensions=dimensions, stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, template=template, mask=mask, noise_dict={'sfnr': 100, 'snr': 25}, iterations=[1, 0], ) system_high = np.std(noise_high[mask > 0], 1).mean() system_low = np.std(noise_low[mask > 0], 1).mean() assert system_low < system_high, "SFNR noise could not be manipulated" # Check that you check for the appropriate template values with pytest.raises(ValueError): sim.generate_noise(dimensions=dimensions, stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, template=template * 2, mask=mask, noise_dict={}, ) # Check that iterations does what it should sim.generate_noise(dimensions=dimensions, stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, template=template, mask=mask, noise_dict={}, iterations=[0, 0], ) sim.generate_noise(dimensions=dimensions, stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, template=template, mask=mask, noise_dict={}, iterations=None, ) # Test drift noise trs = 1000 period = 100 drift = sim._generate_noise_temporal_drift(trs, tr_duration, 'sine', period, ) # Check that the max frequency is the appropriate frequency power = abs(np.fft.fft(drift))[1:trs // 2] freq = np.linspace(1, trs // 2 - 1, trs // 2 - 1) / trs period_freq = np.where(freq == 1 / (period // tr_duration)) max_freq = np.argmax(power) assert period_freq == max_freq, 'Max frequency is not where it should be' # Do the same but now with cosine basis functions, answer should be close drift = sim._generate_noise_temporal_drift(trs, tr_duration, 'discrete_cos', period, ) # Check that the appropriate frequency is peaky (may not be the max) power = abs(np.fft.fft(drift))[1:trs // 2] freq = np.linspace(1, trs // 2 - 1, trs // 2 - 1) / trs period_freq = np.where(freq == 1 / (period // tr_duration))[0][0] assert power[period_freq] > power[period_freq + 1], 'Power is low' assert power[period_freq] > power[period_freq - 1], 'Power is low' # Check it gives a warning if the duration is too short drift = sim._generate_noise_temporal_drift(50, tr_duration, 'discrete_cos', period, ) # Test physiological noise (using unrealistic parameters so that it's easy) timepoints = list(np.linspace(0, (trs - 1) * tr_duration, trs)) resp_freq = 0.2 heart_freq = 1.17 phys = sim._generate_noise_temporal_phys(timepoints, resp_freq, heart_freq, ) # Check that the max frequency is the appropriate frequency power = abs(np.fft.fft(phys))[1:trs // 2] freq = np.linspace(1, trs // 2 - 1, trs // 2 - 1) / (trs * tr_duration) peaks = (power > (power.mean() + power.std())) # Where are the peaks peak_freqs = freq[peaks] assert np.any(resp_freq == peak_freqs), 'Resp frequency not found' assert len(peak_freqs) == 2, 'Two peaks not found' # Test task noise sim._generate_noise_temporal_task(stimfunction_tr, motion_noise='gaussian', ) sim._generate_noise_temporal_task(stimfunction_tr, motion_noise='rician', ) # Test ARMA noise with pytest.raises(ValueError): noise_dict = {'fwhm': 4, 'auto_reg_rho': [1], 'ma_rho': [1, 1]} sim._generate_noise_temporal_autoregression(stimfunction_tr, noise_dict, dimensions, mask, ) # Generate spatial noise vol = sim._generate_noise_spatial(np.array([10, 10, 10, trs])) assert len(vol.shape) == 3, 'Volume was not reshaped to ignore TRs' # Switch some of the noise types on noise_dict = dict(physiological_sigma=1, drift_sigma=1, task_sigma=1, auto_reg_sigma=0) sim.generate_noise(dimensions=dimensions, stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, template=template, mask=mask, noise_dict=noise_dict, iterations=[0, 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, )
def generate_data(outputDir, user_settings): """Generate simulated fMRI data Use a few parameters that might be relevant for real time analysis Parameters ---------- outputDir : str Specify output data dir where the data should be saved user_settings : 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) """ data_dict = default_settings.copy() data_dict.update(user_settings) # If the folder doesn't exist then make it os.system('mkdir -p %s' % outputDir) logger.info('Load template of average voxel value') # Get the file names needed for loading in the data ROI_A_file, ROI_B_file, template_path, noise_dict_file = \ _get_input_names(data_dict) # Load in the template data (it may already be loaded if doing a test) if isinstance(template_path, str): template_nii = nibabel.load(template_path) template = template_nii.get_data() else: template = template_path dimensions = np.array(template.shape[0:3]) logger.info('Create binary mask and normalize the template range') mask, template = sim.mask_brain( volume=template, mask_self=True, ) # Write out the mask as a numpy file outFile = os.path.join(outputDir, 'mask.npy') np.save(outFile, mask.astype(np.uint8)) # Load the noise dictionary logger.info('Loading noise parameters') # If this isn't a string, assume it is a resource stream file if type(noise_dict_file) is str: with open(noise_dict_file, 'r') as f: noise_dict = f.read() else: # Read the resource stream object noise_dict = noise_dict_file.decode() noise_dict = eval(noise_dict) noise_dict['matched'] = 0 # Increases processing time # Add it here for easy access data_dict['noise_dict'] = noise_dict logger.info('Generating noise') temp_stimfunction = np.zeros((data_dict['numTRs'], 1)) noise = sim.generate_noise( dimensions=dimensions, stimfunction_tr=temp_stimfunction, tr_duration=int(data_dict['trDuration']), template=template, mask=mask, noise_dict=noise_dict, ) # Create the stimulus time course of the conditions total_time = int(data_dict['numTRs'] * data_dict['trDuration']) onsets_A = [] onsets_B = [] curr_time = data_dict['burn_in'] while curr_time < (total_time - data_dict['event_duration']): # Flip a coin for each epoch to determine whether it is A or B if np.random.randint(0, 2) == 1: onsets_A.append(curr_time) else: onsets_B.append(curr_time) # Increment the current time curr_time += data_dict['event_duration'] + data_dict['isi'] # How many timepoints per second of the stim function are to be generated? temporal_res = 1 / data_dict['trDuration'] # Create a time course of events event_durations = [data_dict['event_duration']] stimfunc_A = sim.generate_stimfunction( onsets=onsets_A, event_durations=event_durations, total_time=total_time, temporal_resolution=temporal_res, ) stimfunc_B = sim.generate_stimfunction( onsets=onsets_B, event_durations=event_durations, total_time=total_time, temporal_resolution=temporal_res, ) # Create a labels timecourse outFile = os.path.join(outputDir, 'labels.npy') np.save(outFile, (stimfunc_A + (stimfunc_B * 2))) # How is the signal implemented in the different ROIs signal_A = _generate_ROIs(ROI_A_file, stimfunc_A, noise, data_dict['scale_percentage'], data_dict) if data_dict['different_ROIs'] is True: signal_B = _generate_ROIs(ROI_B_file, stimfunc_B, noise, data_dict['scale_percentage'], data_dict) else: # Halve the evoked response if these effects are both expected in the # same ROI if data_dict['multivariate_pattern'] is False: signal_B = _generate_ROIs(ROI_A_file, stimfunc_B, noise, data_dict['scale_percentage'] * 0.5, data_dict) else: signal_B = _generate_ROIs(ROI_A_file, stimfunc_B, noise, data_dict['scale_percentage'], data_dict) # Combine the two signal timecourses signal = signal_A + signal_B logger.info('Generating TRs in real time') for idx in range(data_dict['numTRs']): # Create the brain volume on this TR brain = noise[:, :, :, idx] + signal[:, :, :, idx] # Convert file to integers to mimic what you get from MR brain_int32 = brain.astype(np.int32) # Store as dicom or nifti? if data_dict['save_dicom'] is True: # Save the volume as a DICOM file, with each TR as its own file output_file = os.path.join(outputDir, 'rt_' + format(idx, '03d') + '.dcm') _write_dicom(output_file, brain_int32, idx + 1) else: # Save the volume as a numpy file, with each TR as its own file output_file = os.path.join(outputDir, 'rt_' + format(idx, '03d') + '.npy') np.save(output_file, brain_int32) logger.info("Generate {}".format(output_file)) # Sleep until next TR if data_dict['save_realtime'] == 1: time.sleep(data_dict['trDuration'])
dimensions=dimensions, feature_coordinates=coordinates_B, feature_type=feature_type, feature_size=feature_size, signal_magnitude=signal_magnitude, ) # Visualize the signal that was generated for condition A fig = plt.figure() sim.plot_brain(fig, volume_static_A) plt.show() # Create the time course for the signal to be generated stimfunction_A = sim.generate_stimfunction( onsets=onsets_A, event_durations=event_durations, total_time=duration, temporal_resolution=temporal_res, ) stimfunction_B = sim.generate_stimfunction( onsets=onsets_B, event_durations=event_durations, total_time=duration, temporal_resolution=temporal_res, ) # Convolve the HRF with the stimulus sequence signal_function_A = sim.double_gamma_hrf( stimfunction=stimfunction_A, tr_duration=tr_duration, temporal_resolution=temporal_res,
feature_coordinates=coordinates_B, feature_type=feature_type, feature_size=feature_size, signal_magnitude=signal_magnitude, ) # Visualize the signal that was generated for condition A fig = plt.figure() sim.plot_brain(fig, volume_static_A) plt.show() # Create the time course for the signal to be generated stimfunction_A = sim.generate_stimfunction(onsets=onsets_A, event_durations=event_durations, total_time=duration, ) stimfunction_B = sim.generate_stimfunction(onsets=onsets_B, event_durations=event_durations, total_time=duration, ) # Convolve the HRF with the stimulus sequence signal_function_A = sim.double_gamma_hrf(stimfunction=stimfunction_A, tr_duration=tr_duration, ) signal_function_B = sim.double_gamma_hrf(stimfunction=stimfunction_B, tr_duration=tr_duration, )
print('Node ' + str(node_counter)) # Preset value volume = np.zeros(dimensions[0:3]) # Preset the signal signal_pattern = signal_coords[node_counter, :] onsets_node = onsets[node_counter] # Only do it if there are onsets if len(onsets_node) > 0: # Create the time course for the signal to be generated stimfunc = sim.generate_stimfunction(onsets=onsets_node, event_durations=event_durations, total_time=duration, temporal_resolution=temporal_res, ) # Aggregate the timecourse if len(stimfunc_all) == 0: stimfunc_all = np.zeros((len(stimfunc), vector_size)) for voxel_counter in list(range(0, vector_size)): stimfunc_all[:, voxel_counter] = np.asarray( stimfunc).transpose() * signal_pattern[voxel_counter] else: # Add these elements together temp = np.zeros((len(stimfunc), vector_size)) for voxel_counter in list(range(0, vector_size)): temp[:, voxel_counter] = np.asarray(stimfunc).transpose() * \
def generate_data(inputDir, outputDir, data_dict): # Generate simulated fMRI data with a few parameters that might be # relevant for real time analysis # inputDir - Specify input data dir where the parameters for fmrisim are # outputDir - Specify output data dir where the data should be saved # data_dict contains: # numTRs - Specify the number of time points # multivariate_patterns - Is the difference between conditions # univariate (0) or multivariate (1) # different_ROIs - 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 - How long, in seconds, is each event # scale_percentage - What is the percent signal change # trDuration - How many seconds per volume # save_dicom - Do you want to save data as a dicom (1) or numpy (0) # save_realtime - Do you want to save the data in real time (1) or as # fast as possible (0)? # isi - What is the time between each event (in seconds) # burn_in - How long before the first event (in seconds) # If the folder doesn't exist then make it if os.path.isdir(outputDir) is False: os.makedirs(outputDir, exist_ok=True) print('Load template of average voxel value') templateFile = os.path.join(inputDir, 'sub_template.nii.gz') template_nii = nibabel.load(templateFile) template = template_nii.get_data() dimensions = np.array(template.shape[0:3]) print('Create binary mask and normalize the template range') mask, template = sim.mask_brain( volume=template, mask_self=True, ) # Write out the mask as a numpy file outFile = os.path.join(outputDir, 'mask.npy') np.save(outFile, mask.astype(np.uint8)) # Load the noise dictionary print('Loading noise parameters') noiseFile = os.path.join(inputDir, 'sub_noise_dict.txt') with open(noiseFile, 'r') as f: noise_dict = f.read() noise_dict = eval(noise_dict) noise_dict['matched'] = 0 # Increases processing time # Add it here for easy access data_dict['noise_dict'] = data_dict print('Generating noise') temp_stimfunction = np.zeros((data_dict['numTRs'], 1)) noise = sim.generate_noise( dimensions=dimensions, stimfunction_tr=temp_stimfunction, tr_duration=int(data_dict['trDuration']), template=template, mask=mask, noise_dict=noise_dict, ) # Create the stimulus time course of the conditions total_time = int(data_dict['numTRs'] * data_dict['trDuration']) onsets_A = [] onsets_B = [] curr_time = data_dict['burn_in'] while curr_time < (total_time - data_dict['event_duration']): # Flip a coin for each epoch to determine whether it is A or B if np.random.randint(0, 2) == 1: onsets_A.append(curr_time) else: onsets_B.append(curr_time) # Increment the current time curr_time += data_dict['event_duration'] + data_dict['isi'] # How many timepoints per second of the stim function are to be generated? temporal_res = 1 / data_dict['trDuration'] # Create a time course of events event_durations = [data_dict['event_duration']] stimfunc_A = sim.generate_stimfunction( onsets=onsets_A, event_durations=event_durations, total_time=total_time, temporal_resolution=temporal_res, ) stimfunc_B = sim.generate_stimfunction( onsets=onsets_B, event_durations=event_durations, total_time=total_time, temporal_resolution=temporal_res, ) # Create a labels timecourse outFile = os.path.join(outputDir, 'labels.npy') np.save(outFile, (stimfunc_A + (stimfunc_B * 2))) roiA_file = os.path.join(inputDir, 'ROI_A.nii.gz') roiB_file = os.path.join(inputDir, 'ROI_B.nii.gz') # How is the signal implemented in the different ROIs signal_A = generate_ROIs(roiA_file, stimfunc_A, noise, data_dict['scale_percentage'], data_dict) if data_dict['different_ROIs'] is True: signal_B = generate_ROIs(roiB_file, stimfunc_B, noise, data_dict['scale_percentage'], data_dict) else: # Halve the evoked response if these effects are both expected in the same ROI if data_dict['multivariate_pattern'] is False: signal_B = generate_ROIs(roiA_file, stimfunc_B, noise, data_dict['scale_percentage'] * 0.5, data_dict) else: signal_B = generate_ROIs(roiA_file, stimfunc_B, noise, data_dict['scale_percentage'], data_dict) # Combine the two signal timecourses signal = signal_A + signal_B print('Generating TRs in real time') for idx in range(data_dict['numTRs']): # Create the brain volume on this TR brain = noise[:, :, :, idx] + signal[:, :, :, idx] # Convert file to integers to mimic what you get from MR brain_int32 = brain.astype(np.int32) # Store as dicom or nifti? if data_dict['save_dicom'] is True: # Save the volume as a DICOM file, with each TR as its own file output_file = os.path.join(outputDir, 'rt_' + format(idx, '03d') + '.dcm') write_dicom(output_file, brain_int32, idx + 1) else: # Save the volume as a numpy file, with each TR as its own file output_file = os.path.join(outputDir, 'rt_' + format(idx, '03d') + '.npy') np.save(output_file, brain_int32) print("Generate {}".format(output_file)) # Sleep until next TR if data_dict['save_realtime'] == 1: time.sleep(data_dict['trDuration'])
def toy_simulation(community_density=1, added_isi=0, rand=0, signal_magnitude=1, noise_type='coordinates', noise_parameter=0, restrict_overall_duration=0, ): # Default these values nodes = 15 runs = 5 vector_size = 2 # How many voxels did you make all_pos = 1 ppt = '1' # What participant would you like to simulate tr_duration = 2 event_durations = [1] hrf_lag = 2 temporal_res = 100 # How many samples per second are there for timing files # Select what the noise is applied to noise_coordinates = 0 # How much noise are you adding to the coordinates noise_timecourse = 0 # How many random noise are you adding to the timecourse if noise_type == 'coordinates': noise_coordinates = noise_parameter elif noise_type == 'timecourse': noise_timecourse = noise_parameter # Load the timing information timing_path = '../../community_structure/simulator_parameters/timing/' #timing_path = '/Volumes/pniintel/ntb/TDA/Validation/code/community_structure/simulator_parameters/timing/' onsets_runs = np.load(timing_path + 'sub-' + ppt + '.npy') # Generate the graph structure (based on the ratio) signal_coords = community_structure(1 - community_density, ) # Add noise to these coordinates noise = np.random.randn(np.prod(signal_coords.shape)).reshape( signal_coords.shape) * noise_coordinates signal_coords += noise # Perform an orthonormal transformation of the data if vector_size > signal_coords.shape[1]: signal_coords = orthonormal_transform(vector_size, signal_coords, ) # Do you want these coordinates to be all positive? This means that # these coordinates are represented as different magnitudes of # activation if all_pos == 1: mins = np.abs(np.min(signal_coords, 0)) for voxel_counter in list(range(0, len(mins))): signal_coords[:, voxel_counter] += mins[voxel_counter] # Bound the value to have a max of 1 so that the signal magnitude is more interpretable signal_coords /= np.max(signal_coords) # Determine the size of the signal signal_coords *= signal_magnitude # Cycle through the runs and generate the data node_brain = np.zeros([vector_size, nodes, runs], dtype='double') # Preset for run_counter in list(range(1, runs + 1)): # Pull out the onsets for this participant (reload it each time to deal with copying issues) onsets_runs = np.load(timing_path + 'sub-' + ppt + '.npy') onsets_run = onsets_runs[run_counter - 1] # What is the original max duration of the onsets max_duration_orig = np.max([np.max(onsets_run[x]) for x in range(onsets_run.size)]) max_duration_orig += 10 # Add some wiggle room # Do you want to randomise the onsets (so that the events do not have a # fixed order) if rand == 1: onsets_run = randomise_timing(onsets_runs[run_counter - 1], ) # If you want to use different timing then take the order of the data # and then create a new timecourse onsets_run = extra_isi(onsets_run, added_isi, ) # If necessary, remove all the values greater than the max if restrict_overall_duration == 1: onsets_run = [onsets_run[x][onsets_run[x] < max_duration_orig] for x in range( onsets_run.size)] onsets_run = np.asarray(onsets_run) # Determine how long the simulated time course is by finding the max of maxs last_event = 0 for node_counter in range(len(onsets_run)): if len(onsets_run[node_counter]) > 0 and onsets_run[node_counter].max() > last_event: last_event = onsets_run[node_counter].max() # How long should you model duration = int(last_event + 10) # Add a decay buffer # Preset brain size brain_signal = np.zeros([2, int(duration / tr_duration)], dtype='double') stimfunc_all = [] for node_counter in list(range(0, nodes)): # Preset the signal signal_pattern = np.ones(vector_size) # Take the coordinates from the signal template for coord_counter in list(range(0, signal_coords.shape[1])): signal_pattern[coord_counter] = signal_coords[node_counter, coord_counter] onsets_node = onsets_run[node_counter] # Only do it if there are onsets if len(onsets_node) > 0: # Create the time course for the signal to be generated stimfunc = sim.generate_stimfunction(onsets=onsets_node, event_durations=event_durations, total_time=duration, temporal_resolution=temporal_res, ) # Aggregate the timecourse if len(stimfunc_all) == 0: stimfunc_all = np.zeros((len(stimfunc), vector_size)) for voxel_counter in list(range(0, vector_size)): stimfunc_all[:, voxel_counter] = np.asarray( stimfunc).transpose() * signal_coords[node_counter, voxel_counter] else: # Add these elements together temp = np.zeros((len(stimfunc), vector_size)) for voxel_counter in list(range(0, vector_size)): temp[:, voxel_counter] = np.asarray(stimfunc).transpose() * \ signal_coords[node_counter, voxel_counter] stimfunc_all += temp # After you have gone through all the nodes, convolve the HRF and # stimulation for each voxel signal_func = sim.convolve_hrf(stimfunction=stimfunc_all, tr_duration=tr_duration, temporal_resolution=temporal_res, ) # Multiply the convolved responses with their magnitudes (after being # scaled) for voxel_counter in list(range(0, vector_size)): # Reset the range of the function to be appropriate for the # stimfunc signal_func[:, voxel_counter] *= stimfunc_all[:, voxel_counter].max() # Create the noise noise = np.random.randn(np.prod(signal_func.shape)).reshape( signal_func.shape) * noise_timecourse # Combine the signal and the noise brain = signal_func + noise # Z score the data #brain = zscore(brain.astype('float'), 0) # Loop through the nodes for node in list(range(0, nodes)): node_trs = onsets_run[node] if len(node_trs) > 0: temp = np.zeros((vector_size, len(node_trs) - 1)) for tr_counter in list(range(1, len(node_trs))): # When does it onset (first TR is zero so minus 1) onset = int(np.round(node_trs[tr_counter] / tr_duration) + hrf_lag) # Add the TR if it is included when considering the hrf lag if onset < brain.shape[0]: temp[:, tr_counter - 1] = brain[onset, :] # Average the TRs node_brain[:, node, run_counter - 1] = np.mean(temp, 1) # average the brains across runs node_brain = np.mean(node_brain, 2) return node_brain
# Iterate through the conditions to make the necessary functions for cond in list(range(conds)): # Generate a volume representing the location and quality of the signal volume_static = sim.generate_signal(dimensions=dimensions, feature_coordinates=coordinates[cond], feature_type=feature_type, feature_size=feature_size, signal_magnitude=signal_magnitude, ) # Create the time course for the signal to be generated stimfunction_cond = sim.generate_stimfunction(onsets=onsets[cond], event_durations= event_durations, total_time=duration, weights=weights[cond], ) # Convolve the HRF with the stimulus sequence signal_function = sim.double_gamma_hrf(stimfunction=stimfunction_cond, tr_duration=tr_duration, ) # Multiply the HRF timecourse with the signal signal_cond = sim.apply_signal(signal_function=signal_function, volume_static=volume_static, ) # Concatenate all the signal and function files if cond == 0:
def test_generate_stimfunction(): # 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, ) assert stimfunction.shape[0] == duration * 100, "stimfunc incorrect length" eventNumber = np.sum(event_durations * len(onsets)) * 100 assert np.sum(stimfunction) == eventNumber, "Event number" # Create the signal function signal_function = sim.convolve_hrf( stimfunction=stimfunction, tr_duration=tr_duration, ) stim_dur = stimfunction.shape[0] / (tr_duration * 100) assert signal_function.shape[0] == stim_dur, "The length did not change" # Test onsets = [0] tr_duration = 1 event_durations = [1] stimfunction = sim.generate_stimfunction( onsets=onsets, event_durations=event_durations, total_time=duration, ) signal_function = sim.convolve_hrf( stimfunction=stimfunction, tr_duration=tr_duration, ) max_response = np.where(signal_function != 0)[0].max() assert 25 < max_response <= 30, "HRF has the incorrect length" assert np.sum(signal_function < 0) > 0, "No values below zero" # Export a stimfunction sim.export_3_column( stimfunction, 'temp.txt', ) # Load in the stimfunction stimfunc_new = sim.generate_stimfunction( onsets=None, event_durations=None, total_time=duration, timing_file='temp.txt', ) assert np.all(stimfunc_new == stimfunction), "Export/import failed" # Break the timing precision of the generation stimfunc_new = sim.generate_stimfunction( onsets=None, event_durations=None, total_time=duration, timing_file='temp.txt', temporal_resolution=0.5, ) assert stimfunc_new.sum() == 0, "Temporal resolution not working right" # Set the duration to be too short so you should get an error onsets = [10, 30, 50, 70, 90] event_durations = [5] with pytest.raises(ValueError): sim.generate_stimfunction( onsets=onsets, event_durations=event_durations, total_time=89, ) # Clip the event offset stimfunc_new = sim.generate_stimfunction( onsets=onsets, event_durations=event_durations, total_time=95, ) assert stimfunc_new[-1] == 1, 'Event offset was not clipped' # Test exporting a group of participants to an epoch file cond_a = sim.generate_stimfunction( onsets=onsets, event_durations=event_durations, total_time=110, ) cond_b = sim.generate_stimfunction( onsets=[x + 5 for x in onsets], event_durations=event_durations, total_time=110, ) stimfunction_group = [np.hstack((cond_a, cond_b))] * 2 sim.export_epoch_file( stimfunction_group, 'temp.txt', tr_duration, ) # Check that convolve throws a warning when the shape is wrong sim.convolve_hrf( stimfunction=np.hstack((cond_a, cond_b)).T, tr_duration=tr_duration, temporal_resolution=1, )
def test_generate_noise(): 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 = [1] # 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 = 200 # 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, ) # Convolve the HRF with the stimulus sequence signal = sim.apply_signal(signal_function=signal_function, volume_signal=volume, ) # Generate the mask of the signal mask, template = sim.mask_brain(signal, mask_threshold=0.1) assert min(mask[mask > 0]) > 0.1, "Mask thresholding did not work" assert len(np.unique(template) > 2), "Template creation did not work" stimfunction_tr = stimfunction[::int(tr_duration * 100)] # Create the noise volumes (using the default parameters) noise = sim.generate_noise(dimensions=dimensions, stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, template=template, mask=mask, ) assert signal.shape == noise.shape, "The dimensions of signal and noise " \ "the same" assert np.std(signal) < np.std(noise), "Noise was not created" noise = sim.generate_noise(dimensions=dimensions, stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, template=template, mask=mask, noise_dict={'sfnr': 10000, 'snr': 10000}, ) system_noise = np.std(noise[mask > 0], 1).mean() assert system_noise <= 0.1, "Noise strength could not be manipulated"
dimensions=dimensions, feature_coordinates=coordinates_B, feature_type=feature_type, feature_size=feature_size, signal_magnitude=signal_magnitude, ) # Visualize the signal that was generated for condition A fig = plt.figure() sim.plot_brain(fig, volume_static_A) plt.show() # Create the time course for the signal to be generated stimfunction_A = sim.generate_stimfunction( onsets=onsets_A, event_durations=event_durations, total_time=duration, ) stimfunction_B = sim.generate_stimfunction( onsets=onsets_B, event_durations=event_durations, total_time=duration, ) # Convolve the HRF with the stimulus sequence signal_function_A = sim.double_gamma_hrf( stimfunction=stimfunction_A, tr_duration=tr_duration, )
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, )
dimensions=dimensions, feature_coordinates=feature_coordinates_B, feature_type=feature_type, feature_size=feature_size, signal_magnitude=signal_magnitude, ) # Visualize the signal that was generated for condition A fig = plt.figure() sim.plot_brain(fig, volume_static_A) plt.show() # Create the time course for the signal to be generated stimfunction_A = sim.generate_stimfunction( onsets=onsets_A, event_durations=event_durations, total_time=duration, tr_duration=tr_duration, ) stimfunction_B = sim.generate_stimfunction( onsets=onsets_B, event_durations=event_durations, total_time=duration, tr_duration=tr_duration, ) # Convolve the HRF with the stimulus sequence signal_function_A = sim.double_gamma_hrf(stimfunction=stimfunction_A, ) signal_function_B = sim.double_gamma_hrf(stimfunction=stimfunction_B, )
feature_coordinates=coordinates_B, feature_type=feature_type, feature_size=feature_size, signal_magnitude=signal_magnitude, ) # Visualize the signal that was generated for condition A fig = plt.figure() sim.plot_brain(fig, volume_signal_A) plt.show() # Create the time course for the signal to be generated stimfunction_A = sim.generate_stimfunction(onsets=onsets_A, event_durations=event_durations, total_time=duration, temporal_resolution=temporal_res, ) stimfunction_B = sim.generate_stimfunction(onsets=onsets_B, event_durations=event_durations, total_time=duration, temporal_resolution=temporal_res, ) # Convolve the HRF with the stimulus sequence signal_function_A = sim.convolve_hrf(stimfunction=stimfunction_A, tr_duration=tr_duration, temporal_resolution=temporal_res, )
def test_generate_noise(): 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 = [1] # 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 = 200 # 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, ) # Convolve the HRF with the stimulus sequence signal = sim.apply_signal( signal_function=signal_function, volume_signal=volume, ) # Generate the mask of the signal mask, template = sim.mask_brain(signal, mask_self=None) assert min(mask[mask > 0]) > 0.1, "Mask thresholding did not work" assert len(np.unique(template) > 2), "Template creation did not work" stimfunction_tr = stimfunction[::int(tr_duration * 100)] # Create the noise volumes (using the default parameters) noise = sim.generate_noise( dimensions=dimensions, stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, template=template, mask=mask, iterations=[1, 0], ) assert signal.shape == noise.shape, "The dimensions of signal and noise " \ "the same" noise_high = sim.generate_noise( dimensions=dimensions, stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, template=template, mask=mask, noise_dict={ 'sfnr': 50, 'snr': 25 }, iterations=[1, 0], ) noise_low = sim.generate_noise( dimensions=dimensions, stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, template=template, mask=mask, noise_dict={ 'sfnr': 100, 'snr': 25 }, iterations=[1, 0], ) system_high = np.std(noise_high[mask > 0], 1).mean() system_low = np.std(noise_low[mask > 0], 1).mean() assert system_low < system_high, "SFNR noise could not be manipulated" # Check that you check for the appropriate template values with pytest.raises(ValueError): sim.generate_noise( dimensions=dimensions, stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, template=template * 2, mask=mask, noise_dict={}, ) # Check that iterations does what it should sim.generate_noise( dimensions=dimensions, stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, template=template, mask=mask, noise_dict={}, iterations=[0, 0], ) sim.generate_noise( dimensions=dimensions, stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, template=template, mask=mask, noise_dict={}, iterations=None, ) # Test drift noise trs = 1000 period = 100 drift = sim._generate_noise_temporal_drift( trs, tr_duration, 'sine', period, ) # Check that the max frequency is the appropriate frequency power = abs(np.fft.fft(drift))[1:trs // 2] freq = np.linspace(1, trs // 2 - 1, trs // 2 - 1) / trs period_freq = np.where(freq == 1 / (period // tr_duration)) max_freq = np.argmax(power) assert period_freq == max_freq, 'Max frequency is not where it should be' # Do the same but now with cosine basis functions, answer should be close drift = sim._generate_noise_temporal_drift( trs, tr_duration, 'discrete_cos', period, ) # Check that the appropriate frequency is peaky (may not be the max) power = abs(np.fft.fft(drift))[1:trs // 2] freq = np.linspace(1, trs // 2 - 1, trs // 2 - 1) / trs period_freq = np.where(freq == 1 / (period // tr_duration))[0][0] assert power[period_freq] > power[period_freq + 1], 'Power is low' assert power[period_freq] > power[period_freq - 1], 'Power is low' # Check it runs fine drift = sim._generate_noise_temporal_drift( 50, tr_duration, 'discrete_cos', period, ) # Check it runs fine drift = sim._generate_noise_temporal_drift( 300, tr_duration, 'cos_power_drop', period, ) # Check that when the TR is greater than the period it errors with pytest.raises(ValueError): sim._generate_noise_temporal_drift(30, 10, 'cos_power_drop', 5) # Test physiological noise (using unrealistic parameters so that it's easy) timepoints = list(np.linspace(0, (trs - 1) * tr_duration, trs)) resp_freq = 0.2 heart_freq = 1.17 phys = sim._generate_noise_temporal_phys( timepoints, resp_freq, heart_freq, ) # Check that the max frequency is the appropriate frequency power = abs(np.fft.fft(phys))[1:trs // 2] freq = np.linspace(1, trs // 2 - 1, trs // 2 - 1) / (trs * tr_duration) peaks = (power > (power.mean() + power.std())) # Where are the peaks peak_freqs = freq[peaks] assert np.any(resp_freq == peak_freqs), 'Resp frequency not found' assert len(peak_freqs) == 2, 'Two peaks not found' # Test task noise sim._generate_noise_temporal_task( stimfunction_tr, motion_noise='gaussian', ) sim._generate_noise_temporal_task( stimfunction_tr, motion_noise='rician', ) # Test ARMA noise with pytest.raises(ValueError): noise_dict = {'fwhm': 4, 'auto_reg_rho': [1], 'ma_rho': [1, 1]} sim._generate_noise_temporal_autoregression( stimfunction_tr, noise_dict, dimensions, mask, ) # Generate spatial noise vol = sim._generate_noise_spatial(np.array([10, 10, 10, trs])) assert len(vol.shape) == 3, 'Volume was not reshaped to ignore TRs' # Switch some of the noise types on noise_dict = dict(physiological_sigma=1, drift_sigma=1, task_sigma=1, auto_reg_sigma=0) sim.generate_noise( dimensions=dimensions, stimfunction_tr=stimfunction_tr, tr_duration=tr_duration, template=template, mask=mask, noise_dict=noise_dict, iterations=[0, 0], )
def test_generate_noise(): dimensions = np.array([64, 64, 36]) # What is the size of the brain feature_size = [2] feature_type = ['cube'] feature_coordinates = np.array([[32, 32, 18]]) signal_magnitude = [30] # Generate a volume representing the location and quality of the signal volume_static = 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, tr_duration=tr_duration, ) signal_function = sim.double_gamma_hrf(stimfunction=stimfunction, ) # Convolve the HRF with the stimulus sequence signal = sim.apply_signal( signal_function=signal_function, volume_static=volume_static, ) # Create the noise volumes (using the default parameters) noise = sim.generate_noise( dimensions=dimensions, stimfunction=stimfunction, tr_duration=tr_duration, ) assert signal.shape == noise.shape, "The dimensions of signal " \ "and noise the same" Z_noise = sim._generate_noise_temporal(stimfunction, tr_duration, 1) noise = sim._generate_noise_temporal(stimfunction, tr_duration, 0) assert np.std(Z_noise) < np.std(noise), "Z scoring is not working" # Combine the signal and the noise volume = signal + noise assert np.std(signal) < np.std(noise), "Noise was not created" noise = sim.generate_noise(dimensions=dimensions, stimfunction=stimfunction, tr_duration=tr_duration, noise_strength=[0, 0, 0]) assert np.sum(noise) == 0, "Noise strength could not be manipulated" assert np.std(noise) == 0, "Noise strength could not be manipulated"
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"