<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def _fit_temporal(noise, mask, template, stimfunction_tr, tr_duration, spatial_sd, temporal_proportion, temporal_sd, noise_dict, fit_thresh, fit_delta, iterations, ):
 """ Fit the noise model to match the SFNR and AR of the data Parameters noise : multidimensional array, float Initial estimate of the noise mask : 3d array, binary The mask of the brain volume, distinguishing brain from non-brain 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. 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? spatial_sd : float What is the standard deviation in space of the noise volume to be generated 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. temporal_sd : float What is the standard deviation in time of the noise volume to be generated noise_dict : dict A dictionary specifying the types of noise in this experiment. The noise types interact in important ways. First, all noise types ending with sigma (e.g. motion sigma) are mixed together in _generate_temporal_noise. These values describe the proportion of mixing of these elements. However critically, SFNR is the parameter that describes how much noise these components contribute to the brain. If you set the noise dict to matched then it will fit the parameters to match the participant as best as possible. 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 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. Returns ------- noise : multidimensional array, float Generates the noise volume given these parameters """


    # Pull out the
    dim_tr = noise.shape
    dim = dim_tr[0:3]
    base = template * noise_dict['max_activity']
    base = base.reshape(dim[0], dim[1], dim[2], 1)
    mean_signal = (base[mask > 0]).mean()

    # Iterate through different parameters to fit SNR and SFNR
    temp_sd_orig = np.copy(temporal_sd)

    # Make a copy of the dictionary so it can be modified
    new_nd = copy.deepcopy(noise_dict)

    # What SFNR do you want
    target_sfnr = noise_dict['sfnr']

    # What AR do you want?
    target_ar = noise_dict['auto_reg_rho'][0]

    # Iterate through different MA parameters to fit AR
    for iteration in list(range(iterations)):

        # If there are iterations left to perform then recalculate the
        # metrics and try again

        # Calculate the new SFNR
        new_sfnr = _calc_sfnr(noise, mask)

        # Calculate the AR
        new_ar, _ = _calc_ARMA_noise(noise,
                                     mask,
                                     len(noise_dict['auto_reg_rho']),
                                     len(noise_dict['ma_rho']),
                                     )

        # Calculate the difference between the real and simulated data
        sfnr_diff = abs(new_sfnr - target_sfnr) / target_sfnr

        # Calculate the difference in the first AR component
        ar_diff = new_ar[0] - target_ar

        # If the SFNR and AR is sufficiently close then break the loop
        if (abs(ar_diff) / target_ar) < fit_thresh and sfnr_diff < fit_thresh:
            msg = 'Terminated AR fit after ' + str(iteration) + ' iterations.'
            logger.info(msg)
            break

        # Otherwise update the noise metrics. Get the new temporal noise value
        temp_sd_new = mean_signal / new_sfnr
        temporal_sd -= ((temp_sd_new - temp_sd_orig) * fit_delta)

        # Prevent these going out of range
        if temporal_sd < 0 or np.isnan(temporal_sd):
            temporal_sd = 10e-3

        # Set the new system noise
        temp_sd_system_new = np.sqrt((temporal_sd ** 2) * temporal_proportion)

        # Get the new AR value
        new_nd['auto_reg_rho'][0] -= (ar_diff * fit_delta)

        # Don't let the AR coefficient exceed 1
        if new_nd['auto_reg_rho'][0] >= 1:
            new_nd['auto_reg_rho'][0] = 0.99

        # Generate the noise. The appropriate
        noise_temporal = _generate_noise_temporal(stimfunction_tr,
                                                  tr_duration,
                                                  dim,
                                                  template,
                                                  mask,
                                                  new_nd,
                                                  )

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

        # 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

    # Failed to converge
    if iterations == 0:
        logger.info('No fitting iterations were run')
    elif iteration == iterations:
        logger.warning('AR failed to converge.')

    # Return the updated noise
    return noise