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
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_lorentzian_fit(freqs, signal, bounds=None): """ Helper function, so that Lorentzian fit can be generalized to different frequency scales (Hz and ppm). """ # Use the signal for a rough estimate of the parameters for initialization: max_idx = np.argmax(np.real(signal)) max_sig = np.max(np.real(signal)) initial_f0 = freqs[max_idx] half_max_idx = np.argmin(np.abs(np.real(signal) - max_sig / 2)) initial_hwhm = np.abs(initial_f0 - freqs[half_max_idx]) # Everything should be treated as real, except for the phase! initial_ph = np.angle(signal[signal.shape[-1] / 2.]) initial_off = np.min(np.real(signal)) initial_drift = 0 initial_a = (np.sum( np.real(signal)[max_idx:max_idx + np.abs(half_max_idx) * 2])) * 2 initial = (initial_f0, initial_a, initial_hwhm, initial_ph, initial_off, initial_drift) params, _ = lsq.leastsqbound(mopt.err_func, initial, args=(freqs, np.real(signal), ut.lorentzian), 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 _do_lorentzian_fit(freqs, signal, bounds=None): """ Helper function, so that Lorentzian fit can be generalized to different frequency scales (Hz and ppm). """ # Use the signal for a rough estimate of the parameters for initialization: max_idx = np.argmax(np.real(signal)) max_sig = np.max(np.real(signal)) initial_f0 = freqs[max_idx] half_max_idx = np.argmin(np.abs(np.real(signal) - max_sig/2)) initial_hwhm = np.abs(initial_f0 - freqs[half_max_idx]) # Everything should be treated as real, except for the phase! initial_ph = np.angle(signal[signal.shape[-1]/2.]) initial_off = np.min(np.real(signal)) initial_drift = 0 initial_a = (np.sum(np.real(signal)[max_idx:max_idx + np.abs(half_max_idx)*2]) ) * 2 initial = (initial_f0, initial_a, initial_hwhm, initial_ph, initial_off, initial_drift) params, _ = lsq.leastsqbound(mopt.err_func, initial, args=(freqs, np.real(signal), ut.lorentzian), bounds=bounds) return params
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