简体   繁体   中英

exponential decay fitting

I am trying to fit some data that are distributed in the time following an exponential decay. I tried to follow some fitting examples on the web, but my code doesn't fit the data. Only a straight line results from the fit. Maybe there is something wrong with the initial parameters? Until now I have only used gaussian and line fits, using the same method, that maybe is not correct for this case. The code take the data from the web, so it is directly executable. Question: why doesn't the code result in any fit? Many thanks in advance.

#!/usr/bin/env python

import pyfits, os, re, glob, sys
from scipy.optimize import leastsq
from numpy import *
from pylab import *
from scipy import *

rc('font',**{'family':'serif','serif':['Helvetica']})
rc('ps',usedistiller='xpdf')
rc('text', usetex=True)
#------------------------------------------------------

tmin = 56200
tmax = 56249

data=pyfits.open('http://heasarc.gsfc.nasa.gov/docs/swift/results/transients/weak/GX304-1.orbit.lc.fits')
time  = data[1].data.field(0)/86400. + data[1].header['MJDREFF'] + data[1].header['MJDREFI']
rate  = data[1].data.field(1)
error = data[1].data.field(2)
data.close()

cond = ((time > 56210) & (time < 56225))
time = time[cond]
rate = rate[cond]
error = error[cond]

right_exp = lambda p, x: p[0]*exp(-p[1]*x)
err = lambda p, x, y:(right_exp(p, x) -y)
v0= [0.20, 56210.0, 1]
out = leastsq(err, v0[:], args = (time, rate), maxfev=100000, full_output=1)
v = out[0] #fit parameters out
xxx = arange(min(time), max(time), time[1] - time[0])
ccc = right_exp(v, xxx)
fig = figure(figsize = (9, 9)) #make a plot
ax1 = fig.add_subplot(111)
ax1.plot(time, rate, 'g.') #spectrum
ax1.plot(xxx, ccc, 'b-') #fitted spectrum
savefig("right exp.png")

axis([tmin-10, tmax, -0.00, 0.45])

Your problem is ill conditioned because your array times contains big numbers that when used in exp(-a*time) are giving values close to 0. , which tricks the err function because your rate array contains small values also close to 0. , leading to small errors. In other words, a high a in the exponential function gives a good solution.

To fix that you can:

  • change your decay function to include an initial time:
    exp(-a*(time-time0))
  • change your input data to start from a smaller number:
    time -= time.min()

For both options you have to change the initial guess v0 , eg v0=[0.,0.] . The first solution seems more robust and you do not have to manage changes in your time array. A good initial guess for time0 is time.min() :

right_exp = lambda p, x: p[0]*exp(-p[1]*(x-p[2]))
err = lambda p, x, y:(right_exp(p, x) -y)
v0= [0., 0., time.min() ]
out = leastsq(err, v0, args = (time, rate))
v = out[0] #fit parameters out
xxx = arange(min(time), max(time), time[1] - time[0])
ccc = right_exp(v, xxx)
fig = figure(figsize = (9, 9)) #make a plot
ax1 = fig.add_subplot(111)
ax1.plot(time, rate, 'g.') #spectrum
ax1.plot(xxx, ccc, 'b-') #fitted spectrum
fig.show()

Giving:

在此处输入图片说明

Still, the final results are depending on v0 , eg with v0=[1.,1.,time.min()] it decays too fast and does not find the optimum.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM