def test_lorentzian(): """ Test the lorentzian function """ freq = np.linspace(0,6,100) freq0 = 3 area = 1 hwhm = 1 phase = np.pi baseline0 = 1 baseline1 = 0 ut.lorentzian(freq, freq0, area, hwhm, phase, baseline0, baseline1)
def fit_lorentzian(spectra, f_ppm, lb=2.6, ub=3.6): """ Fit a lorentzian function to spectra This is used in estimation of the water peak and for estimation of the NAA peak. 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 = 6 # Set the bounds for the optimization bounds = [ (lb, ub), #peak (0, None), #area (0, None), #hwhm (-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_lorentzian_fit(f_ppm[idx], np.real(signal[ii]), bounds=bounds) model[ii] = ut.lorentzian(f_ppm[idx], *params[ii]) return model, signal, params
def fit_lorentzian(spectra, f_ppm, lb=2.6, ub=3.6): """ Fit a lorentzian function to spectra This is used in estimation of the water peak and for estimation of the NAA peak. 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 = 6 # Set the bounds for the optimization bounds = [(lb,ub), #peak (0,None), #area (0,None), #hwhm (-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_lorentzian_fit(f_ppm[idx], np.real(signal[ii]), bounds=bounds) model[ii] = ut.lorentzian(f_ppm[idx], *params[ii]) return model, signal, params
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)
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)