def generate_noise(dimensions,
                   stimfunction_tr,
                   tr_duration,
                   template,
                   mask=None,
                   noise_dict=None,
                   temporal_proportion=0.5,
                   iterations=None,
                   fit_thresh=0.05,
                   fit_delta=0.5,
                   ):
    """ Generate the noise to be added to the signal.
    Default noise parameters will create a noise volume with a standard
    deviation of 0.1 (where the signal defaults to a value of 1). This has
    built into estimates of how different types of noise mix. All noise
    values can be set by the user or estimated with calc_noise.

    Parameters
    ----------

    dimensions : nd array
        What is the shape of the volume to be generated

    stimfunction_tr :  Iterable, list
        When do the stimuli events occur. Each element is a TR

    tr_duration : float
        What is the duration, in seconds, of each TR?

    template : 3d array, float
        A continuous (0 -> 1) volume describing the likelihood a voxel is in
        the brain. This can be used to contrast the brain and non brain.

    mask : 3d array, binary
        The mask of the brain volume, distinguishing brain from non-brain

    noise_dict : dictionary, float
        This is a dictionary which describes the noise parameters of the
        data. If there are no other variables provided then it will use
        default values. The noise variables are as follows:

        snr [float]: Ratio of MR signal to the spatial noise
        sfnr [float]: Ratio of the MR signal to the temporal noise. This is the
        total variability that the following sigmas 'sum' to:

        task_sigma [float]: Size of the variance of task specific noise
        drift_sigma [float]: Size of the variance of drift noise
        auto_reg_sigma [float]: Size of the variance of autoregressive
        noise. This is an ARMA process where the AR and MA components can be
        separately specified
        physiological_sigma [float]: Size of the variance of physiological
        noise

        auto_reg_rho [list]: The coefficients of the autoregressive
        components you are modeling
        ma_rho [list]:The coefficients of the moving average components you
        are modeling
        max_activity [float]: The max value of the averaged brain in order
        to reference the template
        voxel_size [list]: The mm size of the voxels
        fwhm [float]: The gaussian smoothing kernel size (mm)
        matched [bool]: Specify whether you are fitting the noise parameters

        The volumes of brain noise that are generated have smoothness
        specified by 'fwhm'

    temporal_proportion, float
        What is the proportion of the temporal variance (as specified by the
        SFNR noise parameter) that is accounted for by the system noise. If
        this number is high then all of the temporal variability is due to
        system noise, if it is low then all of the temporal variability is
        due to brain variability.

    iterations : list, int
        The first element is how many steps of fitting the SFNR and SNR values
        will be performed. Usually converges after < 5. The second element
        is the number of iterations for the AR fitting. This is much more
        time consuming (has to make a new timecourse on each iteration) so
        be careful about setting this appropriately.

    fit_thresh : float
        What proportion of the target parameter value is sufficient error to
        warrant finishing fit search.

    fit_delta : float
        How much are the parameters attenuated during the fitting process,
        in terms of the proportion of difference between the target
        parameter and the actual parameter


    Returns
    ----------

    noise : multidimensional array, float
        Generates the noise volume for these parameters

    """

    # Check the input data
    if template.max() > 1.1:
        raise ValueError('Template out of range')

    # Change to be an empty dictionary if it is None
    if noise_dict is None:
        noise_dict = {}

    # Take in the noise dictionary and add any missing information
    noise_dict = _noise_dict_update(noise_dict)

    # How many iterations will you perform? If unspecified it will set
    # values based on whether you are trying to match noise specifically to
    # this participant or just get in the ball park
    if iterations is None:
        if noise_dict['matched'] == 1:
            iterations = [20, 20]
        else:
            iterations = [0, 0]

    if abs(noise_dict['auto_reg_rho'][0]) - abs(noise_dict['ma_rho'][0]) < 0.1:
        logger.warning('ARMA coefs are close, may have trouble fitting')

    # What are the dimensions of the volume, including time
    dimensions_tr = (dimensions[0],
                     dimensions[1],
                     dimensions[2],
                     len(stimfunction_tr))

    # Get the mask of the brain and set it to be 3d
    if mask is None:
        mask = np.ones(dimensions)

    # Create the base (this inverts the process to make the template)
    base = template * noise_dict['max_activity']

    # Reshape the base (to be the same size as the volume to be created)
    base = base.reshape(dimensions[0], dimensions[1], dimensions[2], 1)
    base = np.ones(dimensions_tr) * base

    # What is the mean signal of the non masked voxels in this template?
    mean_signal = (base[mask > 0]).mean()

    # Generate the noise
    noise_temporal = _generate_noise_temporal(stimfunction_tr=stimfunction_tr,
                                              tr_duration=tr_duration,
                                              dimensions=dimensions,
                                              template=template,
                                              mask=mask,
                                              noise_dict=noise_dict,
                                              )

    # Convert SFNR into the size of the standard deviation of temporal
    # variability
    temporal_sd = (mean_signal / noise_dict['sfnr'])

    # Calculate the temporal sd of the system noise (as opposed to the noise
    #  attributed to the functional variability).
    temporal_sd_system = np.sqrt((temporal_sd ** 2) * temporal_proportion)

    # What is the standard deviation of the background activity
    spat_sd = mean_signal / noise_dict['snr']
    spatial_sd = np.sqrt((spat_sd ** 2) * (1 - temporal_proportion))

    # Set up the machine noise
    noise_system = _generate_noise_system(dimensions_tr=dimensions_tr,
                                          spatial_sd=spatial_sd,
                                          temporal_sd=temporal_sd_system,
                                          )

    # Sum up the noise of the brain
    noise = base + (noise_temporal * temporal_sd) + noise_system

    # Reject negative values (only happens outside of the brain)
    noise[noise < 0] = 0

    # Fit the SNR
    noise, spatial_sd = _fit_spatial(noise,
                                     noise_temporal,
                                     mask,
                                     template,
                                     spatial_sd,
                                     temporal_sd_system,
                                     noise_dict,
                                     fit_thresh,
                                     fit_delta,
                                     iterations[0],
                                     )

    # Fit the SFNR and AR noise
    noise = _fit_temporal(noise,
                          mask,
                          template,
                          stimfunction_tr,
                          tr_duration,
                          spatial_sd,
                          temporal_proportion,
                          temporal_sd,
                          noise_dict,
                          fit_thresh,
                          fit_delta,
                          iterations[1],
                          )

    # Return the noise
    return noise
Generate the noise to be added to the signal.
    Default noise parameters will create a noise volume with a standard
    deviation of 0.1 (where the signal defaults to a value of 1). This has
    built into estimates of how different types of noise mix. All noise
    values can be set by the user or estimated with calc_noise.

    Parameters
    ----------

    dimensions : nd array
        What is the shape of the volume to be generated

    stimfunction_tr :  Iterable, list
        When do the stimuli events occur. Each element is a TR

    tr_duration : float
        What is the duration, in seconds, of each TR?

    template : 3d array, float
        A continuous (0 -> 1) volume describing the likelihood a voxel is in
        the brain. This can be used to contrast the brain and non brain.

    mask : 3d array, binary
        The mask of the brain volume, distinguishing brain from non-brain

    noise_dict : dictionary, float
        This is a dictionary which describes the noise parameters of the
        data. If there are no other variables provided then it will use
        default values. The noise variables are as follows:

        snr [float]: Ratio of MR signal to the spatial noise
        sfnr [float]: Ratio of the MR signal to the temporal noise. This is the
        total variability that the following sigmas 'sum' to:

        task_sigma [float]: Size of the variance of task specific noise
        drift_sigma [float]: Size of the variance of drift noise
        auto_reg_sigma [float]: Size of the variance of autoregressive
        noise. This is an ARMA process where the AR and MA components can be
        separately specified
        physiological_sigma [float]: Size of the variance of physiological
        noise

        auto_reg_rho [list]: The coefficients of the autoregressive
        components you are modeling
        ma_rho [list]:The coefficients of the moving average components you
        are modeling
        max_activity [float]: The max value of the averaged brain in order
        to reference the template
        voxel_size [list]: The mm size of the voxels
        fwhm [float]: The gaussian smoothing kernel size (mm)
        matched [bool]: Specify whether you are fitting the noise parameters

        The volumes of brain noise that are generated have smoothness
        specified by 'fwhm'

    temporal_proportion, float
        What is the proportion of the temporal variance (as specified by the
        SFNR noise parameter) that is accounted for by the system noise. If
        this number is high then all of the temporal variability is due to
        system noise, if it is low then all of the temporal variability is
        due to brain variability.

    iterations : list, int
        The first element is how many steps of fitting the SFNR and SNR values
        will be performed. Usually converges after < 5. The second element
        is the number of iterations for the AR fitting. This is much more
        time consuming (has to make a new timecourse on each iteration) so
        be careful about setting this appropriately.

    fit_thresh : float
        What proportion of the target parameter value is sufficient error to
        warrant finishing fit search.

    fit_delta : float
        How much are the parameters attenuated during the fitting process,
        in terms of the proportion of difference between the target
        parameter and the actual parameter


    Returns
    ----------

    noise : multidimensional array, float
        Generates the noise volume for these parameters