def fit_data_bg(x, y, peak_pos, peak_type='LO', width=None, bg_ord=0): """ Builds a lmfit model of peaks in listed by index in `peak_pos` Parameters ---------- peak_type : string (default='lorentizian') Peaks can be of the following types: - 'LO' : symmetric lorentzian - 'GA' : symmetric gaussain - 'VO' : symmetric pseudo voigt max_width : int (default = total points/10) max width (in data points) that peak fitted can be bg_ord: int order of the background polynomial 0: constant, 1: linear, ... Returns ------- out: fitted model """ # need to define peak width finding if width is None: width = guess_peak_width(x, y) # start with polynomial background model = PolynomialModel(bg_ord, prefix='bg_') pars = model.make_params() if peak_type == 'LO': peak_function = lorentzian elif peak_type == 'GA': peak_function = gaussian elif peak_type == 'VO': peak_function = voigt # add peak type for all peaks for i, peak in enumerate(peak_pos): temp_model = Model(peak_function, prefix='p%s_' % i) pars.update(temp_model.make_params()) model += temp_model # set initial background as flat line at zeros for i in range(bg_ord + 1): pars['bg_c%i' % i].set(0) # give values for other peaks, keeping width and height positive for i, peak in enumerate(peak_pos): pars['p%s_x0' % i].set(x[peak]) pars['p%s_fwhm' % i].set(width, min=0) pars['p%s_amp' % i].set(y[peak], min=0) out = model.fit(y, pars, x=x) return out
def fit_experimental_data_gauss(exp_x, exp_y, expected_peak_pos, deg_of_bck_poly=5, maxfev=25000): num_of_peaks = len(expected_peak_pos) mod = PolynomialModel(deg_of_bck_poly, prefix='poly_') for c in range(num_of_peaks): mod = mod + PseudoVoigtModel(prefix='p{}_'.format(c)) params = mod.make_params() center = 0 sigma = 0 amplitude = 0 fraction = 0 for param in params: if 'center' in param: params[param].set(value=expected_peak_pos[center]) params[param].set(min=expected_peak_pos[center] - 0.5) params[param].set(max=expected_peak_pos[center] + 0.5) center += 1 if 'poly' in param: if param == 'poly_c0': params[param].set(value=50) params[param].set(min=-100) params[param].set(max=100) continue if param == 'poly_c1': params[param].set(value=-1) params[param].set(min=-100) params[param].set(max=100) continue params[param].set(value=0) ## params[param].set(min = 3e-1) ## params[param].set(max = 3e-1) if 'sigma' in param: params[param].set(value=0.5) params[param].set(min=0.0001) params[param].set(max=0.8) sigma += 1 if 'amplitude' in param: params[param].set(value=5.5) params[param].set(min=0.0001) amplitude += 1 if 'fraction' in param: params[param].set(value=0.0) params[param].set(min=0.000) params[param].set(max=0.000001) fraction += 1 result = mod.fit(np.asarray(exp_y), params, x=np.asarray(exp_x), fit_kws={'maxfev': maxfev}) print(result.fit_report()) return result
def fit_data_bg(x, y, peak_pos, peak_type="LO", width=None, bg_ord=0): """ Builds a lmfit model of peaks in listed by index in `peak_pos` Parameters ---------- peak_type : string (default='lorentizian') Peaks can be of the following types: - 'LO' : symmetric lorentzian - 'GA' : symmetric gaussain - 'VO' : symmetric pseudo voigt max_width : int (default = total points/10) max width (in data points) that peak fitted can be bg_ord: int order of the background polynomial 0: constant, 1: linear, ... Returns ------- out: fitted model """ # need to define peak width finding if width is None: width = guess_peak_width(x, y) # start with polynomial background model = PolynomialModel(bg_ord, prefix="bg_") pars = model.make_params() if peak_type == "LO": peak_function = lorentzian elif peak_type == "GA": peak_function = gaussian elif peak_type == "VO": peak_function = voigt # add peak type for all peaks for i, peak in enumerate(peak_pos): temp_model = Model(peak_function, prefix="p%s_" % i) pars.update(temp_model.make_params()) model += temp_model # set initial background as flat line at zeros for i in range(bg_ord + 1): pars["bg_c%i" % i].set(0) # give values for other peaks, keeping width and height positive for i, peak in enumerate(peak_pos): pars["p%s_x0" % i].set(x[peak]) pars["p%s_fwhm" % i].set(width, min=0) pars["p%s_amp" % i].set(y[peak], min=0) out = model.fit(y, pars, x=x) return out
def bg_sub(raman_spectra, plot_each=False, reduce_region=[3090, 4000], cut_region=[3150, 3722], order=2, to_run='all'): bg = PolynomialModel(order) flag = False if type(raman_spectra) == AHR.RamanSpectrum: raman_spectra = {'a': raman_spectra} flag = True BGsub = {} for key, spec in raman_spectra.items(): if to_run != 'all': if key not in to_run: continue spec_red = spec.reduce_wn_region(reduce_region) spec_cut = spec_red.cut_wn_region(cut_region) spec_cut_x = spec_cut.wn spec_cut_y = np.squeeze(spec_cut.spec_data.T) bg_params = bg.make_params(c0=0, c1=0, c2=0, c3=0, c4=0, c5=5, c6=0, c7=0) bg_fit = bg.fit(spec_cut_y, x=spec_cut_x, params=bg_params) spec_red_bg_sub = AHR.RamanSpectrum( spec_red.wn, np.squeeze(spec_red.spec_data.T) - bg_fit.eval(x=spec_red.wn)) BGsub[key] = spec_red_bg_sub if plot_each: fig, ax = plt.subplots() ax.plot(spec_red.wn, spec_red.spec_data.T) ax.scatter(spec_cut.wn, spec_cut.spec_data.T, s=3, color='orange') ax.plot(spec_red.wn, bg_fit.eval(x=spec_red.wn)) ax.set_title(key) if flag: return BGsub['a'] else: return BGsub
def prepare_for_fitting(self, poly_order, maxwidth, centerrange): """ :param x_center: numpy array of initial x values at picked centers :param y_center: numpy array of initial y values at picked centers :param fwhm: single float number for initial fwhm value """ self.set_baseline(poly_order) baseline_mod = PolynomialModel(poly_order, prefix='b_') mod = baseline_mod pars = baseline_mod.make_params() peakinfo = {} for i in range(poly_order + 1): prefix = "b_c{0:d}".format(i) pars[prefix].set(value=self.baseline_in_queue[i]['value'], vary=self.baseline_in_queue[i]['vary']) i = 0 for peak in self.peaks_in_queue: prefix = "p{0:d}_".format(i) peak_mod = PseudoVoigtModel(prefix=prefix, ) pars.update(peak_mod.make_params()) pars[prefix + 'center'].set(value=peak['center'], min=peak['center'] - centerrange, max=peak['center'] + centerrange, vary=peak['center_vary']) pars[prefix + 'sigma'].set(value=peak['sigma'], min=0.0, vary=peak['sigma_vary'], max=maxwidth) pars[prefix + 'amplitude'].set(value=peak['amplitude'], min=0, vary=peak['amplitude_vary']) pars[prefix + 'fraction'].set(value=peak['fraction'], min=0., max=1., vary=peak['fraction_vary']) peakinfo[prefix + 'phasename'] = peak['phasename'] peakinfo[prefix + 'h'] = peak['h'] peakinfo[prefix + 'k'] = peak['k'] peakinfo[prefix + 'l'] = peak['l'] mod += peak_mod i += 1 self.parameters = pars self.peakinfo = peakinfo self.fit_model = mod
def fitTwoGaussians(x,y): background = PolynomialModel(2) pars = background.make_params() peak1 = GaussianModel(prefix='p1_') pars.update( peak1.make_params()) peak2 = GaussianModel(prefix='p2_') pars.update( peak2.make_params()) # Guess some parameters from data to help the fitting span = max(x)-min(x) c1Guess = (y[-1]-y[0])/(x[-1]-x[0]) c0Guess = y[0]-c1Guess*x[0] bgGuess = background.func(x=x,c0=c0Guess,c1=c1Guess,c2=0.) signalGuess=min(y-bgGuess) sigmaGuess = span/30. amplitudeGuess = signalGuess*(sigmaGuess*np.sqrt(2.0*np.pi)) # Fit variables initialization # pars.add('splitting',0.0001,max=span) pars['c2'].set(0.,min=-0.000001,max=0.001) pars['c1'].set(c1Guess) pars['c0'].set(c0Guess) pars['p1_center'].set(min(x)+span*0.35,min=min(x),max=max(x)) pars['p2_center'].set(min(x)+span*0.55,min=min(x),max=max(x)) # pars['p2_center'].set(min(x)+span*0.65,expr='p1_center+splitting') pars['p1_amplitude'].set(amplitudeGuess,max=amplitudeGuess/10000.) pars['p2_amplitude'].set(amplitudeGuess,max=amplitudeGuess/10000.) pars['p1_sigma'].set(sigmaGuess, min=sigmaGuess/100.,max=sigmaGuess*10000.) pars['p2_sigma'].set(sigmaGuess, min=sigmaGuess/100.,max=sigmaGuess*10000.) #Add some useful parameters to evaluate pars.add('p1_signal', expr='p1_amplitude/(p1_sigma*sqrt(2.0*pi))') pars.add('p2_signal', expr='p2_amplitude/(p2_sigma*sqrt(2.0*pi))') pars.add('p1_contrast', expr='-p1_amplitude/(p1_sigma*sqrt(2.0*pi)*(c0+c1*p1_center+c2*p1_center**2))') pars.add('p2_contrast', expr='-p2_amplitude/(p2_sigma*sqrt(2.0*pi)*(c0+c1*p2_center+c2*p2_center**2))') pars.add('splitting',pars['p2_center']-pars['p1_center'],expr='p2_center-p1_center',min=0.00001) model = peak1 + peak2 + background init = model.eval(pars, x=x) out = model.fit(y, pars, x=x) # print out.fit_report() return init,out
def build_model_dd(bg_ord=1, peak_num=1, peak_type="lorentzian"): model = PolynomialModel(bg_ord, prefix="bg_") peak_str = peak_type.lower()[:2] if peak_str == "lo": peak_function = lorentzian_dd elif peak_str == "ga": peak_function = gaussian_dd elif peak_str == "vo" or peak_type == "ps": peak_function = voigt else: print( "'peak_type' should be one of 'lorentzian', 'gaussian' or 'pseudo-voight'" ) return for i in range(peak_num): model += Model(peak_function, prefix="p%s_" % i) params = model.make_params() return model, params
def build_model(self, peak_type='LO', max_width=None, bg_ord=2): """ Builds a lmfit model of peaks in listed by index in `peak_pos` Uses some basic algorithms to determine initial parameters for amplitude and fwhm (limit on fwhm to avoid fitting background as peaks) Parameters ---------- peak_type : string (default='lorentizian') Peaks can be of the following types: - 'LO' : symmetric lorentzian - 'GA' : symmetric gaussain max_width : int (default = total points/10) max width (in data points) that peak fitted can be bg_ord: int order of the background polynomial 0: constant, 1: linear, ... Returns ------- pars : model parameters model : model object """ x = self.x y = self.y pw = self.test_peak_width peak_guess = self.x[self.peak_pos] print("Building model ... ") # start with polynomial background # second order model = PolynomialModel(bg_ord, prefix='bg_') pars = model.make_params() if peak_type == 'LO': peak_function = lorentzian self.afactor = pi self.wfactor = 2.0 elif peak_type == 'GA': peak_function = gaussian self.afactor = sqrt(2 * pi) self.wfactor = 2.354820 elif peak_type == 'VO': peak_function = voigt self.afactor = sqrt(2 * pi) self.wfactor = 3.60131 # add lorentizian peak for all peaks for i, peak in enumerate(peak_guess): temp_model = Model(peak_function, prefix='p%s_' % i) pars.update(temp_model.make_params()) model += temp_model # set inital background as flat line at zeros for i in range(bg_ord + 1): pars['bg_c%i' % i].set(0) # give values for other peaks for i, peak in enumerate(self.peak_pos): print('Peak %i: pos %s, height %s' % (i, x[peak], y[peak])) # could set bounds #, min=x[peak]-5, max=x[peak]+5) pars['p%s_center' % i].set(x[peak]) pars['p%s_sigma' % i].set(pw / 2, min=pw * 0.25, max=pw * 2) # here as well #, min=0, max=2*max(y)) pars['p%s_amplitude' % i].set(self.amplitude(y[peak], (pw / 2))) self.pars = pars self.model = model return self.pars, self.model
def fit_data(x, y, peak_pos, peak_type='LO', max_width=None, bg_ord=2): """ Builds a lmfit model of peaks in listed by index in `peak_pos` Uses some basic algorithms to determine initial parameters for amplitude and fwhm (limit on fwhm to avoid fitting background as peaks) Parameters ---------- peak_type : string (default='lorentizian') Peaks can be of the following types: - 'LO' : symmetric lorentzian - 'GA' : symmetric gaussain - 'VO' : symmetric pseudo voigt max_width : int (default = total points/10) max width (in data points) that peak fitted can be bg_ord: int order of the background polynomial 0: constant, 1: linear, ... Returns ------- pars : model parameters model : model object """ # need to define peak width finding pw = guess_peak_width(x, y) peak_guess = x[peak_pos] # start with polynomial background model = PolynomialModel(bg_ord, prefix='bg_') pars = model.make_params() if peak_type == 'LO': peak_function = lorentzian elif peak_type == 'GA': peak_function = gaussian elif peak_type == 'VO': peak_function = voigt # add lorentizian peak for all peaks for i, peak in enumerate(peak_guess): temp_model = Model(peak_function, prefix='p%s_' % i) pars.update(temp_model.make_params()) model += temp_model # set inital background as flat line at zeros for i in range(bg_ord + 1): pars['bg_c%i' % i].set(0) # give values for other peaks for i, peak in enumerate(peak_pos): # could set bounds #, min=x[peak]-5, max=x[peak]+5) pars['p%s_x0' % i].set(x[peak]) pars['p%s_fwhm' % i].set(pw / 2, min=pw * 0.25, max=pw * 2) # here as well #, min=0, max=2*max(y)) pars['p%s_amp' % i].set(y[peak]) out = model.fit(y, pars, x=x) return out
def build_model(self, peak_type="LO", max_width=None, bg_ord=2): """ Builds a lmfit model of peaks in listed by index in `peak_pos` Uses some basic algorithms to determine initial parameters for amplitude and fwhm (limit on fwhm to avoid fitting background as peaks) Parameters ---------- peak_type : string (default='lorentizian') Peaks can be of the following types: - 'LO' : symmetric lorentzian - 'GA' : symmetric gaussain max_width : int (default = total points/10) max width (in data points) that peak fitted can be bg_ord: int order of the background polynomial 0: constant, 1: linear, ... Returns ------- pars : model parameters model : model object """ x = self.x y = self.y pw = self.test_peak_width peak_guess = self.x[self.peak_pos] print("Building model ... ") # start with polynomial background # second order model = PolynomialModel(bg_ord, prefix="bg_") pars = model.make_params() if peak_type == "LO": peak_function = lorentzian self.afactor = pi self.wfactor = 2.0 elif peak_type == "GA": peak_function = gaussian self.afactor = sqrt(2 * pi) self.wfactor = 2.354820 elif peak_type == "VO": peak_function = voigt self.afactor = sqrt(2 * pi) self.wfactor = 3.60131 # add lorentizian peak for all peaks for i, peak in enumerate(peak_guess): temp_model = Model(peak_function, prefix="p%s_" % i) pars.update(temp_model.make_params()) model += temp_model # set inital background as flat line at zeros for i in range(bg_ord + 1): pars["bg_c%i" % i].set(0) # give values for other peaks for i, peak in enumerate(self.peak_pos): print("Peak %i: pos %s, height %s" % (i, x[peak], y[peak])) # could set bounds #, min=x[peak]-5, max=x[peak]+5) pars["p%s_center" % i].set(x[peak]) pars["p%s_sigma" % i].set(pw / 2, min=pw * 0.25, max=pw * 2) # here as well #, min=0, max=2*max(y)) pars["p%s_amplitude" % i].set(self.amplitude(y[peak], (pw / 2))) self.pars = pars self.model = model return self.pars, self.model
def fit(spectra, obj, sigma=2.0, ord=4, iter=4): poly = PolynomialModel(3) pars = poly.make_params() for p in range(4): label = 'c'+str(p) pars[label].set(value=1., vary=True) wkcopy = np.copy(spectra[1]) truesp = [i for i in wkcopy if i > 5] truex = [spectra[0][i] for i in range(len(spectra[1])) if spectra[1][i] > 5] outcont = poly.fit(truesp, pars, x=truex) firstcont = outcont.eval(x=spectra[0]) xn = np.copy(spectra[0]) yn = np.copy(spectra[1])/firstcont pl1=plt.subplot((iter+1)*100+11) pl1.plot(xn, spectra[1], 'k-', linewidth=0.3) pl1.plot(xn, firstcont, 'r-', linewidth=0.6) pl1.set_ylim([0, np.mean(firstcont)*1.5]) for i in range(iter): i_=np.copy(i) niter=str(i_+1) sigma = sigma-i*0.21*sigma md = np.median(yn) n = len([i for i in yn if i > 0.1]) offset = (len(xn)-n)/2 absor = md - min(yn[offset:n-offset]) freq, bin = np.histogram(yn, bins=50, range=(md-absor, md+absor)) rebin = [(bin[b+1]+bin[b])/2 for b in range(len(bin)-1)] gauss = SkewedGaussianModel() pars = gauss.make_params() pars['center'].set(value=md, vary=True) pars['amplitude'].set(vary=True) pars['sigma'].set(vary=True) pars['gamma'].set(vary=True) out = gauss.fit(freq, pars, x=rebin) var = sigma*out.best_values['sigma'] xrbn = np.linspace(rebin[0], rebin[-1], num=100) yrbn = list(out.eval(x=xrbn)) mode = xrbn[yrbn.index(max(yrbn))] ync = np.copy(spectra[1]) xnc = np.copy(spectra[0]) mask = [] for j in range(len(yn)): if (yn[j] > mode+var/2) or (yn[j] < mode-var/2): mask.append(False) else: mask.append(True) mask = np.array(mask) ync = ync[mask] xnc = xnc[mask] poly2 = PolynomialModel(ord) pars2 = poly2.make_params() for p in range(ord+1): label = 'c'+str(p) pars2[label].set(value=1., vary=True) outcont2 = poly2.fit(ync, pars2, x=xnc) contf = outcont2.eval(x=xn) yn = spectra[1]/contf err = spectra[2]/contf pln=plt.subplot(int((iter+1)*100+10+(i_+2))) pln.plot(xn, yn*(np.mean(contf)*0.8), 'k-', linewidth=0.3) pln.plot(xnc, ync, 'r-', linewidth=0.3) pln.plot(xn, contf, 'b-', linewidth=0.6) pln.set_ylim([0, np.mean(contf)*1.2]) plt.savefig(obj[0]+'_fit.png', dpi=300) plt.clf() return np.array([xn, yn, err])
def fit(spectra, sigma=4.0, ptreg=8., ord=4, iter=2): rej = [] for i, w in enumerate(spectra[1]): if w <= 0: rej.append(i) spectra[0] = np.delete(spectra[0], rej) spectra[1] = np.delete(spectra[1], rej) # prepare first kick poly = PolynomialModel(3) pars = poly.make_params() for p in range(4): label = 'c' + str(p) pars[label].set(value=1., vary=True) wkcopy = np.copy(spectra[1]) truesp = [i for i in wkcopy if i >= 0] truex = [ spectra[0][i] for i in range(len(spectra[1])) if spectra[1][i] >= 0 ] outcont = poly.fit(truesp, pars, x=truex) firstcont = outcont.eval(x=spectra[0]) xn = np.copy(spectra[0]) yn = np.copy(spectra[1]) / firstcont # start cont. cleaning iterations for i in range(iter): i_ = np.copy(i) niter = str(i_ + 1) sigma = sigma - i * 0.21 * sigma md = np.median(yn) n = len([i for i in yn if i > 0.1]) offset = (len(xn) - n) / 2 absor = md - min(yn[offset:n - offset]) freq, bin = np.histogram(yn, bins=50, range=(md - absor, md + absor)) rebin = [(bin[b + 1] + bin[b]) / 2 for b in range(len(bin) - 1)] gauss = SkewedGaussianModel() pars = gauss.make_params() pars['center'].set(vary=True) pars['amplitude'].set(vary=True) pars['sigma'].set(vary=True) pars['gamma'].set(vary=True) out = gauss.fit(freq, pars, x=rebin) var = sigma * out.best_values['sigma'] xrbn = np.linspace(rebin[0], rebin[-1], num=100) yrbn = list(out.eval(x=xrbn)) mode = xrbn[yrbn.index(max(yrbn))] # clean cont. ync = np.copy(spectra[1]) xnc = np.copy(spectra[0]) mask = [] for j in range(len(yn)): if (yn[j] > mode + var / 2) or (yn[j] < mode - var / 2): mask.append(False) else: mask.append(True) mask = np.array(mask) ync = ync[mask] xnc = xnc[mask] # re-fitting poly2 = PolynomialModel(ord) pars2 = poly2.make_params() for p in range(ord + 1): label = 'c' + str(p) pars2[label].set(value=1., vary=True) try: outcont2 = poly2.fit(ync, pars2, x=xnc) except: plt.plot(xn, yn, 'k-') plt.plot([xn[0], xn[-1]], [mode, mode], 'b-') plt.plot([xn[0], xn[-1]], [mode + var / 2, mode + var / 2], 'r-') plt.plot([xn[0], xn[-1]], [mode - var / 2, mode - var / 2], 'r-') plt.show() contf = outcont2.eval(x=xn) yn = spectra[1] / contf clspec = [xnc, ync] # start slicing firstv = clspec[0][0] wavrange = clspec[0][-1] - firstv sliceno = wavrange / ptreg slisize = wavrange / sliceno points = [[], []] # continuum point definition for s in range(int(sliceno)): i = bissec(clspec[0], firstv + s * slisize) f = bissec(clspec[0], firstv + (s + 1) * slisize) slc = [clspec[0][i:f], clspec[1][i:f]] if len(slc[1]) > 2.: md = np.median(slc[1]) absor = min(slc[1]) high = max(slc[1]) freq, bin = np.histogram(slc[1], bins=20, range=(absor, high)) rebin = [(bin[b + 1] + bin[b]) / 2 for b in range(len(bin) - 1)] fmode = rebin[list(freq).index(max(freq))] fsigma = rebin[-1] - rebin[0] gauss = GaussianModel() pars = gauss.make_params() pars['center'].set(value=fmode, vary=True) pars['amplitude'].set(value=max(freq), vary=True) pars['sigma'].set(value=fsigma, vary=True) out = gauss.fit(freq, pars, x=rebin) xrbn = np.linspace(rebin[0], rebin[-1], num=100) yrbn = list(out.eval(x=xrbn)) mode = xrbn[yrbn.index(max(yrbn))] xp = slc[0][len(slc[0]) / 2] points[0].append(xp) points[1].append(mode) spline = splrep(points[0], points[1], k=3) contx = splev(clspec[0], spline) continuum = splev(spectra[0], spline) return [spectra[0], spectra[1] / continuum]