Example #1
0
def fit_gaussian(spectra, f_ppm, lb=2.6, ub=3.6):
    """
   Fit a gaussian function to the difference spectra to be used for estimation
   of the GABA peak.
   
   Parameters
   ----------
   spectra : array of shape (n_transients, n_points)
      Typically the difference of the on/off spectra in each transient.

   f_ppm : array

   lb, ub : floats
      In ppm, the range over which optimization is bounded
   
   """
    idx = ut.make_idx(f_ppm, lb, ub)
    # We are only going to look at the interval between lb and ub
    n_points = idx.stop - idx.start
    n_params = 5
    fit_func = ut.gaussian
    # Set the bounds for the optimization
    bounds = [
        (lb, ub),  # peak location
        (0, None),  # sigma
        (0, None),  # amp
        (None, None),  # offset
        (None, None)  # drift
    ]

    model = np.empty((spectra.shape[0], n_points))
    signal = np.empty((spectra.shape[0], n_points))
    params = np.empty((spectra.shape[0], n_params))
    for ii, xx in enumerate(spectra):
        # We fit to the real spectrum:
        signal[ii] = np.real(xx[idx])
        # Use the signal for a rough estimate of the parameters for
        # initialization :
        max_idx = np.argmax(signal[ii])
        max_sig = np.max(signal[ii])
        initial_f0 = f_ppm[idx][max_idx]
        half_max_idx = np.argmin(np.abs(signal[ii] - max_sig / 2))
        # We estimate sigma as the hwhm:
        initial_sigma = np.abs(initial_f0 - f_ppm[idx][half_max_idx])
        initial_off = np.min(signal[ii])
        initial_drift = 0
        initial_amp = max_sig

        initial = (initial_f0, initial_sigma, initial_amp, initial_off,
                   initial_drift)

        params[ii], _ = lsq.leastsqbound(mopt.err_func,
                                         initial,
                                         args=(f_ppm[idx], np.real(signal[ii]),
                                               fit_func),
                                         bounds=bounds)

        model[ii] = fit_func(f_ppm[idx], *params[ii])

    return model, signal, params
Example #2
0
    def fit_water(self,
                  line_broadening=5,
                  zerofill=100,
                  filt_method=None,
                  min_ppm=-5.0,
                  max_ppm=5.0):
        """

        """
        # Get the water spectrum as well:
        f_hz, w_spectra = ana.get_spectra(self.water_fid,
                                          line_broadening=line_broadening,
                                          zerofill=zerofill,
                                          filt_method=filt_method)

        f_ppm = ut.freq_to_ppm(f_hz)
        # Averaging across echos:
        self.water_spectra = np.mean(w_spectra, 1)
        model, signal, params = ana.fit_lorentzian(self.water_spectra,
                                                   self.f_ppm,
                                                   lb=min_ppm,
                                                   ub=max_ppm)

        # Store the params:
        self.water_model = model
        self.water_signal = signal
        self.water_params = params
        self.water_idx = ut.make_idx(self.f_ppm, min_ppm, max_ppm)
        mean_params = stats.nanmean(params, 0)
        self.water_auc = self._calc_auc(ut.lorentzian, params, self.water_idx)
Example #3
0
    def fit_water(self, line_broadening=5, zerofill=100,
                 filt_method=None, min_ppm=-5.0, max_ppm=5.0):
        """

        """
        # Get the water spectrum as well:
        f_hz, w_spectra = ana.get_spectra(self.water_fid,
                                          line_broadening=line_broadening,
                                          zerofill=zerofill,
                                          filt_method=filt_method)

        f_ppm = ut.freq_to_ppm(f_hz)
        # Averaging across echos:
        self.water_spectra = np.mean(w_spectra, 1)
        model, signal, params = ana.fit_lorentzian(self.water_spectra,
                                                   self.f_ppm,
                                                   lb=min_ppm,
                                                   ub=max_ppm)

        # Store the params:
        self.water_model = model
        self.water_signal = signal
        self.water_params = params
        self.water_idx = ut.make_idx(self.f_ppm, min_ppm, max_ppm)
        mean_params = stats.nanmean(params, 0)
        self.water_auc = self._calc_auc(ut.lorentzian, params, self.water_idx)
Example #4
0
def fit_two_gaussian(spectra, f_ppm, lb=3.6, ub=3.9):
    """
   Fit a gaussian function to the difference spectra

   This is useful for estimation of the Glx peak, which tends to have two
   peaks.


   Parameters
   ----------
   spectra : array of shape (n_transients, n_points)
      Typically the difference of the on/off spectra in each transient.

   f_ppm : array

   lb, ub : floats
      In ppm, the range over which optimization is bounded

   """
    idx = ut.make_idx(f_ppm, lb, ub)
    # We are only going to look at the interval between lb and ub
    n_points = idx.stop - idx.start
    n_params = 8
    fit_func = ut.two_gaussian
    # Set the bounds for the optimization
    bounds = [
        (lb, ub),  # peak 1 location
        (lb, ub),  # peak 2 location
        (0, None),  # sigma 1
        (0, None),  # sigma 2
        (0, None),  # amp 1
        (0, None),  # amp 2
        (None, None),  # offset
        (None, None),  # drift
    ]

    model = np.empty((spectra.shape[0], n_points))
    signal = np.empty((spectra.shape[0], n_points))
    params = np.empty((spectra.shape[0], n_params))
    for ii, xx in enumerate(spectra):
        # We fit to the real spectrum:
        signal[ii] = np.real(xx[idx])
        params[ii] = _do_two_gaussian_fit(f_ppm[idx],
                                          np.real(signal[ii]),
                                          bounds=bounds)

        model[ii] = fit_func(f_ppm[idx], *params[ii])

    return model, signal, params
Example #5
0
def fit_two_lorentzian(spectra, f_ppm, lb=2.6, ub=3.6):
    """
   Fit a lorentzian function to the sum spectra to be used for estimation of
   the creatine and choline peaks.
   
   Parameters
   ----------
   spectra : array of shape (n_transients, n_points)
      Typically the sum of the on/off spectra in each transient.

   f_ppm : array

   lb, ub : floats
      In ppm, the range over which optimization is bounded
   
   """
    # We are only going to look at the interval between lb and ub
    idx = ut.make_idx(f_ppm, lb, ub)
    n_points = np.abs(idx.stop - idx.start)
    n_params = 10  # Lotsa params!
    # Set the bounds for the optimization
    bounds = [
        (lb, ub),  #peak1 
        (lb, ub),  #peak2 
        (0, None),  #area1 
        (0, None),  #area2 
        (0, ub - lb),  #hwhm1 
        (0, ub - lb),  #hwhm2
        (-np.pi / 2, np.pi / 2),  #phase
        (-np.pi / 2, np.pi / 2),  #phase
        (None, None),  #offset
        (None, None)
    ]  #drift

    model = np.empty((spectra.shape[0], n_points))
    signal = np.empty((spectra.shape[0], n_points))
    params = np.empty((spectra.shape[0], n_params))
    for ii, xx in enumerate(spectra):
        # We fit to the real spectrum:
        signal[ii] = np.real(xx[idx])
        params[ii] = _do_two_lorentzian_fit(f_ppm[idx],
                                            np.real(signal[ii]),
                                            bounds=bounds)

        model[ii] = ut.two_lorentzian(f_ppm[idx], *params[ii])

    return model, signal, params
Example #6
0
def fit_two_gaussian(spectra, f_ppm, lb=3.6, ub=3.9):
   """
   Fit a gaussian function to the difference spectra

   This is useful for estimation of the Glx peak, which tends to have two
   peaks.


   Parameters
   ----------
   spectra : array of shape (n_transients, n_points)
      Typically the difference of the on/off spectra in each transient.

   f_ppm : array

   lb, ub: floats
      In ppm, the range over which optimization is bounded

   """
   idx = ut.make_idx(f_ppm, lb, ub)
   # We are only going to look at the interval between lb and ub
   n_points = idx.stop - idx.start
   n_params = 8
   fit_func = ut.two_gaussian
   # Set the bounds for the optimization
   bounds = [(lb,ub), # peak 1 location
             (lb,ub), # peak 2 location
             (0,None), # sigma 1
             (0,None), # sigma 2
             (0,None), # amp 1
             (0,None), # amp 2
             (None, None), # offset
             (None, None),  # drift
             ]

   model = np.empty((spectra.shape[0], n_points))
   signal = np.empty((spectra.shape[0], n_points))
   params = np.empty((spectra.shape[0], n_params))
   for ii, xx in enumerate(spectra):
      # We fit to the real spectrum:
      signal[ii] = np.real(xx[idx])
      params[ii] = _do_two_gaussian_fit(f_ppm[idx], np.real(signal[ii]),
                                      bounds=bounds)

      model[ii] = fit_func(f_ppm[idx], *params[ii])

   return model, signal, params
Example #7
0
def fit_two_lorentzian(spectra, f_ppm, lb=2.6, ub=3.6):
   """
   Fit a lorentzian function to the sum spectra to be used for estimation of
   the creatine and choline peaks.
   
   Parameters
   ----------
   spectra : array of shape (n_transients, n_points)
      Typically the sum of the on/off spectra in each transient.

   f_ppm : array

   lb, ub: floats
      In ppm, the range over which optimization is bounded
   
   """
   # We are only going to look at the interval between lb and ub
   idx = ut.make_idx(f_ppm, lb, ub)
   n_points = np.abs(idx.stop - idx.start) 
   n_params = 10 # Lotsa params!
   # Set the bounds for the optimization
   bounds = [(lb,ub), #peak1 
             (lb,ub), #peak2 
             (0,None), #area1 
             (0,None), #area2 
             (0,ub-lb), #hwhm1 
             (0,ub-lb), #hwhm2
             (-np.pi/2, np.pi/2), #phase
             (-np.pi/2, np.pi/2), #phase
             (None,None), #offset
             (None, None)] #drift 

   model = np.empty((spectra.shape[0], n_points))
   signal = np.empty((spectra.shape[0], n_points))
   params = np.empty((spectra.shape[0], n_params))
   for ii, xx in enumerate(spectra):
      # We fit to the real spectrum:
      signal[ii] = np.real(xx[idx])
      params[ii] = _do_two_lorentzian_fit(f_ppm[idx], np.real(signal[ii]),
                                      bounds=bounds)
      
      model[ii] = ut.two_lorentzian(f_ppm[idx], *params[ii])
   
   return model, signal, params
Example #8
0
    def fit_naa(self, reject_outliers=3.0, fit_lb=1.8, fit_ub=2.4,
                 phase_correct=True):
        """
        Fit a Lorentzian function to the NAA peak at ~ 2 ppm.  Example of
        fitting inverted peak: Foerster et al. 2013, An imbalance between
        excitatory and inhibitory neurotransmitters in amyothrophic lateral
        sclerosis revealed by use of 3T proton MRS
        """
        model, signal, params = ana.fit_lorentzian(self.diff_spectra,
                                                   self.f_ppm,
                                                   lb=fit_lb,
                                                   ub=fit_ub)

        # Store the params:
        self.naa_model = model
        self.naa_signal = signal
        self.naa_params = params
        self.naa_idx = ut.make_idx(self.f_ppm, fit_lb, fit_ub)
        mean_params = stats.nanmean(params, 0)
        self.naa_auc = self._calc_auc(ut.lorentzian, params, self.naa_idx)
Example #9
0
    def fit_naa(self, reject_outliers=3.0, fit_lb=1.8, fit_ub=2.4,
                 phase_correct=True):
        """
        Fit a Lorentzian function to the NAA peak at ~ 2 ppm.  Example of
        fitting inverted peak: Foerster et al. 2013, An imbalance between
        excitatory and inhibitory neurotransmitters in amyothrophic lateral
        sclerosis revealed by use of 3T proton MRS
        """
        model, signal, params = ana.fit_lorentzian(self.diff_spectra,
                                                   self.f_ppm,
                                                   lb=fit_lb,
                                                   ub=fit_ub)

        # Store the params:
        self.naa_model = model
        self.naa_signal = signal
        self.naa_params = params
        self.naa_idx = ut.make_idx(self.f_ppm, fit_lb, fit_ub)
        mean_params = stats.nanmean(params, 0)
        self.naa_auc = self._calc_auc(ut.lorentzian, params, self.naa_idx)
Example #10
0
    def fit_glx2(self,
                 reject_outliers=3.0,
                 fit_lb=3.6,
                 fit_ub=3.9,
                 phase_correct=True,
                 scalefit=False):
        """

        Parameters
        ----------
        reject_outliers : float or bool
           If set to a float, this is the z score threshold for rejection (on
           any of the parameters). If set to False, no outlier rejection

        fit_lb, fit_ub : float
           What part of the spectrum (in ppm) contains the creatine peak.
           Default (3.5, 4.2)

        scalefit : boolean
           If this is set to true, attempt is made to tighten the fit to the
           peak with a second round of fitting where the fitted curve
           is fit with a scale factor. (default false)

        """
        if not hasattr(self, 'creatine_params'):
            self.fit_creatine()

        fit_spectra = self.diff_spectra

        # We fit a two-gaussian function to this entire chunk of the spectrum,
        # to catch both glx peaks
        model, signal, params = ana.fit_two_gaussian(fit_spectra,
                                                     self.f_ppm,
                                                     lb=fit_lb,
                                                     ub=fit_ub)

        # Use an array of ones to index everything but the outliers and nans:
        ii = np.ones(signal.shape[0], dtype=bool)
        # Reject outliers:
        if reject_outliers:
            model, signal, params, ii = self._outlier_rejection(
                params, model, signal, ii)

        # We'll keep around a private attribute to tell us which transients
        # were good:
        self._glx2_transients = np.where(ii)

        # Now we separate params of the two glx peaks from each other
        # (remember that they both share offset and drift!):
        self.glxp1_params = params[:, (0, 2, 4, 6, 7)]
        self.glxp2_params = params[:, (1, 3, 5, 6, 7)]

        self.glx2_idx = ut.make_idx(self.f_ppm, fit_lb, fit_ub)

        # We'll need to generate the model predictions from these parameters,
        # because what we're holding in 'model' is for both together:
        self.glxp1_model = np.zeros(
            (self.glxp1_params.shape[0],
             np.abs(self.glx2_idx.stop - self.glx2_idx.start)))

        self.glxp2_model = np.zeros(
            (self.glxp2_params.shape[0],
             np.abs(self.glx2_idx.stop - self.glx2_idx.start)))

        for idx in range(self.glxp2_params.shape[0]):
            self.glxp2_model[idx] = ut.gaussian(self.f_ppm[self.glx2_idx],
                                                *self.glxp2_params[idx])
            self.glxp1_model[idx] = ut.gaussian(self.f_ppm[self.glx2_idx],
                                                *self.glxp1_params[idx])

        if scalefit:
            combinedmodel = self.glxp2_model + self.glxp1_model
            scalefac, scalemodel = ana._do_scale_fit(self.f_ppm[self.glx2_idx],
                                                     signal, combinedmodel)
            # Reject outliers:
            scalemodel, signal, params, ii = self._rm_outlier_by_amp(
                params, scalemodel, signal, ii)
            self.glx2_model = scalemodel
        else:
            self.glx2_model = self.glxp1_model + self.glxp2_model

        self.glx2_signal = signal
        self.glx2_auc = (
            self._calc_auc(ut.gaussian, self.glxp2_params, self.glx2_idx) +
            self._calc_auc(ut.gaussian, self.glxp1_params, self.glx2_idx))
Example #11
0
    def _fit_helper(self, fit_spectra, reject_outliers, fit_lb, fit_ub,
                    fit_func):
        """
        This is a helper function for fitting different segments of the spectrum
        with Gaussian functions (GLX and GABA).

        Parameters
        ----------
        fit_spectra : ndarray
           The data to fit

        reject_outliers : float or bool
            Z score for outlier rejection. If set to `False`, not outlier
            rejection.

        fit_lb : float
            The lower bound of the part of the ppm scale for which the Gaussian
            is fit.

        fit_ub : float
            The upper bound of the part of the scale fit.

        fit_func: callable
           e.g. `fit_gaussian`

        Returns
        -------
        choose_transients : tuple
            Indices into the original data's transients dimension to select

        non-outlier transients. If reject_outliers is set to `False`, this is
            all the  transients

        model : ndarray
            The model predicition in each transient, based on the fit.

        signal : ndarray
            The original signal in this part of the difference spectrum.

        params : ndarray
            The Gaussian parameters in each transient as fit.

        this_idx : slice object
            A slice into the part of the spectrum that is fit
        """
        # fit_idx should already be set from fitting the creatine params:
        model, signal, params = fit_func(fit_spectra,
                                         self.f_ppm,
                                         lb=fit_lb,
                                         ub=fit_ub)

        # We'll use these indices to reject outliers (or not):
        ii = np.ones(signal.shape[0], dtype=bool)
        # Reject outliers:
        if reject_outliers:
            model, signal, params, ii = self._outlier_rejection(
                params, model, signal, ii)

        choose_transients = np.where(ii)
        this_idx = ut.make_idx(self.f_ppm, fit_lb, fit_ub)
        return choose_transients, model, signal, params, this_idx
Example #12
0
    def fit_creatine(self, reject_outliers=3.0, fit_lb=2.7, fit_ub=3.5):
        """
        Fit a model to the portion of the summed spectra containing the
        creatine and choline signals.

        Parameters
        ----------
        reject_outliers : float or bool
           If set to a float, this is the z score threshold for rejection (on
           any of the parameters). If set to False, no outlier rejection

        fit_lb, fit_ub : float
           What part of the spectrum (in ppm) contains the creatine peak.
           Default (2.7, 3.5)

        Note
        ----
        We use upper and lower bounds that are a variation on the bounds
        mentioned on the GANNET ISMRM2013 poster [1]_.

        [1] RAE Edden et al (2013). Gannet GABA analysis toolkit. ISMRM
        conference poster.

        """
        # We fit a two-lorentz function to this entire chunk of the spectrum,
        # to catch both choline and creatine
        model, signal, params = ana.fit_two_lorentzian(self.sum_spectra,
                                                       self.f_ppm,
                                                       lb=fit_lb,
                                                       ub=fit_ub)

        # Use an array of ones to index everything but the outliers and nans:
        ii = np.ones(signal.shape[0], dtype=bool)
        # Reject outliers:
        if reject_outliers:
            model, signal, params, ii = self._outlier_rejection(
                params, model, signal, ii)

        # We'll keep around a private attribute to tell us which transients
        # were good (this is for both creatine and choline):
        self._cr_transients = np.where(ii)

        # Now we separate choline and creatine params from each other (remember
        # that they both share offset and drift!):
        self.choline_params = params[:, (0, 2, 4, 6, 8, 9)]
        self.creatine_params = params[:, (1, 3, 5, 7, 8, 9)]

        self.cr_idx = ut.make_idx(self.f_ppm, fit_lb, fit_ub)

        # We'll need to generate the model predictions from these parameters,
        # because what we're holding in 'model' is for both together:
        self.choline_model = np.zeros(
            (self.creatine_params.shape[0],
             np.abs(self.cr_idx.stop - self.cr_idx.start)))

        self.creatine_model = np.zeros(
            (self.choline_params.shape[0],
             np.abs(self.cr_idx.stop - self.cr_idx.start)))

        for idx in range(self.creatine_params.shape[0]):
            self.creatine_model[idx] = ut.lorentzian(
                self.f_ppm[self.cr_idx], *self.creatine_params[idx])
            self.choline_model[idx] = ut.lorentzian(self.f_ppm[self.cr_idx],
                                                    *self.choline_params[idx])
        self.creatine_signal = signal
        self.creatine_auc = self._calc_auc(ut.lorentzian, self.creatine_params,
                                           self.cr_idx)
        self.choline_auc = self._calc_auc(ut.lorentzian, self.choline_params,
                                          self.cr_idx)
Example #13
0
def fit_gaussian(spectra, f_ppm, lb=2.6, ub=3.6):
   """
   Fit a gaussian function to the difference spectra to be used for estimation
   of the GABA peak.
   
   Parameters
   ----------
   spectra : array of shape (n_transients, n_points)
      Typically the difference of the on/off spectra in each transient.

   f_ppm : array

   lb, ub: floats
      In ppm, the range over which optimization is bounded
   
   """
   idx = ut.make_idx(f_ppm, lb, ub)
   # We are only going to look at the interval between lb and ub
   n_points = idx.stop - idx.start
   n_params = 5
   fit_func = ut.gaussian
   # Set the bounds for the optimization
   bounds = [(lb,ub), # peak location
             (0,None), # sigma
             (0,None), # amp
             (None, None), # offset
             (None, None)  # drift
             ]

   model = np.empty((spectra.shape[0], n_points))
   signal = np.empty((spectra.shape[0], n_points))
   params = np.empty((spectra.shape[0], n_params))
   for ii, xx in enumerate(spectra):
      # We fit to the real spectrum:
      signal[ii] = np.real(xx[idx])
      # Use the signal for a rough estimate of the parameters for
      # initialization :
      max_idx = np.argmax(signal[ii])
      max_sig = np.max(signal[ii])
      initial_f0 = f_ppm[idx][max_idx]
      half_max_idx = np.argmin(np.abs(signal[ii] - max_sig/2))
      # We estimate sigma as the hwhm:
      initial_sigma = np.abs(initial_f0 - f_ppm[idx][half_max_idx])
      initial_off = np.min(signal[ii])
      initial_drift = 0
      initial_amp = max_sig
      
      initial = (initial_f0,
                 initial_sigma,
                 initial_amp,
                 initial_off,
                 initial_drift)
      
      params[ii], _ = lsq.leastsqbound(mopt.err_func,
                                       initial,
                                       args=(f_ppm[idx],
                                             np.real(signal[ii]),
                                             fit_func), bounds=bounds)

      model[ii] = fit_func(f_ppm[idx], *params[ii])
   
   return model, signal, params
Example #14
0
    def fit_glx2(self, reject_outliers=3.0, fit_lb=3.6, fit_ub=3.9,
                 phase_correct=True, scalefit=False):
        """

        Parameters
        ----------
        reject_outliers : float or bool
           If set to a float, this is the z score threshold for rejection (on
           any of the parameters). If set to False, no outlier rejection

        fit_lb, fit_ub : float
           What part of the spectrum (in ppm) contains the creatine peak.
           Default (3.5, 4.2)

        scalefit : boolean
           If this is set to true, attempt is made to tighten the fit to the
           peak with a second round of fitting where the fitted curve
           is fit with a scale factor. (default false)

        """
        if not hasattr(self, 'creatine_params'):
            self.fit_creatine()

        fit_spectra = self.diff_spectra

        # We fit a two-gaussian function to this entire chunk of the spectrum,
        # to catch both glx peaks
        model, signal, params = ana.fit_two_gaussian(fit_spectra,
                                                     self.f_ppm,
                                                     lb=fit_lb,
                                                     ub=fit_ub)

        # Use an array of ones to index everything but the outliers and nans:
        ii = np.ones(signal.shape[0], dtype=bool)
        # Reject outliers:
        if reject_outliers:
            model, signal, params, ii = self._outlier_rejection(params,
                                                                model,
                                                                signal,
                                                                ii)

        # We'll keep around a private attribute to tell us which transients
        # were good:
        self._glx2_transients = np.where(ii)

        # Now we separate params of the two glx peaks from each other
        # (remember that they both share offset and drift!):
        self.glxp1_params = params[:, (0, 2, 4, 6, 7)]
        self.glxp2_params = params[:, (1, 3, 5, 6, 7)]

        self.glx2_idx = ut.make_idx(self.f_ppm, fit_lb, fit_ub)

        # We'll need to generate the model predictions from these parameters,
        # because what we're holding in 'model' is for both together:
        self.glxp1_model = np.zeros((self.glxp1_params.shape[0],
                                np.abs(self.glx2_idx.stop-self.glx2_idx.start)))

        self.glxp2_model = np.zeros((self.glxp2_params.shape[0],
                                np.abs(self.glx2_idx.stop-self.glx2_idx.start)))

        for idx in range(self.glxp2_params.shape[0]):
            self.glxp2_model[idx] = ut.gaussian(self.f_ppm[self.glx2_idx],
                                                *self.glxp2_params[idx])
            self.glxp1_model[idx] = ut.gaussian(self.f_ppm[self.glx2_idx],
                                                    *self.glxp1_params[idx])

        if scalefit:
            combinedmodel = self.glxp2_model + self.glxp1_model
            scalefac, scalemodel = ana._do_scale_fit(
                self.f_ppm[self.glx2_idx], signal,combinedmodel)
            # Reject outliers:
            scalemodel, signal, params, ii = self._rm_outlier_by_amp(params,
                                                                scalemodel,
                                                                signal,
                                                                ii)
            self.glx2_model = scalemodel
        else:
            self.glx2_model = self.glxp1_model + self.glxp2_model


        self.glx2_signal = signal
        self.glx2_auc = (
            self._calc_auc(ut.gaussian, self.glxp2_params, self.glx2_idx) +
            self._calc_auc(ut.gaussian, self.glxp1_params, self.glx2_idx))
Example #15
0
    def _fit_helper(self, fit_spectra, reject_outliers, fit_lb, fit_ub,
                    fit_func):
        """
        This is a helper function for fitting different segments of the spectrum
        with Gaussian functions (GLX and GABA).

        Parameters
        ----------
        fit_spectra : ndarray
           The data to fit

        reject_outliers : float or bool
            Z score for outlier rejection. If set to `False`, not outlier
            rejection.

        fit_lb : float
            The lower bound of the part of the ppm scale for which the Gaussian
            is fit.

        fit_ub : float
            The upper bound of the part of the scale fit.

        fit_func: callable
           e.g. `fit_gaussian`

        Returns
        -------
        choose_transients : tuple
            Indices into the original data's transients dimension to select

        non-outlier transients. If reject_outliers is set to `False`, this is
            all the  transients

        model : ndarray
            The model predicition in each transient, based on the fit.

        signal : ndarray
            The original signal in this part of the difference spectrum.

        params : ndarray
            The Gaussian parameters in each transient as fit.

        this_idx : slice object
            A slice into the part of the spectrum that is fit
        """
        # fit_idx should already be set from fitting the creatine params:
        model, signal, params = fit_func(fit_spectra,
                                         self.f_ppm,
                                         lb=fit_lb,
                                         ub=fit_ub)

        # We'll use these indices to reject outliers (or not):
        ii = np.ones(signal.shape[0], dtype=bool)
        # Reject outliers:
        if reject_outliers:
            model, signal, params, ii = self._outlier_rejection(params,
                                                                model,
                                                                signal,
                                                                ii)

        choose_transients = np.where(ii)
        this_idx = ut.make_idx(self.f_ppm, fit_lb, fit_ub)
        return choose_transients, model, signal, params, this_idx
Example #16
0
    def fit_creatine(self, reject_outliers=3.0, fit_lb=2.7, fit_ub=3.5):
        """
        Fit a model to the portion of the summed spectra containing the
        creatine and choline signals.

        Parameters
        ----------
        reject_outliers : float or bool
           If set to a float, this is the z score threshold for rejection (on
           any of the parameters). If set to False, no outlier rejection

        fit_lb, fit_ub : float
           What part of the spectrum (in ppm) contains the creatine peak.
           Default (2.7, 3.5)

        Note
        ----
        We use upper and lower bounds that are a variation on the bounds
        mentioned on the GANNET ISMRM2013 poster [1]_.

        [1] RAE Edden et al (2013). Gannet GABA analysis toolkit. ISMRM
        conference poster.

        """
        # We fit a two-lorentz function to this entire chunk of the spectrum,
        # to catch both choline and creatine
        model, signal, params = ana.fit_two_lorentzian(self.sum_spectra,
                                                       self.f_ppm,
                                                       lb=fit_lb,
                                                       ub=fit_ub)

        # Use an array of ones to index everything but the outliers and nans:
        ii = np.ones(signal.shape[0], dtype=bool)
        # Reject outliers:
        if reject_outliers:
            model, signal, params, ii = self._outlier_rejection(params,
                                                                model,
                                                                signal,
                                                                ii)
            
        # We'll keep around a private attribute to tell us which transients
        # were good (this is for both creatine and choline):
        self._cr_transients = np.where(ii)
        
        # Now we separate choline and creatine params from each other (remember
        # that they both share offset and drift!):
        self.choline_params = params[:, (0,2,4,6,8,9)]
        self.creatine_params = params[:, (1,3,5,7,8,9)]
        
        self.cr_idx = ut.make_idx(self.f_ppm, fit_lb, fit_ub)

        # We'll need to generate the model predictions from these parameters,
        # because what we're holding in 'model' is for both together:
        self.choline_model = np.zeros((self.creatine_params.shape[0],
                                    np.abs(self.cr_idx.stop-self.cr_idx.start)))

        self.creatine_model = np.zeros((self.choline_params.shape[0],
                                    np.abs(self.cr_idx.stop-self.cr_idx.start)))
        
        for idx in range(self.creatine_params.shape[0]):
            self.creatine_model[idx] = ut.lorentzian(self.f_ppm[self.cr_idx],
                                                     *self.creatine_params[idx])
            self.choline_model[idx] = ut.lorentzian(self.f_ppm[self.cr_idx],
                                                    *self.choline_params[idx])
        self.creatine_signal = signal
        self.creatine_auc = self._calc_auc(ut.lorentzian,
                                           self.creatine_params,
                                           self.cr_idx)
        self.choline_auc = self._calc_auc(ut.lorentzian,
                                          self.choline_params,
                                          self.cr_idx)