def least(func, x, y, sy=None, beta0=[]): linear = odrpack.Model(func) #mydata = odrpack.Data(x, z[1], wd=1./np.power(z[2],2), we=1./np.power(sy,2)) if not sy == None: mydata = odrpack.RealData(x, y, sy=sy) else: mydata = odrpack.RealData(x, y) myodr = odrpack.ODR(mydata, linear, beta0=beta0) myodr.set_job(fit_type=2) myoutput = myodr.run() myoutput.pprint() return myodr.output
def bilinear_Q_regression(freqs_log, Q_list_log): freqs_log = array(freqs_log) #data = odrpack.RealData(x[12:], y[12:]) data = odrpack.RealData(freqs_log, Q_list_log) #x_range = arange(-0.5, 1.0, step=0.01) # x range bilin_reg = odrpack.Model(bilinear_reg_free) odr = odrpack.ODR(data, bilin_reg, beta0=[0.4, 3.0, 0.3, -0.5]) odr.set_job( fit_type=2) #if set fit_type=2, returns the same as least squares out = odr.run() #print('\nbilinear auto\n') #out.pprint() a = out.beta[0] b = out.beta[1] c = out.beta[2] hx = out.beta[3] # x hinge point log_q_fit = b + a * freqs_log # get y values from bilinear yhinge = b + a * hx idx = freqs_log > hx log_q_fit[idx] = c * (freqs_log[idx] - hx) + yhinge return log_q_fit
def bilinear_regression(x, y): data = odrpack.RealData(x[12:], y[12:]) x_range = np.arange(-0.5, 1.0, step=0.01) # x range bilin_reg = odrpack.Model(bilinear_reg_free) odr = odrpack.ODR(data, bilin_reg, beta0=[0.4, 3.0, 0.3, -0.5]) odr.set_job(fit_type=2) #if set fit_type=2, returns the same as least squares out = odr.run() print('\nbilinear auto\n') out.pprint() a = out.beta[0] b = out.beta[1] c = out.beta[2] hx = out.beta[3] # x hinge point y_range = b + a * x_range # get y values from bilinear yhinge = b + a * hx idx = x_range > hx y_range[idx] = c * (x_range[idx]-hx) + yhinge return y_range, x_range
def least(func, x, y, sy=None, beta0=None, ifixb=None, fjacb=None): linear = odrpack.Model(func, fjacb=fjacb) #mydata = odrpack.Data(x, z[1], wd=1./np.power(z[2],2), we=1./np.power(sy,2)) mydata = odrpack.RealData(x, y, sy=sy) myodr = odrpack.ODR(mydata, linear, beta0=beta0, ifixb=ifixb) myodr.set_job(fit_type=2) myoutput = myodr.run() # myoutput.pprint() return myodr.output
def ws_correlation_orthoginal_distance_model(data, ref_ws_col='ref', site_ws_col='site', force_through_origin=False): """Calculate the slope and offset between two wind speed columns using orthoganal distance regression. https://docs.scipy.org/doc/scipy-0.18.1/reference/odr.html :Parameters: data: DataFrame DataFrame with wind speed columns ref and site, and direction data dir ref_ws_col: string, default None (primary anemometer assumed) Reference anemometer data to use. Extracted from MetMast.data site_ws_col: string, default None (primary anemometer assumed) Site anemometer data to use. Extracted from MetMast.data force_through_origin: boolean, default False Force the correlation through the origin (offset equal to zero) :Returns: out: DataFrame slope, offset, R2, uncert, points """ data = data.loc[:, [ref_ws_col, site_ws_col]].dropna().astype(np.float) results = return_correlation_results_frame(ref_label=ref_ws_col, site_label=site_ws_col) if not valid_ws_correlation_data(data=data, ref_ws_col=ref_ws_col, site_ws_col=site_ws_col): return results points = data.shape[0] R2 = calculate_R2(data=data, ref_ws_col=ref_ws_col, site_ws_col=site_ws_col) uncert = calculate_IEC_uncertainty(data=data, ref_ws_col=ref_ws_col, site_ws_col=site_ws_col) X = data.loc[:, ref_ws_col].values Y = data.loc[:, site_ws_col].values data_mean = data.mean() slope_estimate_via_ratio = data_mean[site_ws_col] / data_mean[ref_ws_col] realdata = odrpack.RealData(X, Y) if force_through_origin: linear = odrpack.Model(f_without_offset) odr = odrpack.ODR(realdata, linear, beta0=[slope_estimate_via_ratio]) slope = odr.run().beta[0] offset = 0 else: linear = odrpack.Model(f_with_offset) odr = odrpack.ODR(realdata, linear, beta0=[slope_estimate_via_ratio, 0.0]) slope, offset = odr.run().beta[0], odr.run().beta[1] results.loc[pd.IndexSlice[ref_ws_col, site_ws_col], ['slope', 'offset', 'R2', 'uncert', 'points']] = np.array( [slope, offset, R2, uncert, points]) return results
def fitScipyODR(xdata, ydata, xerr, yerr, func, pInit): """ Fit a series of data points with ODR (function must be in from f(beta[n], x)) """ model = odrpack.Model(func) data = odrpack.RealData(xdata, ydata, sx=xerr, sy=yerr) odr = odrpack.ODR(data, model, beta0=pInit) out = odr.run() popt = out.beta pcov = out.cov_beta out.pprint() print('Chi square = %f' % out.sum_square) return popt, pcov
def do_odr(f, x, xe, y, ye, estimates): model = odrpack.Model(f) # sx and sy should be the covariances data = odrpack.RealData(x, y, sx=xe, sy=ye) # need to hard-code in estimates for parameters odr = odrpack.ODR(data, model, estimates) output = odr.run() return output
def estimate_spectra(self): from scipy.odr import odrpack as odr def ofunc(pars, x, sp_sens, nu, el): a, b, dkalpha, tele = pars spectra = a * Kalpha_profile(el, nu, dkalpha) + b * ff_profile( nu, tele) spectra /= np.trapz(spectra, nu) spectra = np.tile(spectra, (sp_sens.shape[0], 1)) comp_tr = np.trapz(sp_sens * spectra, nu, axis=-1) return comp_tr def ofunc2(pars, thick, nu, el): spectra = compute_spectra(pars, nu) sp_tr_filters = np.ones(nu.shape) for filt_el, filt_thick in self.filters.iteritems(): sp_tr_filters *= np.exp(-cold_opacity(filt_el, nu=nu) * filt_thick) ip_sens = ip_sensitivity(nu) comp_tr = [] for this_thick in thick: sp_sens = np.exp(-cold_opacity(el, nu=nu)*this_thick)\ * sp_tr_filters * ip_sens * spectra comp_tr.append(np.trapz(sp_sens, nu, axis=0)) return np.array(comp_tr).reshape((1, -1)) #return ((comp_tr - exp_tr)**2).sum() beta0 = [1, 1, 100, 1000] my_data = odr.RealData(self.thick, self.exp_tr, sy=0.05 * np.ones(self.exp_tr.shape)) my_model = odr.Model(ofunc2, extra_args=(self.nu, 'polystyrene')) my_odr = odr.ODR(my_data, my_model, beta0=beta0) my_odr.set_job(fit_type=2) my_odr.set_iprint(final=2, iter=1, iter_step=1) fit = my_odr.run() self.beta = fit.beta #[::-1] self.sdbeta = fit.sd_beta #[::-1] print(ofunc2(self.beta, self.thick, self.nu, 'polystyrene')) print(self.exp_tr) print('\n') print(beta0) print(self.beta)
def nominal_AB(self, K, N, T, explore_mag=10, res_time=100): ''' Estimates matrices A and B Args: K: The controller gain N: number of iterations to be consistent with iterative methods T: Rollout length explore_mag: noise magnitude for excitement res_time: when to reset the dynamics to its initial condition Returns: A_nom, B_nom ''' Lin_gain = LinK(K) Lin_gain.make_sampling_on(explore_mag) if T >= res_time: N = int(np.ceil(N * T / res_time)) T = res_time A_nom = np.zeros((self.n, self.n)) B_nom = np.zeros((self.n, self.m)) # storage matrices states_batch = np.zeros((self.n, N, T)) next_states_batch = np.zeros((self.n, N, T)) actions_batch = np.zeros((self.m, N, T)) # simulate for k in range(N): # Do one rollout to save data for model estimation states, actions, _, next_states = self.dyn.one_rollout(Lin_gain.sample_lin_policy, T) states_batch[:, k, :] = states.T actions_batch[:, k, :] = actions.T next_states_batch[:, k, :] = next_states.T for i in range(self.n): linear = odrpack.Model(linear_func) data = odrpack.RealData( x=np.vstack((states_batch.reshape(self.n, N * T), actions_batch.reshape(self.m, N * T))), y=next_states_batch[i, :, :].reshape(1, N * T)) Myodr = odrpack.ODR(data, linear, np.zeros(self.n + self.m)) out = Myodr.run() tmp = out.beta A_nom[i, :] = tmp[0:self.n] B_nom[i, :] = tmp[self.n:] return A_nom, B_nom
def fitSingleCrystalBallPeak(self): params = np.array([ self.peak1_paramsEdits[0].value(), self.peak1_paramsEdits[1].value(), self.peak1_paramsEdits[2].value(), self.peak1_paramsEdits[3].value(), 0.9, 4 ]) model = odr.Model(lineshape.Single_Crystalball) odr_data = odr.RealData(self.x_cut, self.y_cut) #, sy = np.sqrt(self.y_cut)) myodr = odr.ODR(odr_data, model, beta0=params) myodr.set_job(fit_type=0) myoutput = myodr.run() self.params = myoutput.beta params_cov = myoutput.cov_beta params_output = [] params_red_chi2 = myoutput.res_var content, error = integrate.quad(lineshape.Single_Crystalball_integrand, self.x_fit[0], self.x_fit[-1], args=tuple(self.params)) params_output.append(content) params_output.append(params_red_chi2) self.params_outputs = np.array(params_output) for i in range(len(self.peak1_paramsEdits)): self.peak1_paramsEdits[i].setValue(self.params[i]) self.peak1_contentEdit.setText(str(self.params_outputs[0])) self.peak1_chi2Edit.setText(str(self.params_outputs[1])) self.plotWidget.plot(clear=True) self.plotWidget.plot(self.x, self.y[:-1], stepMode=True) fitPen = pg.mkPen(color=(204, 0, 0), width=2) self.plotWidget.plot(self.x_fit, lineshape.Single_Crystalball( self.params, self.x_fit), pen=fitPen) self.plotWidget.addItem(self.vLine, ignoreBounds=True) self.plotWidget.addItem(self.hLine, ignoreBounds=True)
def fit2(data,interval,init): interval.sort() nData = data[(data[:,0] > interval[0])&(data[:,0] < interval[1])] x=nData[:,0] y=nData[:,1] sx=None sy=None try: sx = nData[:,2] sy = nData[:,3] except: pass def func(B,x): return (1/B[0]) * x linear = odrpack.Model(func) mydata = odrpack.RealData(x, y, sx=sx, sy=sy) myodr = odrpack.ODR(mydata, linear, beta0=[init]) myoutput = myodr.run() myoutput.pprint() return [myoutput.beta[0],myoutput.sd_beta[0]]
def fit_tls(x: np.ndarray, y: np.ndarray) -> float: """Fit total least squares model to data This function fits a total least squares (also known as orthogonal distance regression) model to 2-dimensional data. The model has the form `y = m * x`, where m is the "slope". (It has an intercept at y==0). See Also: At its core, the function uses scipy's `Orthogonal Distance Regression`_ module .. _Orthogonal Distance Regression: https://docs.scipy.org/doc/scipy/reference/odr.html Args: x: 1-dimensional Numpy array y: 1-dimensional Numpy array of the same size as `x` Returns: The slope of the fitted model """ odr_data = odrpack.RealData(x, y) model = odrpack.Model(lambda beta, x_: beta[0] * x_) odr_container = odrpack.ODR(odr_data, model, beta0=[1.0]) slope = odr_container.run().beta[0] #TODO PLOT SECTOR 0 some pairs (weird results) return slope
def ODRfit(model, X, Y, p0, verbose=False): if type(p0) != 'numpy.ndarray': try: p0, up0 = unpack_unarray(p0) except TypeError: pass x, ux = unpack_unarray(X) y, uy = unpack_unarray(Y) modello = odrpack.Model(model) data = odrpack.RealData(x, y, sx=ux, sy=uy) engine = odrpack.ODR(data, modello, beta0=p0) output = engine.run() P = unc.correlated_values(output.beta, output.cov_beta) if verbose: output.pprint() return P, output.sum_square
infile = sys.argv[1] outfile = sys.argv[2] dataframe = pd.read_pickle(infile) def f(params, x): rho_per, rho_par, shift = params return rho_per + (rho_par - rho_per) * np.cos(x - shift)**2 slice = dataframe.loc[dataframe.current == CURRENT] R_S = "Sample Resistance, R_S (Ohmns)" R_S_E = "Error in R_S, alpha_R_S (Ohms)" A = "Angle, theta (degrees)" A_E = "Error in theta, alpha_theta (degrees)" xs = slice[A] * np.pi / 180 ys = slice[R_S] sx = slice[A_E] * np.pi / 180 sy = slice[R_S_E] beta0 = [0., 2., 0.] linear = odrpack.Model(f) mydata = odrpack.RealData(xs, ys, sx=sx, sy=sy) myodr = odrpack.ODR(mydata, linear, beta0, maxit=100) myoutput = myodr.run() fig, ax = plt.subplots() ax.scatter(xs, ys, marker="+") ax.plot(xs, f(myoutput.beta, xs)) fig.savefig(outfile)
## ## Test orth. regression ## ################################################################################ def f(B, theta1): return B[0] * (np.cos((2*np.pi)/360*theta1))**2 + B[1] x = theta1 y = a1 sx = theta2 sy = a2 linear = odrpack.Model(f) myData = odrpack.RealData(x, y, sx=sx, sy=sy) myOdr = odrpack.ODR(myData, linear , beta0=[1,1]) myOdr.set_job(fit_type=2) #if set fit_type=2, returns the same as leastsq out = myOdr.run() #out.pprint() coeff = out.beta[::-1] err = out.sd_beta[::-1] print(coeff[0], err[0]) print(coeff[1], err[1]) ################################################################################
stdp[x, :, :] = np.std(np.fft.ifft(np.fft.fft(temp) * noise_mask), -1) # Reshape variables into a single column mag = np.reshape( mag, (-1, nt)) # Reshapes variable intro 2D matrix of voxels x timepoints ph = np.reshape(ph, (-1, nt)) stdm = np.reshape( stdm, (-1, )) # Reshapes variable intro array of length = number of voxels stdp = np.reshape(stdp, (-1, )) mask = np.reshape(mask, (-1, )) for x in range(mag.shape[0]): if mask[x]: design = ph[x, :] ests = [stdm[x] / stdp[x], 1.0] mydata = odr.RealData(design, mag[x, :], sx=stdp[x], sy=stdm[x]) odr_obj = odr.ODR(mydata, linearfit, beta0=ests, maxit=600) res = odr_obj.run() est = res.y r2[x] = 1.0 - (np.sum((mag[x, :] - est)**2) / np.sum((mag[x, :])**2)) # take out scaled phase signal and re-mean may need correction sim[x, :] = ph[x, :] * res.beta[0] filt[x, :] = mag[x, :] - est # estimate residuals residuals[x, :] = np.sign(mag[x, :] - est) * ( np.sum(res.delta**2, axis=0) + res.eps**2) delta[x, :] = np.sum( res.delta, axis=0 ) # res.delta --> Array of estimated errors in input variables (same shape as x)
print(linfit3) #[ 2.34733290e-07 -6.08446455e-05] #[ 2.62854976e-07 -8.24342656e-05] #[ 2.58426791e-07 -7.77971621e-05] def f(B, x): return B[0] * x + B[1] linear = odrpack.Model(f) #for i in range(0): mydata1 = odrpack.RealData(druck[0], brechungsindex[0], sx=Er_druck[0], sy=Er_brech[0]) mydata2 = odrpack.RealData(druck[1], brechungsindex[1], sx=Er_druck[1], sy=Er_brech[1]) mydata3 = odrpack.RealData(druck[2], brechungsindex[2], sx=Er_druck[2], sy=Er_brech[2]) myodr1 = odrpack.ODR(mydata1, linear, beta0=[1., 2.]) myodr2 = odrpack.ODR(mydata2, linear, beta0=[1., 2.]) myodr3 = odrpack.ODR(mydata3, linear, beta0=[1., 2.]) myoutput1 = myodr1.run() myoutput2 = myodr2.run() myoutput3 = myodr3.run()
def peak_fit(xdata, ydata, iparams=[], peaktype='Gauss', maxit=300, background='constant', plot=False, func_out=False, debug=False): """ fit function using odr-pack wrapper in scipy similar to https://github.com/tiagopereira/python_tips/wiki/Scipy%3A-curve-fitting for Gauss, Lorentz or Pseudovoigt-functions Parameters ---------- xdata: xcoordinates of the data to be fitted ydata: ycoordinates of the data which should be fit keyword parameters: iparams: initial paramters for the fit, determined automatically if not specified peaktype: type of peak to fit: 'Gauss', 'Lorentz', 'PseudoVoigt', 'PseudoVoigtAsym' maxit: maximal iteration number of the fit background: type of background, either 'constant' or 'linear' plot: flag to ask for a plot to visually judge the fit. If plot is a string it will be used as figure name, which makes reusing the figures easier. func_out: returns the fitted function, which takes the independent variables as only argument (f(x)) Returns ------- params,sd_params,itlim[,fitfunc] the parameters as defined in function Gauss1d/Lorentz1d/PseudoVoigt1d/ PseudoVoigt1dasym(x, *param). In the case of linear background one more parameter is included! For every parameter the corresponding errors of the fit 'sd_params' are returned. A boolean flag 'itlim', which is False in the case of a successful fit is added by default. Further the function used in the fit can be returned (see func_out). """ if plot: try: from matplotlib import pyplot as plt except ImportError: if config.VERBOSITY >= config.INFO_ALL: print("XU.math.peak_fit: Warning: plot " "functionality not available") plot = False gfunc, gfunc_dx, gfunc_dp = _getfit_func(peaktype, background) # determine initial parameters _check_iparams(iparams, peaktype, background) if not any(iparams): iparams = _guess_iparams(xdata, ydata, peaktype, background) if config.VERBOSITY >= config.DEBUG: print("XU.math.peak_fit: iparams: %s" % str(tuple(iparams))) # set up odr fitting peak = odr.Model(gfunc, fjacd=gfunc_dx, fjacb=gfunc_dp) sy = numpy.sqrt(ydata) sy[sy == 0] = 1 mydata = odr.RealData(xdata, ydata, sy=sy) myodr = odr.ODR(mydata, peak, beta0=iparams, maxit=maxit) myodr.set_job(fit_type=2) # use least-square fit fit = myodr.run() if config.VERBOSITY >= config.DEBUG: print('XU.math.peak_fit:') fit.pprint() # prints final message from odrpack fparam = fit.beta if peaktype in ('PseudoVoigt', 'PseudoVoigtAsym'): if background == 'linear': etaidx = -2 else: etaidx = -1 fparam[etaidx] = 0 if fparam[etaidx] < 0 else fparam[etaidx] fparam[etaidx] = 1 if fparam[etaidx] > 1 else fparam[etaidx] itlim = False if fit.stopreason[0] == 'Iteration limit reached': itlim = True if config.VERBOSITY >= config.INFO_LOW: print("XU.math.peak_fit: Iteration limit reached, " "do not trust the result!") if plot: if isinstance(plot, basestring): plt.figure(plot) else: plt.figure('XU:peak_fit') plt.plot(xdata, ydata, 'ko', label='data', mew=2) if debug: plt.plot(xdata, gfunc(iparams, xdata), '-', color='0.5', label='estimate') plt.plot(xdata, gfunc(fparam, xdata), 'r-', label='%s-fit' % peaktype) plt.legend() if func_out: return fparam, fit.sd_beta, itlim, lambda x: gfunc(fparam, x) else: return fparam, fit.sd_beta, itlim
medbin = delete(medbin, delidx) binstrp = delete(binstrp, delidx) stdbin = delete(stdbin, delidx) ''' if mb == 4.25: print(len(mmi[idx])) print(log10(rrup[idx])) print(medbin, binstrp) print(eqname[idx]) crash ''' if len(medbin < 2) and mb != 4.25: # get intercept data = odrpack.RealData(binstrp, medbin) intfit = odrpack.Model(linear_fixed_slope) odr = odrpack.ODR(data, intfit, beta0=[5.0]) #data = odrpack.RealData(10**binstrp, medbin, meta={'mag':mb}) #intfit = odrpack.Model(near_src_trunc_fixed_slope) #odr = odrpack.ODR(data, intfit, beta0=[5.0]) odr.set_job(fit_type=2) #if set fit_type=2, returns the same as leastsq, 0=ODR out = odr.run() intercept = out.beta intercepts.append(intercept[0]) meanmagbin.append(mean(mmi[idx])) meanmws.append(mean(mw[idx])) else: intercepts.append(nan)
def peak_fit(xdata, ydata, iparams=[], peaktype='Gauss', maxit=300, background='constant', plot=False, func_out=False, debug=False): """ fit function using odr-pack wrapper in scipy similar to https://github.com/tiagopereira/python_tips/wiki/Scipy%3A-curve-fitting for Gauss, Lorentz or Pseudovoigt-functions Parameters ---------- xdata : array_like x-coordinates of the data to be fitted ydata : array_like y-coordinates of the data which should be fit iparams : list, optional initial paramters, determined automatically if not specified peaktype : {'Gauss', 'Lorentz', 'PseudoVoigt', 'PseudoVoigtAsym', 'PseudoVoigtAsym2'}, optional type of peak to fit maxit : int, optional maximal iteration number of the fit background : {'constant', 'linear'}, optional type of background function plot : bool or str, optional flag to ask for a plot to visually judge the fit. If plot is a string it will be used as figure name, which makes reusing the figures easier. func_out : bool, optional returns the fitted function, which takes the independent variables as only argument (f(x)) Returns ------- params : list the parameters as defined in function `Gauss1d/Lorentz1d/PseudoVoigt1d/ PseudoVoigt1dasym`. In the case of linear background one more parameter is included! sd_params : list For every parameter the corresponding errors are returned. itlim : bool flag to tell if the iteration limit was reached, should be False fitfunc : function, optional the function used in the fit can be returned (see func_out). """ if plot: plot, plt = utilities.import_matplotlib_pyplot('XU.math.peak_fit') gfunc, gfunc_dx, gfunc_dp = _getfit_func(peaktype, background) # determine initial parameters _check_iparams(iparams, peaktype, background) if not any(iparams): iparams = _guess_iparams(xdata, ydata, peaktype, background) if config.VERBOSITY >= config.DEBUG: print("XU.math.peak_fit: iparams: %s" % str(tuple(iparams))) # set up odr fitting peak = odr.Model(gfunc, fjacd=gfunc_dx, fjacb=gfunc_dp) sy = numpy.sqrt(ydata) sy[sy == 0] = 1 mydata = odr.RealData(xdata, ydata, sy=sy) myodr = odr.ODR(mydata, peak, beta0=iparams, maxit=maxit) myodr.set_job(fit_type=2) # use least-square fit fit = myodr.run() if config.VERBOSITY >= config.DEBUG: print('XU.math.peak_fit:') fit.pprint() # prints final message from odrpack fparam = fit.beta etaidx = [] if peaktype in ('PseudoVoigt', 'PseudoVoigtAsym'): if background == 'linear': etaidx = [-2, ] else: etaidx = [-1, ] elif peaktype == 'PseudoVoigtAsym2': etaidx = [5, 6] for e in etaidx: fparam[e] = 0 if fparam[e] < 0 else fparam[e] fparam[e] = 1 if fparam[e] > 1 else fparam[e] itlim = False if fit.stopreason[0] == 'Iteration limit reached': itlim = True if config.VERBOSITY >= config.INFO_LOW: print("XU.math.peak_fit: Iteration limit reached, " "do not trust the result!") if plot: if isinstance(plot, str): plt.figure(plot) else: plt.figure('XU:peak_fit') plt.plot(xdata, ydata, 'ok', label='data', mew=2) if debug: plt.plot(xdata, gfunc(iparams, xdata), '-', color='0.5', label='estimate') plt.plot(xdata, gfunc(fparam, xdata), '-r', label='%s-fit' % peaktype) plt.legend() if func_out: return fparam, fit.sd_beta, itlim, lambda x: gfunc(fparam, x) else: return fparam, fit.sd_beta, itlim
ang = np.array([20, 40, 60, 80, 100, 120, 140, 160, 180]) x = np.round(np.sin(np.radians(ang / 2)), 2) y = (41, 48, 63, 76, 107, 111, 137, 162, 172) error = np.round(np.sqrt(y), 2) yerr1 = np.array(error) def f(p, x): B, c = p return B * x + c linear = odrpack.Model(f) mydata = odrpack.RealData(x, y, sy=yerr1) myodr = odrpack.ODR(mydata, linear, beta0=[0., 1.]) myoutput = myodr.run() myoutput.pprint() x_fit = np.linspace(x[0], x[-1], 100) y_fit = f(myoutput.beta, x_fit) plt.plot(x_fit, y_fit, label='ODR', lw=3, color='purple') plt.xlabel('Sin(Theta/2)[Degrees]') plt.ylabel('dN')
def multPeakFit(x, data, peakpos, peakwidth, dranges=None, peaktype='Gaussian'): """ function to fit multiple Gaussian/Lorentzian peaks with linear background to a set of data Parameters ---------- x: x-coordinate of the data data: data array with same length as x peakpos: initial parameters for the peak positions peakwidth: initial values for the peak width dranges: list of tuples with (min,max) value of the data ranges to use. does not need to have the same number of entries as peakpos peaktype: type of peaks to be used: can be either 'Gaussian' or 'Lorentzian' Returns ------- pos,sigma,amp,background pos: list of peak positions derived by the fit sigma: list of peak width derived by the fit amp: list of amplitudes of the peaks derived by the fit background: array of background values at positions x """ if peaktype == 'Gaussian': pfunc = Gauss1d pfunc_derx = Gauss1d_der_x elif peaktype == 'Lorentzian': pfunc = Lorentz1d pfunc_derx = Lorentz1d_der_x else: raise ValueError('wrong value for parameter peaktype was given') def deriv_x(p, x): """ function to calculate the derivative of the signal of multiple peaks and background w.r.t. the x-coordinate p: list of parameters, for every peak there needs to be position, sigma, amplitude and at the end two values for the linear background function (b0,b1) x: x-coordinate """ derx = numpy.zeros(x.size) # sum up peak functions contributions for i in range(len(p) // 3): ldx = pfunc_derx(x, p[3 * i], p[3 * i + 1], p[3 * i + 2], 0) derx += ldx # background contribution k = p[-2] d = p[-1] b = numpy.ones(x.size) * k return derx + b def deriv_p(p, x): """ function to calculate the derivative of the signal of multiple peaks and background w.r.t. the parameters p: list of parameters, for every peak there needs to be position, sigma, amplitude and at the end two values for the linear background function (b0,b1) x: x-coordinate returns derivative w.r.t. all the parameters with shape (len(p),x.size) """ derp = numpy.empty(0) # peak functions contributions for i in range(len(p) // 3): lp = (p[3 * i], p[3 * i + 1], p[3 * i + 2], 0) if peaktype == 'Gaussian': derp = numpy.append(derp, -2 * (lp[0] - x) * pfunc(x, *lp)) derp = numpy.append( derp, (lp[0] - x) ** 2 / (2 * lp[1] ** 3) * pfunc(x, *lp)) derp = numpy.append(derp, pfunc(x, *lp) / lp[2]) else: # Lorentzian derp = numpy.append(derp, 4 * (x - lp[0]) * lp[2] / lp[1] / (1 + (2 * (x - lp[0]) / lp[1]) ** 2) ** 2) derp = numpy.append(derp, 4 * (lp[0] - x) * lp[2] / lp[1] ** 2 / (1 + (2 * (x - lp[0]) / lp[1]) ** 2) ** 2) derp = numpy.append(derp, 1 / (1 + (2 * (x - p[0]) / p[1]) ** 2)) # background contributions derp = numpy.append(derp, x) derp = numpy.append(derp, numpy.ones(x.size)) # reshape output derp.shape = (len(p),) + x.shape return derp def fsignal(p, x): """ function to calculate the signal of multiple peaks and background p: list of parameters, for every peak there needs to be position, sigma, amplitude and at the end two values for the linear background function (k,d) x: x-coordinate """ f = numpy.zeros(x.size) # sum up peak functions for i in range(len(p) // 3): lf = pfunc(x, p[3 * i], p[3 * i + 1], p[3 * i + 2], 0) f += lf # background k = p[-2] d = p[-1] b = numpy.polyval((k, d), x) return f + b ########################## # create local data set (extract data ranges) if dranges: mask = numpy.array([False] * x.size) for i in range(len(dranges)): lrange = dranges[i] lmask = numpy.logical_and(x > lrange[0], x < lrange[1]) mask = numpy.logical_or(mask, lmask) lx = x[mask] ldata = data[mask] else: lx = x ldata = data # create initial parameter list p = [] # background k, d = numpy.polyfit(lx, ldata, 1) # peak parameters for i in range(len(peakpos)): amp = ldata[(lx - peakpos[i]) >= 0][0] - \ numpy.polyval((k, d), lx)[(lx - peakpos[i]) >= 0][0] p += [peakpos[i], peakwidth[i], amp] # background parameters p += [k, d] if(config.VERBOSITY >= config.DEBUG): print("XU.math.multGaussFit: intial parameters") print(p) ########################## # fit with odrpack model = odr.Model(fsignal, fjacd=deriv_x, fjacb=deriv_p) odata = odr.RealData(lx, ldata) my_odr = odr.ODR(odata, model, beta0=p) # fit type 2 for least squares my_odr.set_job(fit_type=2) fit = my_odr.run() if(config.VERBOSITY >= config.DEBUG): print("XU.math.multPeakFit: fitted parameters") print(fit.beta) try: if fit.stopreason[0] not in ['Sum of squares convergence']: print("XU.math.multPeakFit: fit NOT converged (%s)" % fit.stopreason[0]) return None, None, None, None except: print("XU.math.multPeakFit: fit most probably NOT converged (%s)" % str(fit.stopreason)) return None, None, None, None # prepare return values fpos = fit.beta[:-2:3] fwidth = numpy.abs(fit.beta[1:-2:3]) famp = fit.beta[2::3] background = numpy.polyval((fit.beta[-2], fit.beta[-1]), x) return fpos, fwidth, famp, background
def multPeakFit(x, data, peakpos, peakwidth, dranges=None, peaktype='Gaussian', returnerror=False): """ function to fit multiple Gaussian/Lorentzian peaks with linear background to a set of data Parameters ---------- x : array-like x-coordinate of the data data : array-like data array with same length as `x` peakpos : list initial parameters for the peak positions peakwidth : list initial values for the peak width dranges : list of tuples list of tuples with (min, max) value of the data ranges to use. does not need to have the same number of entries as peakpos peaktype : {'Gaussian', 'Lorentzian'} type of peaks to be used returnerror : bool decides if the fit errors of pos, sigma, and amp are returned (default: False) Returns ------- pos : list peak positions derived by the fit sigma : list peak width derived by the fit amp : list amplitudes of the peaks derived by the fit background : array-like background values at positions `x` if returnerror == True: sd_pos : list standard error of peak positions as returned by scipy.odr.Output sd_sigma : list standard error of the peak width sd_amp : list standard error of the peak amplitude """ warnings.warn("deprecated function -> use the lmfit Python packge instead", DeprecationWarning) if peaktype == 'Gaussian': pfunc = Gauss1d pfunc_derx = Gauss1d_der_x elif peaktype == 'Lorentzian': pfunc = Lorentz1d pfunc_derx = Lorentz1d_der_x else: raise ValueError('wrong value for parameter peaktype was given') def deriv_x(p, x): """ function to calculate the derivative of the signal of multiple peaks and background w.r.t. the x-coordinate Parameters ---------- p : list parameters, for every peak there needs to be position, sigma, amplitude and at the end two values for the linear background function (b0, b1) x : array-like x-coordinate """ derx = numpy.zeros(x.size) # sum up peak functions contributions for i in range(len(p) // 3): ldx = pfunc_derx(x, p[3 * i], p[3 * i + 1], p[3 * i + 2], 0) derx += ldx # background contribution k = p[-2] b = numpy.ones(x.size) * k return derx + b def deriv_p(p, x): """ function to calculate the derivative of the signal of multiple peaks and background w.r.t. the parameters Parameters ---------- p : list parameters, for every peak there needs to be position, sigma, amplitude and at the end two values for the linear background function (b0, b1) x : array-like x-coordinate returns derivative w.r.t. all the parameters with shape (len(p),x.size) """ derp = numpy.empty(0) # peak functions contributions for i in range(len(p) // 3): lp = (p[3 * i], p[3 * i + 1], p[3 * i + 2], 0) if peaktype == 'Gaussian': derp = numpy.append(derp, -2 * (lp[0] - x) * pfunc(x, *lp)) derp = numpy.append( derp, (lp[0] - x) ** 2 / (2 * lp[1] ** 3) * pfunc(x, *lp)) derp = numpy.append(derp, pfunc(x, *lp) / lp[2]) else: # Lorentzian derp = numpy.append(derp, 4 * (x - lp[0]) * lp[2] / lp[1] / (1 + (2 * (x - lp[0]) / lp[1]) ** 2) ** 2) derp = numpy.append(derp, 4 * (lp[0] - x) * lp[2] / lp[1] ** 2 / (1 + (2 * (x - lp[0]) / lp[1]) ** 2) ** 2) derp = numpy.append(derp, 1 / (1 + (2 * (x - p[0]) / p[1]) ** 2)) # background contributions derp = numpy.append(derp, x) derp = numpy.append(derp, numpy.ones(x.size)) # reshape output derp.shape = (len(p),) + x.shape return derp def fsignal(p, x): """ function to calculate the signal of multiple peaks and background Parameters ---------- p : list list of parameters, for every peak there needs to be position, sigma, amplitude and at the end two values for the linear background function (k, d) x : array-like x-coordinate """ f = numpy.zeros(x.size) # sum up peak functions for i in range(len(p) // 3): lf = pfunc(x, p[3 * i], p[3 * i + 1], p[3 * i + 2], 0) f += lf # background k = p[-2] d = p[-1] b = numpy.polyval((k, d), x) return f + b ########################## # create local data set (extract data ranges) if dranges: mask = numpy.array([False] * x.size) for i in range(len(dranges)): lrange = dranges[i] lmask = numpy.logical_and(x > lrange[0], x < lrange[1]) mask = numpy.logical_or(mask, lmask) lx = x[mask] ldata = data[mask] else: lx = x ldata = data # create initial parameter list p = [] # background # exclude +/-2 peakwidth around the peaks bmask = numpy.ones_like(lx, dtype=bool) for pp, pw in zip(peakpos, peakwidth): bmask = numpy.logical_and(bmask, numpy.logical_or(lx < (pp-2*pw), lx > (pp+2*pw))) if numpy.any(bmask): k, d = numpy.polyfit(lx[bmask], ldata[bmask], 1) else: if(config.VERBOSITY >= config.DEBUG): print("XU.math.multPeakFit: no data outside peak regions!") k, d = (0, ldata.min()) # peak parameters for i in range(len(peakpos)): amp = ldata[(lx - peakpos[i]) >= 0][0] - \ numpy.polyval((k, d), lx)[(lx - peakpos[i]) >= 0][0] p += [peakpos[i], peakwidth[i], amp] # background parameters p += [k, d] if(config.VERBOSITY >= config.DEBUG): print("XU.math.multPeakFit: intial parameters") print(p) ########################## # fit with odrpack model = odr.Model(fsignal, fjacd=deriv_x, fjacb=deriv_p) odata = odr.RealData(lx, ldata) my_odr = odr.ODR(odata, model, beta0=p) # fit type 2 for least squares my_odr.set_job(fit_type=2) fit = my_odr.run() if(config.VERBOSITY >= config.DEBUG): print("XU.math.multPeakFit: fitted parameters") print(fit.beta) try: if fit.stopreason[0] not in ['Sum of squares convergence']: print("XU.math.multPeakFit: fit NOT converged (%s)" % fit.stopreason[0]) return Nono, None, None, None except IndexError: print("XU.math.multPeakFit: fit most probably NOT converged (%s)" % str(fit.stopreason)) return None, None, None, None # prepare return values fpos = fit.beta[:-2:3] fwidth = numpy.abs(fit.beta[1:-2:3]) famp = fit.beta[2::3] background = numpy.polyval((fit.beta[-2], fit.beta[-1]), x) if returnerror: sd_pos = fit.sd_beta[:-2:3] sd_width = fit.sd_beta[1:-2:3] sd_amp = fit.sd_beta[2::3] return fpos, fwidth, famp, background, sd_pos, sd_width, sd_amp return fpos, fwidth, famp, background
mb = np.array(mb) mw = np.array(mw) idx_src = np.array(idx) # Mw = np.array([x[3] for x in cat]) # Ml_pre = np.array([x[4] for x in cat]) # Ml_rev = np.array([x[5] for x in cat]) # Mw_ref = np.array([x[6] for x in cat]) # # idx1 = np.where(Mw_ref=='HG')[0] # idx2 = np.where(Mw_ref=='TA-SEA')[0] # idx3 = np.where(Mw_ref=='TA-WA')[0] # idx4 = np.where(Mw_ref=='other')[0] ############### bilinear auto data = odrpack.RealData(mb[mb >= 3.5], mw[mb >= 3.5]) sx = np.interp(mw, [min(mw), max(mw)], [0.3, 0.1]) sy = sx data = odrpack.RealData(mb[mb >= 3.5], mw[mb >= 3.5], sx=sx[mb >= 3.5], sy=sy[mb >= 3.5]) xrng = np.arange(3.5, 6.0, step=0.01) bilin_reg = odrpack.Model(bilinear_reg_free) odr = odrpack.ODR(data, bilin_reg, beta0=[0.7, 1.0, 1.0, 3.5]) odr.set_job(fit_type=0) #if set fit_type=2, returns the same as least squares out = odr.run() out.pprint()
#d1_array.append(d1) #d2_array.append(d2) #d3_array.append(d3) plt.semilogx(10**medx, logmedamp, 'rs', ms=6) ax.set_xscale('log') ############################################################################### # fit data ############################################################################### def fit_site_amp(c, x): return c[0] + c[1] / (x - log10(150)) #data = odrpack.RealData(medx, logmedamp) idx = where(isfinite(Yres))[0] data = odrpack.RealData(log10(vs30[idx]), Yres[idx]) sitefit = odrpack.Model(fit_site_amp) odr = odrpack.ODR(data, sitefit, beta0=[0.1, 0.]) odr.set_job( fit_type=2) #if set fit_type=2, returns the same as leastsq, 0=ODR out = odr.run() c = out.beta print(c) coefs1.append(c) # plot fit dx = arange(2., 3, 0.01) dy = c[0] + c[1] / (dx - log10(150)) #dy = d0 + d1*dx**3 + d2*dx**2 + d3*dx
# plot bi-linear interface cinter_len = 10**(lenc + lengrd1*mrng) idx = mrng > lenhmag ylen = lenc + lengrd1 * lenhmag cinter_len[idx] = 10**(lengrd2 * (mrng[idx]-lenhmag) + ylen) ''' h = plt.semilogy(mrng, cinter_len, 'k-', lw=2.0) hh = [h[0]] # fit lengths savec = [] tabtxt = 'Length\nType,a,SEa,b,sig,Range\n' for i in range(0, len(fmag)): data = odrpack.RealData(array(fmag[i]),log10(array(flen[i]))) grad = grads[0] lin = odrpack.Model(linear_reg_fix_slope) odr = odrpack.ODR(data, lin, beta0=[-2.]) odr.set_job(fit_type=0) #if set fit_type=2, returns the same as leastsq out = odr.run() out.pprint() c = out.beta[0] savec.append(c) regmrng = arange(min(fmag[i]), max(fmag[i])+0.01, 0.01) clen = 10**(c + grad * regmrng) print i h = plt.semilogy(regmrng, clen, '-', color=cs2[i+1], lw=2.0) hh.append(h[0])
def fit_function(w, F0, w0, gamma): #gamma = 0.01515 return F0 / pylab.sqrt((w0**2 - w**2)**2 + 4.0 * (gamma**2) * (w**2)) def fit_function_ODR(pars, w): #pars[2] = 0.01515 return pars[0] / pylab.sqrt((pars[1]**2 - w**2)**2 + 4.0 * (pars[2]**2) * (w**2)) # Run the actual ODR. model = odrpack.Model(fit_function_ODR) data = odrpack.RealData(s, x) odr = odrpack.ODR(data, model, beta0=(53.7, 4.7, 0.064)) out = odr.run() popt, pcov = out.beta, out.cov_beta F0, w0, gamma = popt dF0, dw0, dgamma = numpy.sqrt(pcov.diagonal()) chisq = out.sum_square # !Run the actual ODR. # Run the actual ODR. model = odrpack.Model(fit_function_ODR) data = odrpack.RealData(s, x) odr = odrpack.ODR(data, model, beta0=(F0, w0, gamma)) out = odr.run() popt, pcov = out.beta, out.cov_beta F0, w0, gamma = popt dF0, dw0, dgamma = numpy.sqrt(pcov.diagonal())
def fitDoubleCrystalBallPeak(self): params = np.array([ self.peak1_paramsEdits[0].value(), self.peak1_paramsEdits[1].value(), self.peak1_paramsEdits[2].value(), self.peak1_paramsEdits[3].value(), self.peak2_paramsEdits[0].value(), self.peak2_paramsEdits[1].value(), self.peak2_paramsEdits[2].value(), 0.9, 4 ]) model = odr.Model(lineshape.Double_Crystalball) odr_data = odr.RealData(self.x_cut, self.y_cut) #, sy = np.sqrt(self.y_cut)) myodr = odr.ODR(odr_data, model, beta0=params) myodr.set_job(fit_type=0) myoutput = myodr.run() self.params = myoutput.beta params_cov = myoutput.cov_beta params_output = [] params_red_chi2 = myoutput.res_var single_index = [0, 1, 2, 3, 7, 8] params_single = self.params[single_index] double_index = [4, 5, 6, 3, 7, 8] params_double = self.params[double_index] content1, error1 = integrate.quad( lineshape.Single_Crystalball_integrand, self.x_fit[0], self.x_fit[-1], args=tuple(params_single)) content2, error2 = integrate.quad( lineshape.Single_Crystalball_integrand, self.x_fit[0], self.x_fit[-1], args=tuple(params_double)) params_output.append(content1) params_output.append(params_red_chi2) params_output.append(content2) self.params_outputs = np.array(params_output) for i in range(len(self.params)): if i < 4: self.peak1_paramsEdits[i].setValue(self.params[i]) if 3 < i < 7: self.peak2_paramsEdits[i - 4].setValue(self.params[i]) self.peak1_contentEdit.setText(str(self.params_outputs[0])) self.peak1_chi2Edit.setText(str(self.params_outputs[1])) self.peak2_contentEdit.setText(str(self.params_outputs[2])) self.plotWidget.plot(clear=True) histo = pg.PlotCurveItem(self.x, self.y[:-1], stepMode=True) self.plotWidget.addItem(histo) if self.PeaksButton.isChecked() == False: fitPen = pg.mkPen(color=(204, 0, 0), width=2) self.plotWidget.plot(self.x_fit, lineshape.Double_Crystalball( self.params, self.x_fit), pen=fitPen) if self.PeaksButton.isChecked() == True: fitPen = pg.mkPen(color=(204, 0, 0), width=2, style=QtCore.Qt.DashLine) params1 = np.array([ self.peak1_paramsEdits[0].value(), self.peak1_paramsEdits[1].value(), self.peak1_paramsEdits[2].value(), self.peak1_paramsEdits[3].value(), 0.9, 4 ]) params2 = np.array([ self.peak2_paramsEdits[0].value(), self.peak2_paramsEdits[1].value(), self.peak2_paramsEdits[2].value(), self.peak1_paramsEdits[3].value(), 0.9, 4 ]) self.plotWidget.plot(self.x_fit, lineshape.Single_Crystalball( params1, self.x_fit), pen=fitPen) self.plotWidget.plot(self.x_fit, lineshape.Single_Crystalball( params2, self.x_fit), pen=fitPen) self.plotWidget.addItem(self.vLine, ignoreBounds=True) self.plotWidget.addItem(self.hLine, ignoreBounds=True)
if len(nidx) > 0: namps = log10(mamps) - logmedamp[nidx] if len(log_norm_amps) == 0: log_norm_amps = namps norm_rhyps = mrhyps else: log_norm_amps = hstack((log_norm_amps, namps)) norm_rhyps = hstack((norm_rhyps, mrhyps)) # regress mag-dependent data and get intercept didx = where((medx >= 2) & (medx <= 3.35))[0] data = odrpack.RealData(medx[didx], logmedamp[didx]) intfit = odrpack.Model(linear_fixed_slope) odr = odrpack.ODR(data, intfit, beta0=[5.0]) odr.set_job( fit_type=2) #if set fit_type=2, returns the same as leastsq, 0=ODR out = odr.run() intercept = out.beta if round(m, 1) != 4.9 and round(m, 1) != 5.5: #or round(m,1) > 6.6 m_intercept.append(intercept[0]) m_reg.append(m) xplt = array([2, 3]) yplt = meanslope * xplt + intercept[0]
def main(): # make output directory if not os.path.exists("output"): os.makedirs("output") # get data and caluclate reflectance n_pix = np.genfromtxt(s_filename, delimiter=",")[:, 0] i_s = np.genfromtxt(s_filename, delimiter=",")[:, 1] i_p = np.genfromtxt(p_filename, delimiter=",")[:, 1] i_bg = np.genfromtxt(bg_filename, delimiter=",")[:, 1] ref = (i_p - i_bg) / (i_s - i_bg) # find beam edges popt, pcov = curve_fit(gaus, n_pix, i_s, p0=[1, 1000, 50]) i_width = gaus(popt[1], *popt) / np.e**2 i_max = int(popt[1]) beam_lim = np.argmax( i_s[:i_max] - i_width > 0), len(n_pix) - np.argmax(i_s[:-i_max:-1] - i_width > 0) idx_centre = int(np.diff(beam_lim) / 2) + beam_lim[0] - 1 # plot raw data and threshold limits plt.figure(figsize=(8, 6)) plt.plot(n_pix, i_s, label="S polarised") plt.plot(n_pix, i_p, label="P polarised") plt.plot(n_pix, i_bg, label="Background") plt.plot(n_pix, gaus(n_pix, *popt), label="Gaussian") plt.plot(n_pix[idx_centre], i_width, "kx", ms=8) plt.plot((n_pix[beam_lim[1]], n_pix[beam_lim[0]]), (i_s[beam_lim[1]], i_s[beam_lim[0]]), "kx", ms=8) plt.text(n_pix[beam_lim[0]] + 20, i_width - 0.01, r"$n_{edge, low}$", ha="left", va="top") plt.text(n_pix[beam_lim[1]] + 20, i_width - 0.01, r"$n_{edge, up}$", ha="left", va="top") plt.text(n_pix[idx_centre] + 20, i_width - 0.01, r"$n_{centre}$", ha="left", va="top") plt.xlabel("Pixel number") plt.ylabel("Intensity") plt.title("S and P polarised intensities for sample 21") plt.legend() plt.show() # get range of angles and error n_pix_shift = np.arange(0, 2048, 1) - idx_centre correct = angle_offset(5) theta_range = beam_angle(n_pix_shift) + (t_prism * correct[0] + correct[1]) n_err = err_edge(np.sqrt(np.diagonal(pcov)), popt, i_width) theta_err = err_angle(n_pix_shift, n_err) err_red = theta_err[beam_lim[0]:beam_lim[1]] ref_red_ = ref[beam_lim[0]:beam_lim[1]] theta_red = theta_range[beam_lim[0]:beam_lim[1]] ref_red = ref_red_ / max(ref_red_[500:-500]) # moving average ref_av = moving_average(ref_red, n=n_av) theta_av = np.linspace(min(theta_red), max(theta_red), len(ref_av)) # fit whole reflectivity to asymmetric asymm = odr.Model(asymmetric) data_full = odr.RealData(theta_red, ref_red, sx=err_red) fit_asy_full = odr.ODR(data_full, asymm, beta0=[0.9, 0.4, 0.4, t_prism + 6, -0.6], maxit=100).run() ref_max = argrelextrema(asymmetric(fit_asy_full.beta, theta_red), np.greater)[0][0] # fit right side of reflectivity to asymmetric idx_asy = ref_max + delta_3 data_right = odr.RealData(theta_red[idx_asy:-400], ref_red[idx_asy:-400], sx=err_red[idx_asy:-400]) fit_asy = odr.ODR(data_right, asymm, beta0=[0.9, 0.4, 0.4, t_prism + 6, -0.6], maxit=100).run() r_sq_asy = 1 - fit_asy.res_var / np.var(ref_red[idx_asy:], ddof=1) data_asy = asymmetric(fit_asy.beta, theta_red) # fit left side of reflectivity to sigmoid sig = odr.Model(sigmoid) idx_sig = ref_max + delta_2 data_left = odr.RealData(theta_red[delta_1:idx_sig], ref_red[delta_1:idx_sig], sx=err_red[delta_1:idx_sig]) fit_sig = odr.ODR(data_left, sig, beta0=[0.15, -2.3, t_prism + 4, 0.8], maxit=100).run() r_sq_sig = 1 - fit_sig.res_var / np.var(ref_red[delta_1:idx_sig], ddof=1) data_sig = sigmoid(fit_sig.beta, theta_red) data_sig_asy = sig_asy( (*fit_asy.beta, *fit_sig.beta[:-1]), theta_red) - fit_sig.beta[0] # first derrivative of asymmetric-sigmoid a, b, c, d, e, f, g, h, x = sym.symbols("a b c d e f g h x") sym_fit = a * (1 - (b + c * (x - d)) / ((x - d)**2 + e**2)) + (f / (1 + sym.exp(g * (x - h)))) fit = sym.lambdify((a, b, c, d, e, f, g, h, x), sym_fit.diff(x), "numpy") d_fit = fit(*(*fit_asy.beta, *fit_sig.beta[:-1]), theta_red) # spr, critical angle, min reflectance and FWHM idx_spr = argrelextrema(data_sig_asy, np.less)[0][0] idx_crit = argrelextrema(d_fit, np.greater)[0][0] theta_spr = theta_red[idx_spr] spr_err = np.sqrt(err_red[idx_spr]**2) theta_crit = theta_red[idx_crit] crit_err = np.sqrt(err_red[idx_crit]**2) min_ref = data_sig_asy[idx_spr] err_min_ref = min_ref * np.linalg.norm( (*fit_sig.sd_beta / fit_sig.beta, *fit_asy.sd_beta / fit_asy.beta)) fwhm_1 = find_nearest(data_sig_asy[ref_max:idx_spr], data_sig_asy[ref_max] / 2) + ref_max fwhm_2 = find_nearest(data_sig_asy[idx_spr:], data_sig_asy[ref_max] / 2) + idx_spr fwhm = np.abs(theta_red[fwhm_2] - theta_red[fwhm_1]) err_fwhm = np.sqrt(err_red[fwhm_1]**2 + err_red[fwhm_2]**2) # plot ratio of s and p intensities, moving average and fitted curves if isinstance(prism_no, float): prism_no_str = str(int(prism_no)) + "a" else: prism_no_str = prism_no plt.figure(figsize=(8, 6)) plt.plot(theta_red, ref_red, "silver", label="Reflectance data") plt.plot(theta_red, data_sig_asy, label="Asymmetric-sigmoid") if details: plt.plot(theta_av, ref_av, label="Moving average, $n={}$".format(n_av)) plt.plot(theta_red, data_asy, label="Asymmetric") plt.plot(theta_red, data_sig, label="Sigmoid") plt.plot(theta_red, d_fit, label="1st derivative of \n asymmetric-sigmoid") plt.plot((theta_red[delta_1], theta_red[idx_sig]), (ref_red[delta_1], ref_red[idx_sig]), "s", label="Sigmoid data range") plt.plot((theta_red[idx_asy], theta_red[-1]), (ref_red[idx_asy], ref_red[-1]), "s", label="Asymmetric data range") plt.plot((theta_red[fwhm_1], theta_red[fwhm_2]), (ref_red[fwhm_1], ref_red[fwhm_2]), "s", label="FWHM limits") plt.plot(theta_crit, d_fit[idx_crit], "kx", ms=8) plt.plot(theta_spr, data_asy[idx_spr], "kx", ms=8) plt.plot(theta_red[ref_max], asymmetric(fit_asy.beta, theta_red)[ref_max], "kx", ms=8) plt.text(theta_crit + 0.2, d_fit[idx_crit] - 0.02, r"$\theta_{crit}$") plt.text(theta_spr + 0.2, data_asy[idx_spr] - 0.02, r"$\theta_{spr}$") plt.text(theta_red[ref_max] - 0.2, asymmetric(fit_asy.beta, theta_red)[ref_max] - 0.08, r"$\theta_{max}$") plt.xlim(theta_red[0], theta_red[-1]) plt.ylim(-0.1, 1.1) plt.xlabel(r"Incidence angle /$^\circ$") plt.ylabel("Normalised reflectance") plt.title("Reflectance plot for sample {}".format(prism_no_str)) plt.legend(loc=7) # formatted string containing the parameters text = """Sample {} on {}: \nprism angle {} deg\nsensor distance {} m\nSPR angle = {} +/- {} deg Critical angle = {} +/- {} deg \nR squared (asymmetric)= {} \nR squared (sigmoid)= {} Asymmetric parameters: {} \nAsymmetric parameter errors: {} \nSigmoid parameters: {} Sigmoid parameter errors: {} \nMinimum reflectance {} +/- {} \nFWHM {} +/- {} deg delta (1, 2, 3): {}, {}, {} \n""".format(prism_no_str, datetime.datetime.now().strftime("%d/%m/%y %H:%M"), t_prism, d_sens, theta_spr, spr_err, theta_crit, crit_err, r_sq_asy, r_sq_sig, fit_asy.beta, fit_asy.sd_beta, fit_sig.beta, fit_sig.sd_beta, min_ref, err_min_ref, fwhm, err_fwhm, delta_1, delta_2, delta_3) if export: # save figure plt.savefig(plotname, dpi=100, bbox_inches="tight") # log parameters file = open("log.txt", "w") file = open("output/log.txt", "a") file.write(text) file.close() # write data to csv np.savetxt(txtname, np.vstack((theta_red, ref_red)).T, delimiter=",", fmt="%f", header="theta,R") # write parameters to csv arr = [ prism_no, theta_spr, spr_err, theta_crit, crit_err, r_sq_asy, r_sq_sig, min_ref, err_min_ref, fwhm, err_fwhm ] with open("output/param.csv", "ab") as f: np.savetxt(f, arr, delimiter=",", newline=",", fmt="%f") f.write(b'\n') plt.show() print(text)