def fit_mod(fc=0.01, mmax = 1e7): t0 = 0.1 delta_t = 0.5 mmin = log10(200.) age_slope = -0.9 cmf_slope = -2.0 starting = array([t0, delta_t, mmin, cmf_slope, age_slope]) parinfo = [{'value':0., 'fixed':0, 'limited':[0,0], 'limits':[0.,0.], \ 'step':0.} for i in range(5)] fac = 0.5 print starting parinfo[0]['limited'][0]=1 parinfo[0]['limited'][1]=1 parinfo[0]['limits'][0]=0. parinfo[0]['limits'][1]=10. parinfo[0]['value']=0.1 parinfo[0]['step']=0.01*fac parinfo[1]['limited'][0]=1 parinfo[1]['limited'][1]=1 parinfo[1]['limits'][0]=0. parinfo[1]['limits'][1]=10. parinfo[1]['value']=0.5 parinfo[1]['step']=0.01*fac parinfo[2]['limited'][0]=1 parinfo[2]['limited'][1]=1 parinfo[2]['limits'][0]=2. parinfo[2]['limits'][1]=4. parinfo[2]['value']=2.2 parinfo[2]['step']=0.01*fac parinfo[3]['limited'][0]=1 parinfo[3]['limited'][1]=1 parinfo[3]['limits'][0]=-2.2 parinfo[3]['limits'][1]=-1.8 parinfo[3]['value']=-2. parinfo[3]['step']=0.01*fac parinfo[4]['limited'][0]=1 parinfo[4]['limited'][1]=1 parinfo[4]['limits'][0]=-0.2 parinfo[4]['limits'][1]=0.2 parinfo[4]['value']=0 parinfo[4]['step']=0.01*fac sss = call_wrap2(starting) return mpfit(call_wrap2, parinfo = parinfo, \ functkw={'mmax':mmax, 'fc':fc})
def multigaussfit(xax, data, ngauss=1, err=None, params=[1, 0, 1], fixed=[False, False, False], limitedmin=[False, False, True], limitedmax=[False, False, False], minpars=[0, 0, 0], maxpars=[0, 0, 0], quiet=True, shh=True): """ An improvement on onedgaussfit. Lets you fit multiple gaussians. Inputs: xax - x axis data - y axis ngauss - How many gaussians to fit? Default 1 (this could supercede onedgaussfit) err - error corresponding to data These parameters need to have length = 3*ngauss. If ngauss > 1 and length = 3, they will be replicated ngauss times, otherwise they will be reset to defaults: params - Fit parameters: [amplitude, offset, width] * ngauss If len(params) % 3 == 0, ngauss will be set to len(params) / 3 fixed - Is parameter fixed? limitedmin/minpars - set lower limits on each parameter (default: width>0) limitedmax/maxpars - set upper limits on each parameter quiet - should MPFIT output each iteration? shh - output final parameters? Returns: Fit parameters Model Fit errors chi2 """ if len(params) != ngauss and (len(params) / 3) > ngauss: ngauss = len(params) / 3 # make sure all various things are the right length; if they're not, fix them using the defaults for parlist in (params, fixed, limitedmin, limitedmax, minpars, maxpars): if len(parlist) != 3 * ngauss: # if you leave the defaults, or enter something that can be multiplied by 3 to get to the # right number of gaussians, it will just replicate if len(parlist) == 3: parlist *= ngauss elif parlist == params: parlist[:] = [1, 0, 1] * ngauss elif parlist == fixed or parlist == limitedmax: parlist[:] = [False, False, False] * ngauss elif parlist == limitedmin: parlist[:] = [False, False, True] * ngauss elif parlist == minpars or parlist == maxpars: parlist[:] = [0, 0, 0] * ngauss def mpfitfun(x, y, err): if err == None: def f(p, fjac=None): return [0, (y - n_gaussian(pars=p)(x))] else: def f(p, fjac=None): return [0, (y - n_gaussian(pars=p)(x)) / err] return f if xax == None: xax = numpy.arange(len(data)) parnames = {0: "SHIFT", 1: "WIDTH", 2: "AMPLITUDE"} parinfo = [{ 'n': ii, 'value': params[ii], 'limits': [minpars[ii], maxpars[ii]], 'limited': [limitedmin[ii], limitedmax[ii]], 'fixed': fixed[ii], 'parname': parnames[ii / 3] + str(ii / 3), 'error': ii } for ii in range(len(params))] mp = mpfit(mpfitfun(xax, data, err), parinfo=parinfo, quiet=quiet) mpp = mp.params mpperr = mp.perror chi2 = mp.fnorm if mp.status == 0: raise Exception(mp.errmsg) if not shh: for i, p in enumerate(mpp): parinfo[i]['value'] = p print(parinfo[i]['parname'], p, " +/- ", mpperr[i]) print("Chi2: ", mp.fnorm, " Reduced Chi2: ", mp.fnorm / len(data), " DOF:", len(data) - len(mpp)) return mpp, n_gaussian(pars=mpp)(xax), mpperr, chi2
def onedgaussfit(xax, data, err=None, params=[0, 1, 0, 1], fixed=[False, False, False, False], limitedmin=[False, False, False, True], limitedmax=[False, False, False, False], minpars=[0, 0, 0, 0], maxpars=[0, 0, 0, 0], quiet=True, shh=True): """ Inputs: xax - x axis data - y axis err - error corresponding to data params - Fit parameters: Height of background, Amplitude, Shift, Width fixed - Is parameter fixed? limitedmin/minpars - set lower limits on each parameter (default: width>0) limitedmax/maxpars - set upper limits on each parameter quiet - should MPFIT output each iteration? shh - output final parameters? Returns: Fit parameters Model Fit errors chi2 """ def mpfitfun(x, y, err): if err == None: def f(p, fjac=None): return [0, (y - onedgaussian(x, *p))] else: def f(p, fjac=None): return [0, (y - onedgaussian(x, *p)) / err] return f if xax == None: xax = numpy.arange(len(data)) parinfo = [{ 'n': 0, 'value': params[0], 'limits': [minpars[0], maxpars[0]], 'limited': [limitedmin[0], limitedmax[0]], 'fixed': fixed[0], 'parname': "HEIGHT", 'error': 0 }, { 'n': 1, 'value': params[1], 'limits': [minpars[1], maxpars[1]], 'limited': [limitedmin[1], limitedmax[1]], 'fixed': fixed[1], 'parname': "AMPLITUDE", 'error': 0 }, { 'n': 2, 'value': params[2], 'limits': [minpars[2], maxpars[2]], 'limited': [limitedmin[2], limitedmax[2]], 'fixed': fixed[2], 'parname': "SHIFT", 'error': 0 }, { 'n': 3, 'value': params[3], 'limits': [minpars[3], maxpars[3]], 'limited': [limitedmin[3], limitedmax[3]], 'fixed': fixed[3], 'parname': "WIDTH", 'error': 0 }] mp = mpfit(mpfitfun(xax, data, err), parinfo=parinfo, quiet=quiet) mpp = mp.params mpperr = mp.perror chi2 = mp.fnorm if mp.status == 0: raise Exception(mp.errmsg) if not shh: for i, p in enumerate(mpp): parinfo[i]['value'] = p print(parinfo[i]['parname'], p, " +/- ", mpperr[i]) print("Chi2: ", mp.fnorm, " Reduced Chi2: ", mp.fnorm / len(data), " DOF:", len(data) - len(mpp)) return mpp, onedgaussian(xax, *mpp), mpperr, chi2
def gaussfit(data, err=None, params=[], autoderiv=1, return_all=0, circle=0, fixed=numpy.repeat(False, 7), limitedmin=[False, False, False, False, True, True, True], limitedmax=[False, False, False, False, False, False, True], usemoment=numpy.array([], dtype='bool'), minpars=numpy.repeat(0, 7), maxpars=[0, 0, 0, 0, 0, 0, 360], rotate=1, vheight=1, quiet=True, returnmp=False, returnfitimage=False, **kwargs): """ Gaussian fitter with the ability to fit a variety of different forms of 2-dimensional gaussian. Input Parameters: data - 2-dimensional data array err=None - error array with same size as data array params=[] - initial input parameters for Gaussian function. (height, amplitude, x, y, width_x, width_y, rota) if not input, these will be determined from the moments of the system, assuming no rotation autoderiv=1 - use the autoderiv provided in the lmder.f function (the alternative is to us an analytic derivative with lmdif.f: this method is less robust) return_all=0 - Default is to return only the Gaussian parameters. 1 - fit params, fit error returnfitimage - returns (best fit params,best fit image) returnmp - returns the full mpfit struct circle=0 - default is an elliptical gaussian (different x, y widths), but can reduce the input by one parameter if it's a circular gaussian rotate=1 - default allows rotation of the gaussian ellipse. Can remove last parameter by setting rotate=0. numpy.expects angle in DEGREES vheight=1 - default allows a variable height-above-zero, i.e. an additive constant for the Gaussian function. Can remove first parameter by setting this to 0 usemoment - can choose which parameters to use a moment estimation for. Other parameters will be taken from params. Needs to be a boolean array. Output: Default output is a set of Gaussian parameters with the same shape as the input parameters Can also output the covariance matrix, 'infodict' that contains a lot more detail about the fit (see scipy.optimize.leastsq), and a message from leastsq telling what the exit status of the fitting routine was Warning: Does NOT necessarily output a rotation angle between 0 and 360 degrees. """ usemoment = numpy.array(usemoment, dtype='bool') params = numpy.array(params, dtype='float') if usemoment.any() and len(params) == len(usemoment): moment = numpy.array(moments(data, circle, rotate, vheight, **kwargs), dtype='float') params[usemoment] = moment[usemoment] elif params == [] or len(params) == 0: params = (moments(data, circle, rotate, vheight, **kwargs)) if vheight == 0: vheight = 1 params = numpy.concatenate([[0], params]) fixed[0] = 1 # mpfit will fail if it is given a start parameter outside the allowed range: for i in range(len(params)): if params[i] > maxpars[i] and limitedmax[i]: params[i] = maxpars[i] if params[i] < minpars[i] and limitedmin[i]: params[i] = minpars[i] if err == None: errorfunction = lambda p: numpy.ravel((twodgaussian(p,circle,rotate,vheight)\ (*numpy.indices(data.shape)) - data)) else: errorfunction = lambda p: numpy.ravel((twodgaussian(p,circle,rotate,vheight)\ (*numpy.indices(data.shape)) - data)/err) def mpfitfun(data, err): if err == None: def f(p, fjac=None): return [0,numpy.ravel(data-twodgaussian(p,circle,rotate,vheight)\ (*numpy.indices(data.shape)))] else: def f(p, fjac=None): return [0,numpy.ravel((data-twodgaussian(p,circle,rotate,vheight)\ (*numpy.indices(data.shape)))/err)] return f parinfo = [{ 'n': 1, 'value': params[1], 'limits': [minpars[1], maxpars[1]], 'limited': [limitedmin[1], limitedmax[1]], 'fixed': fixed[1], 'parname': "AMPLITUDE", 'error': 0 }, { 'n': 2, 'value': params[2], 'limits': [minpars[2], maxpars[2]], 'limited': [limitedmin[2], limitedmax[2]], 'fixed': fixed[2], 'parname': "XSHIFT", 'error': 0 }, { 'n': 3, 'value': params[3], 'limits': [minpars[3], maxpars[3]], 'limited': [limitedmin[3], limitedmax[3]], 'fixed': fixed[3], 'parname': "YSHIFT", 'error': 0 }, { 'n': 4, 'value': params[4], 'limits': [minpars[4], maxpars[4]], 'limited': [limitedmin[4], limitedmax[4]], 'fixed': fixed[4], 'parname': "XWIDTH", 'error': 0 }] if vheight == 1: parinfo.insert( 0, { 'n': 0, 'value': params[0], 'limits': [minpars[0], maxpars[0]], 'limited': [limitedmin[0], limitedmax[0]], 'fixed': fixed[0], 'parname': "HEIGHT", 'error': 0 }) if circle == 0: parinfo.append({ 'n': 5, 'value': params[5], 'limits': [minpars[5], maxpars[5]], 'limited': [limitedmin[5], limitedmax[5]], 'fixed': fixed[5], 'parname': "YWIDTH", 'error': 0 }) if rotate == 1: parinfo.append({ 'n': 6, 'value': params[6], 'limits': [minpars[6], maxpars[6]], 'limited': [limitedmin[6], limitedmax[6]], 'fixed': fixed[6], 'parname': "ROTATION", 'error': 0 }) if autoderiv == 0: # the analytic derivative, while not terribly difficult, is less # efficient and useful. I only bothered putting it here because I was # instructed to do so for a class project - please ask if you would # like this feature implemented raise ValueError("I'm sorry, I haven't implemented this feature yet.") else: # p, cov, infodict, errmsg, success = optimize.leastsq(errorfunction,\ # params, full_output=1) mp = mpfit(mpfitfun(data, err), parinfo=parinfo, quiet=quiet) if returnmp: returns = (mp) elif return_all == 0: returns = mp.params elif return_all == 1: returns = mp.params, mp.perror if returnfitimage: fitimage = twodgaussian(mp.params, circle, rotate, vheight)(*numpy.indices(data.shape)) returns = (returns, fitimage) return returns
def multigaussfit(xax, data, ngauss=1, err=None, params=[1,0,1], fixed=[False,False,False], limitedmin=[False,False,True], limitedmax=[False,False,False], minpars=[0,0,0], maxpars=[0,0,0], quiet=True, shh=True, veryverbose=False): """ An improvement on onedgaussfit. Lets you fit multiple gaussians. Inputs: xax - x axis data - y axis ngauss - How many gaussians to fit? Default 1 (this could supersede onedgaussfit) err - error corresponding to data These parameters need to have length = 3*ngauss. If ngauss > 1 and length = 3, they will be replicated ngauss times, otherwise they will be reset to defaults: params - Fit parameters: [amplitude, offset, width] * ngauss If len(params) % 3 == 0, ngauss will be set to len(params) / 3 fixed - Is parameter fixed? limitedmin/minpars - set lower limits on each parameter (default: width>0) limitedmax/maxpars - set upper limits on each parameter quiet - should MPFIT output each iteration? shh - output final parameters? Returns: Fit parameters Model Fit errors chi2 """ if len(params) != ngauss and (len(params) / 3) > ngauss: ngauss = len(params) / 3 if isinstance(params,np.ndarray): params=params.tolist() # make sure all various things are the right length; if they're not, fix them using the defaults for parlist in (params,fixed,limitedmin,limitedmax,minpars,maxpars): if len(parlist) != 3*ngauss: # if you leave the defaults, or enter something that can be multiplied by 3 to get to the # right number of gaussians, it will just replicate if len(parlist) == 3: parlist *= ngauss elif parlist==params: parlist[:] = [1,0,1] * ngauss elif parlist==fixed or parlist==limitedmax: parlist[:] = [False,False,False] * ngauss elif parlist==limitedmin: parlist[:] = [False,False,True] * ngauss elif parlist==minpars or parlist==maxpars: parlist[:] = [0,0,0] * ngauss def mpfitfun(x,y,err): if err is None: def f(p,fjac=None): return [0,(y-n_gaussian(pars=p)(x))] else: def f(p,fjac=None): return [0,(y-n_gaussian(pars=p)(x))/err] return f if xax == None: xax = np.arange(len(data)) parnames = {0:"AMPLITUDE",1:"SHIFT",2:"WIDTH"} parinfo = [ {'n':ii, 'value':params[ii], 'limits':[minpars[ii],maxpars[ii]], 'limited':[limitedmin[ii],limitedmax[ii]], 'fixed':fixed[ii], 'parname':parnames[ii%3]+str(ii%3), 'error':ii} for ii in xrange(len(params)) ] if veryverbose: print "GUESSES: " print "\n".join(["%s: %s" % (p['parname'],p['value']) for p in parinfo]) mp = mpfit(mpfitfun(xax,data,err),parinfo=parinfo,quiet=quiet) mpp = mp.params mpperr = mp.perror chi2 = mp.fnorm if mp.status == 0: raise Exception(mp.errmsg) if not shh: print "Final fit values: " for i,p in enumerate(mpp): parinfo[i]['value'] = p print parinfo[i]['parname'],p," +/- ",mpperr[i] print "Chi2: ",mp.fnorm," Reduced Chi2: ",mp.fnorm/len(data)," DOF:",len(data)-len(mpp) return mpp,n_gaussian(pars=mpp)(xax),mpperr,chi2
def onedgaussfit(xax, data, err=None, params=[0,1,0,1],fixed=[False,False,False,False], limitedmin=[False,False,False,True], limitedmax=[False,False,False,False], minpars=[0,0,0,0], maxpars=[0,0,0,0], quiet=True, shh=True, veryverbose=False, vheight=True, negamp=False, usemoments=False): """ Inputs: xax - x axis data - y axis err - error corresponding to data params - Fit parameters: Height of background, Amplitude, Shift, Width fixed - Is parameter fixed? limitedmin/minpars - set lower limits on each parameter (default: width>0) limitedmax/maxpars - set upper limits on each parameter quiet - should MPFIT output each iteration? shh - output final parameters? usemoments - replace default parameters with moments Returns: Fit parameters Model Fit errors chi2 """ def mpfitfun(x,y,err): if err is None: def f(p,fjac=None): return [0,(y-onedgaussian(x,*p))] else: def f(p,fjac=None): return [0,(y-onedgaussian(x,*p))/err] return f if xax == None: xax = np.arange(len(data)) if vheight is False: height = params[0] fixed[0] = True if usemoments: params = onedmoments(xax,data,vheight=vheight,negamp=negamp, veryverbose=veryverbose) if vheight is False: params = [height]+params if veryverbose: print "OneD moments: h: %g a: %g c: %g w: %g" % tuple(params) parinfo = [ {'n':0,'value':params[0],'limits':[minpars[0],maxpars[0]],'limited':[limitedmin[0],limitedmax[0]],'fixed':fixed[0],'parname':"HEIGHT",'error':0} , {'n':1,'value':params[1],'limits':[minpars[1],maxpars[1]],'limited':[limitedmin[1],limitedmax[1]],'fixed':fixed[1],'parname':"AMPLITUDE",'error':0}, {'n':2,'value':params[2],'limits':[minpars[2],maxpars[2]],'limited':[limitedmin[2],limitedmax[2]],'fixed':fixed[2],'parname':"SHIFT",'error':0}, {'n':3,'value':params[3],'limits':[minpars[3],maxpars[3]],'limited':[limitedmin[3],limitedmax[3]],'fixed':fixed[3],'parname':"WIDTH",'error':0}] mp = mpfit(mpfitfun(xax,data,err),parinfo=parinfo,quiet=quiet) mpp = mp.params mpperr = mp.perror chi2 = mp.fnorm if mp.status == 0: raise Exception(mp.errmsg) if (not shh) or veryverbose: print "Fit status: ",mp.status for i,p in enumerate(mpp): parinfo[i]['value'] = p print parinfo[i]['parname'],p," +/- ",mpperr[i] print "Chi2: ",mp.fnorm," Reduced Chi2: ",mp.fnorm/len(data)," DOF:",len(data)-len(mpp) return mpp,onedgaussian(xax,*mpp),mpperr,chi2
def gaussfit(data,err=None,params=(),autoderiv=True,return_all=False,circle=False, fixed=np.repeat(False,7),limitedmin=[False,False,False,False,True,True,True], limitedmax=[False,False,False,False,False,False,True], usemoment=np.array([],dtype='bool'), minpars=np.repeat(0,7),maxpars=[0,0,0,0,0,0,360], rotate=1,vheight=1,quiet=True,returnmp=False, returnfitimage=False,**kwargs): """ Gaussian fitter with the ability to fit a variety of different forms of 2-dimensional gaussian. Input Parameters: data - 2-dimensional data array err=None - error array with same size as data array params=[] - initial input parameters for Gaussian function. (height, amplitude, x, y, width_x, width_y, rota) if not input, these will be determined from the moments of the system, assuming no rotation autoderiv=1 - use the autoderiv provided in the lmder.f function (the alternative is to us an analytic derivative with lmdif.f: this method is less robust) return_all=0 - Default is to return only the Gaussian parameters. 1 - fit params, fit error returnfitimage - returns (best fit params,best fit image) returnmp - returns the full mpfit struct circle=0 - default is an elliptical gaussian (different x, y widths), but can reduce the input by one parameter if it's a circular gaussian rotate=1 - default allows rotation of the gaussian ellipse. Can remove last parameter by setting rotate=0. np.expects angle in DEGREES vheight=1 - default allows a variable height-above-zero, i.e. an additive constant for the Gaussian function. Can remove first parameter by setting this to 0 usemoment - can choose which parameters to use a moment estimation for. Other parameters will be taken from params. Needs to be a boolean array. Output: Default output is a set of Gaussian parameters with the same shape as the input parameters If returnfitimage=True returns a np array of a gaussian contructed using the best fit parameters. If returnmp=True returns a `mpfit` object. This object contains a `covar` attribute which is the 7x7 covariance array generated by the mpfit class in the `mpfit_custom.py` module. It contains a `param` attribute that contains a list of the best fit parameters in the same order as the optional input parameter `params`. Warning: Does NOT necessarily output a rotation angle between 0 and 360 degrees. """ usemoment=np.array(usemoment,dtype='bool') params=np.array(params,dtype='float') if usemoment.any() and len(params)==len(usemoment): moment = np.array(moments(data,circle,rotate,vheight,**kwargs),dtype='float') params[usemoment] = moment[usemoment] elif params == [] or len(params)==0: params = (moments(data,circle,rotate,vheight,**kwargs)) if vheight==0: vheight=1 params = np.concatenate([[0],params]) fixed[0] = 1 # mpfit will fail if it is given a start parameter outside the allowed range: for i in xrange(len(params)): if params[i] > maxpars[i] and limitedmax[i]: params[i] = maxpars[i] if params[i] < minpars[i] and limitedmin[i]: params[i] = minpars[i] if err is None: errorfunction = lambda p: np.ravel((twodgaussian(p,circle,rotate,vheight)\ (*np.indices(data.shape)) - data)) else: errorfunction = lambda p: np.ravel((twodgaussian(p,circle,rotate,vheight)\ (*np.indices(data.shape)) - data)/err) def mpfitfun(data,err): if err is None: def f(p,fjac=None): return [0,np.ravel(data-twodgaussian(p,circle,rotate,vheight)\ (*np.indices(data.shape)))] else: def f(p,fjac=None): return [0,np.ravel((data-twodgaussian(p,circle,rotate,vheight)\ (*np.indices(data.shape)))/err)] return f parinfo = [ {'n':1,'value':params[1],'limits':[minpars[1],maxpars[1]],'limited':[limitedmin[1],limitedmax[1]],'fixed':fixed[1],'parname':"AMPLITUDE",'error':0}, {'n':2,'value':params[2],'limits':[minpars[2],maxpars[2]],'limited':[limitedmin[2],limitedmax[2]],'fixed':fixed[2],'parname':"XSHIFT",'error':0}, {'n':3,'value':params[3],'limits':[minpars[3],maxpars[3]],'limited':[limitedmin[3],limitedmax[3]],'fixed':fixed[3],'parname':"YSHIFT",'error':0}, {'n':4,'value':params[4],'limits':[minpars[4],maxpars[4]],'limited':[limitedmin[4],limitedmax[4]],'fixed':fixed[4],'parname':"XWIDTH",'error':0} ] if vheight == 1: parinfo.insert(0,{'n':0,'value':params[0],'limits':[minpars[0],maxpars[0]],'limited':[limitedmin[0],limitedmax[0]],'fixed':fixed[0],'parname':"HEIGHT",'error':0}) if circle == 0: parinfo.append({'n':5,'value':params[5],'limits':[minpars[5],maxpars[5]],'limited':[limitedmin[5],limitedmax[5]],'fixed':fixed[5],'parname':"YWIDTH",'error':0}) if rotate == 1: parinfo.append({'n':6,'value':params[6],'limits':[minpars[6],maxpars[6]],'limited':[limitedmin[6],limitedmax[6]],'fixed':fixed[6],'parname':"ROTATION",'error':0}) if autoderiv == 0: # the analytic derivative, while not terribly difficult, is less # efficient and useful. I only bothered putting it here because I was # instructed to do so for a class project - please ask if you would # like this feature implemented raise ValueError("I'm sorry, I haven't implemented this feature yet.") else: # p, cov, infodict, errmsg, success = optimize.leastsq(errorfunction,\ # params, full_output=1) mp = mpfit(mpfitfun(data,err),parinfo=parinfo,quiet=quiet) if returnmp: returns = (mp) elif return_all == 0: returns = mp.params elif return_all == 1: returns = mp.params,mp.perror if returnfitimage: fitimage = twodgaussian(mp.params,circle,rotate,vheight)(*np.indices(data.shape)) returns = (returns,fitimage) return returns
def onedgaussfit(xax, data, err=None, params=[0, 1, 0, 1], fixed=[False, False, False, False], limitedmin=[False, False, False, True], limitedmax=[False, False, False, False], minpars=[0, 0, 0, 0], maxpars=[0, 0, 0, 0], quiet=True, shh=True, veryverbose=False, vheight=True, negamp=False, usemoments=False): """ Inputs: xax - x axis data - y axis err - error corresponding to data params - Fit parameters: Height of background, Amplitude, Shift, Width fixed - Is parameter fixed? limitedmin/minpars - set lower limits on each parameter (default: width>0) limitedmax/maxpars - set upper limits on each parameter quiet - should MPFIT output each iteration? shh - output final parameters? usemoments - replace default parameters with moments Returns: Fit parameters Model Fit errors chi2 """ def mpfitfun(x, y, err): if err is None: def f(p, fjac=None): return [0, (y - onedgaussian(x, *p))] else: def f(p, fjac=None): return [0, (y - onedgaussian(x, *p)) / err] return f if xax == None: xax = np.arange(len(data)) if vheight is False: height = params[0] fixed[0] = True if usemoments: params = onedmoments(xax, data, vheight=vheight, negamp=negamp, veryverbose=veryverbose) if vheight is False: params = [height] + params if veryverbose: print "OneD moments: h: %g a: %g c: %g w: %g" % tuple(params) parinfo = [{ 'n': 0, 'value': params[0], 'limits': [minpars[0], maxpars[0]], 'limited': [limitedmin[0], limitedmax[0]], 'fixed': fixed[0], 'parname': "HEIGHT", 'error': 0 }, { 'n': 1, 'value': params[1], 'limits': [minpars[1], maxpars[1]], 'limited': [limitedmin[1], limitedmax[1]], 'fixed': fixed[1], 'parname': "AMPLITUDE", 'error': 0 }, { 'n': 2, 'value': params[2], 'limits': [minpars[2], maxpars[2]], 'limited': [limitedmin[2], limitedmax[2]], 'fixed': fixed[2], 'parname': "SHIFT", 'error': 0 }, { 'n': 3, 'value': params[3], 'limits': [minpars[3], maxpars[3]], 'limited': [limitedmin[3], limitedmax[3]], 'fixed': fixed[3], 'parname': "WIDTH", 'error': 0 }] mp = mpfit(mpfitfun(xax, data, err), parinfo=parinfo, quiet=quiet) mpp = mp.params mpperr = mp.perror chi2 = mp.fnorm if mp.status == 0: raise Exception(mp.errmsg) if (not shh) or veryverbose: print "Fit status: ", mp.status for i, p in enumerate(mpp): parinfo[i]['value'] = p print parinfo[i]['parname'], p, " +/- ", mpperr[i] print "Chi2: ", mp.fnorm, " Reduced Chi2: ", mp.fnorm / len( data), " DOF:", len(data) - len(mpp) return mpp, onedgaussian(xax, *mpp), mpperr, chi2
def call_mpfit(FUNCTION, INIT_PARAM, x, y, error, with_plot = False): """ This method makes fit of function(par,x) to experimental data contained in X,Y arrays. (1)the FUNCTION must be defined as follows: def func(param,x): value = some_formula(param[0],param[1]..., x) return value (2)INIT_PARAM -- is a list of initial values of parameters (3) X exp. data (4) Y experimental data Return: [list of fited parameters], [list of parameters errors], Chi2-value """ def mpfitfunc(x,y,err): if err == None: def f(p,fjac=None): return [0,(y-FUNCTION(p,x))] else: def f(p,fjac=None): return [0,(y-FUNCTION(p,x))/err] return f mpfitparaminfo = generate_mpfit_info(INIT_PARAM) mp2 = mpfit(mpfitfunc(x,y,error), parinfo=mpfitparaminfo,quiet=0) fit_params = mp2.params fit_par_error= mp2.perror chi2 = mp2.fnorm if len(fit_params)>0: print() print("MPFIT ALGORITHM RESULT:") N_params = len(INIT_PARAM) p_cnt=-1 output_string = ' ' #for a report about obtained param value into a string: for p in fit_params: p_cnt+=1 string = str() if fit_par_error!=None: string = "PARAM "+str(p_cnt)+":\t"+str(p)+"+/-("+str(fit_par_error[p_cnt])+")\n" print(string) else: string = "PARAM "+str(p_cnt)+":\t"+str(p)+"\n" print(string) output_string+=string #end for output_string += 'Chi2: '+str(chi2) #write that string to the file: param_file = open("params.mpfit.txt", 'w') param_file.write(output_string) param_file.close() #write fited function values at X into output file. FUNC_VAL = numpy.zeros(len(x)) FUNC_VAL = FUNCTION(fit_params, x) write_arrays( [x, FUNC_VAL], "output.mpfit.txt") print ("Chi2: "+str( chi2)) if with_plot: PLT.plot(x,y,'+', x,FUNC_VAL,'-'); PLT.legend(['data','formula approx.'],loc='best') PLT.show() # end if with_plot if fit_par_error!=None: return fit_params,chi2 else: return fit_params, fit_par_error,chi2 return fit_params
import numpy as np import matplotlib.pyplot as plt from scipy.optimize import curve_fit def func(x, a, b, c): #return a * np.exp(-b * x) + c return a * np.log(b * x) + c x = np.linspace(1,5,50) # changed boundary conditions to avoid division by 0 y = func(x, 2.5, 1.3, 0.5) yn = y + 0.2*np.random.normal(size=len(x)) popt, pcov = curve_fit(func, x, yn) plt.figure() plt.plot(x, yn, 'ko', label="Original Noised Data") plt.plot(x, func(x, *popt), 'r-', label="Fitted Curve") plt.legend() plt.show() """ import mpfit import Numeric x = Numeric.arange(100, Numeric.float) p0 = [5.7, 2.2, 500., 1.5, 2000.] y = ( p[0] + p[1]*[x] + p[2]*[x**2] + p[3]*Numeric.sqrt(x) + p[4]*Numeric.log(x)) fa = {'x':x, 'y':y, 'err':err} m = mpfit('myfunct', p0, functkw=fa) print 'status = ', m.status if (m.status <= 0): print 'error message = ', m.errmsg print 'parameters = ', m.params