################################################################################################### # Least square optimization problem to fit a gaussian with offset ################################################################################################### from mathutils import * from plotutils import * run("CPython/GaussFit_wrapper") ################################################################################################### #Fitting the gaussian function with offset f(x) = a + b * exp(-(pow((x - c), 2) / (2 * pow(d, 2)))) ################################################################################################### camtool.start("Simulation") time.sleep(2.0) xdata =camtool.getValue("x_axis") ydata = camtool.getValue("x_profile") p = plot(ydata, "Data" , xdata)[0] p.setLegendVisible(True) def fit_gaussian_offset(y, x, start_point = None, weights = None): """Fits data into a gaussian with offset. f(x) = a + b * exp(-(pow((x - c), 2) / (2 * pow(d, 2)))) Args: x(float array or list): observed points x y(float array or list): observed points y start_point(optional tuple of float): initial parameters (normalization, mean, sigma) weights(optional float array or list): weight for each observed point Returns: Tuples of gaussian parameters: (offset, normalization, mean, sigma) """ # For normalised gauss curve sigma=1/(amp*sqrt(2*pi)) if start_point is None: off = min(y) # good enough starting point for offset com = x[y.index(max(y))] amp = max(y) - off sigma = trapz([v-off for v in y], x) / (amp*math.sqrt(2*math.pi)) start_point = [off, amp, com , sigma] class Model(MultivariateJacobianFunction): def value(self, variables): value = ArrayRealVector(len(x)) jacobian = Array2DRowRealMatrix(len(x), 4) for i in range(len(x)): (a,b,c,d) = (variables.getEntry(0), variables.getEntry(1), variables.getEntry(2), variables.getEntry(3)) v = math.exp(-(math.pow((x[i] - c), 2) / (2 * math.pow(d, 2)))) model = a + b * v value.setEntry(i, model) jacobian.setEntry(i, 0, 1) # derivative with respect to p0 = a jacobian.setEntry(i, 1, v) # derivative with respect to p1 = b v2 = b*v*((x[i] - c)/math.pow(d, 2)) jacobian.setEntry(i, 2, v2) # derivative with respect to p2 = c jacobian.setEntry(i, 3, v2*(x[i] - c)/d ) # derivative with respect to p3 = d return Pair(value, jacobian) model = Model() target = [v for v in y] #the target is to have all points at the positios (parameters, residuals, rms, evals, iters) = optimize_least_squares(model, target, start_point, weights) return parameters start = time.time() (off, amp, com, sigma) = fit_gaussian_offset(ydata, xdata, None, None) f = Gaussian(amp, com, sigma) gauss = [f.value(i)+off for i in xdata] s = LinePlotSeries("Fit with offset") p.addSeries(s) s.setData(to_array(xdata,'d'), to_array(gauss,'d')) error=0 for i in range(len(ydata)) : error += abs(ydata[i]-gauss[i]) print "\nFit with offset:\off: ", off , " amp: ", amp, " com: ", com, " sigma: ", sigma, " error: ", error print "Time: ",(time.time()-start) start = time.time() (amp, com, sigma) = fit_gaussian(ydata, xdata, None, None) f = Gaussian(amp, com, sigma) gauss = [f.value(i) for i in xdata] s = LinePlotSeries("Normal Fit") p.addSeries(s) s.setData(to_array(xdata,'d'), to_array(gauss,'d')) error=0 for i in range(len(ydata)) : error += abs(ydata[i]-gauss[i]) print "\nNormal fit:\amp: ", amp, " com: ", com, sigma, " error: ", error, " time: ", (time.time()-start) start = time.time() [off, amp, com, sigma] = gfitoff(xdata, ydata, off=None, amp=None, com=None, sigma=None) from mathutils import Gaussian g = Gaussian(amp, com, sigma) gauss = [g.value(i)+off for i in xdata] s = LinePlotSeries("CPython Fit") p.addSeries(s) s.setData(to_array(xdata,'d'), to_array(gauss,'d')) error=0 for i in range(len(ydata)) : error += abs(ydata[i]-gauss[i]) print "\nCPython Fit:\n", off , " amp: ", amp, " com: ", com, " sigma: ", sigma, error, " time: ", (time.time()-start) off = min(ydata) # good enough starting point for offset com = xdata[ydata.index(max(ydata))] amp = max(ydata) - off sigma = trapz([v-off for v in ydata], xdata) / (amp*math.sqrt(2*math.pi)) g = Gaussian(amp, com, sigma) gauss = [g.value(i)+off for i in xdata] s = LinePlotSeries("Start Point") p.addSeries(s) s.setData(to_array(xdata,'d'), to_array(gauss,'d')) error=0 for i in range(len(ydata)) : error += abs(ydata[i]-gauss[i]) print "\nStartPoint:\n", off , " amp: ", amp, " com: ", com, " sigma: ", sigma, error, " time: ", (time.time()-start) fit_point_list = create_fit_point_list(ydata, xdata, None) (amp, com, sigma) = GaussianCurveFitter.ParameterGuesser(fit_point_list).guess().tolist() gauss = [g.value(i)+off for i in xdata] s = LinePlotSeries("Default SP") p.addSeries(s) s.setData(to_array(xdata,'d'), to_array(gauss,'d')) error=0 for i in range(len(ydata)) : error += abs(ydata[i]-gauss[i]) print "\Default SP:\n", off , " amp: ", amp, " com: ", com, " sigma: ", sigma, error, " time: ", (time.time()-start)