def _do_two_gaussian_fit(freqs, signal, bounds=None): """ Helper function for the two gaussian fit """ initial = _two_func_initializer(freqs, signal) # Edit out the ones we want in the order we want them: initial = (initial[0], initial[1], initial[6], initial[7], initial[2], initial[3], initial[10], initial[11]) # We want to preferntially weight the error on estimating the height of the # individual peaks, so we formulate an error-weighting function based on # these peaks, which is simply a two-gaussian bumpety-bump: w = (ut.gaussian(freqs, initial[0], 0.075, 1, 0, 0) + ut.gaussian(freqs, initial[1], 0.075, 1, 0, 0)) # Further, we want to also optimize on the individual gaussians error, to # restrict the fit space a bit more. For this purpose, we will pass a list # of gaussians with indices into the parameter list, so that we can do # that (see mopt.err_func for the mechanics). func_list = [[ut.gaussian, [0,2,4,6,7], ut.gaussian(freqs, initial[0], 0.075, 1, 0, 0)], [ut.gaussian, [1,3,5,6,7], ut.gaussian(freqs, initial[1], 0.075, 1, 0, 0)]] params, _ = lsq.leastsqbound(mopt.err_func, initial, args=(freqs, np.real(signal), ut.two_gaussian, w, func_list), bounds=bounds) return params
def _do_two_gaussian_fit(freqs, signal, bounds=None): """ Helper function for the two gaussian fit """ initial = _two_func_initializer(freqs, signal) # Edit out the ones we want in the order we want them: initial = (initial[0], initial[1], initial[6], initial[7], initial[2], initial[3], initial[10], initial[11]) # We want to preferntially weight the error on estimating the height of the # individual peaks, so we formulate an error-weighting function based on # these peaks, which is simply a two-gaussian bumpety-bump: w = (ut.gaussian(freqs, initial[0], 0.075, 1, 0, 0) + ut.gaussian(freqs, initial[1], 0.075, 1, 0, 0)) # Further, we want to also optimize on the individual gaussians error, to # restrict the fit space a bit more. For this purpose, we will pass a list # of gaussians with indices into the parameter list, so that we can do # that (see mopt.err_func for the mechanics). func_list = [[ ut.gaussian, [0, 2, 4, 6, 7], ut.gaussian(freqs, initial[0], 0.075, 1, 0, 0) ], [ ut.gaussian, [1, 3, 5, 6, 7], ut.gaussian(freqs, initial[1], 0.075, 1, 0, 0) ]] params, _ = lsq.leastsqbound(mopt.err_func, initial, args=(freqs, np.real(signal), ut.two_gaussian, w, func_list), bounds=bounds) return params
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))
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))