You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
84 lines
2.6 KiB
84 lines
2.6 KiB
2 years ago
|
#!/usr/bin/env python
|
||
|
# encoding: utf-8
|
||
|
"""
|
||
|
expfitting.py
|
||
|
Provide single or double exponential fits to data.
|
||
|
"""
|
||
|
|
||
|
import lmfit
|
||
|
import numpy as np
|
||
|
import scipy.optimize
|
||
|
|
||
|
|
||
|
class ExpFitting:
|
||
|
"""
|
||
|
Parameters
|
||
|
----------
|
||
|
nexp : int
|
||
|
1 or 2 for single or double exponential fit
|
||
|
initpars : dict
|
||
|
dict of initial parameters. For example: {'dc': 0.,
|
||
|
'a1': 1., 't1': 3, 'a2' : 0.5, 'delta': 3.}, where
|
||
|
delta determines the ratio between the time constants.
|
||
|
bounds : dict
|
||
|
dictionary of bounds for each parameter, with a list of lower and upper values.
|
||
|
|
||
|
"""
|
||
|
|
||
|
def __init__(self, nexp=1, initpars=None, bounds=None):
|
||
|
self.fitpars = lmfit.Parameters()
|
||
|
if nexp == 1:
|
||
|
# (Name, Value, Vary, Min, Max, Expr)
|
||
|
self.fitpars.add_many(
|
||
|
("dc", 0, True, -100.0, 0.0, None),
|
||
|
("a1", 1.0, True, -25.0, 25.0, None),
|
||
|
("t1", 10.0, True, 0.1, 50, None),
|
||
|
)
|
||
|
self.efunc = self.exp1_err
|
||
|
elif nexp == 2:
|
||
|
self.fitpars.add_many(
|
||
|
("dc", 0, True, -100.0, 0.0, None),
|
||
|
("a1", 1.0, True, 0.0, 25.0, None),
|
||
|
("t1", 10.0, True, 0.1, 50, None),
|
||
|
("a2", 1.0, True, 0.0, 25.0, None),
|
||
|
("delta", 3.0, True, 3.0, 100.0, None),
|
||
|
)
|
||
|
if initpars is not None:
|
||
|
assert len(initpars) == 5
|
||
|
for k, v in initpars.iteritems():
|
||
|
self.fitpars[k].value = v
|
||
|
if bounds is not None:
|
||
|
assert len(bounds) == 5
|
||
|
for k, v in bounds.iteritems():
|
||
|
self.fitpars[k].min = v[0]
|
||
|
self.fitpars[k].max = v[1]
|
||
|
|
||
|
self.efunc = self.exp2_err
|
||
|
else:
|
||
|
raise ValueError
|
||
|
|
||
|
def fit(self, x, y, p, verbose=False):
|
||
|
|
||
|
kws = {"maxfev": 5000}
|
||
|
mim = lmfit.minimize(
|
||
|
self.efunc, p, method="least_squares", args=(x, y)
|
||
|
) # , kws=kws)
|
||
|
if verbose:
|
||
|
lmfit.printfuncs.report_fit(mim.params)
|
||
|
fitpars = mim.params
|
||
|
return fitpars
|
||
|
|
||
|
@staticmethod
|
||
|
def exp1(x, dc, t1, a1):
|
||
|
return dc + a1 * np.exp(-x / t1)
|
||
|
|
||
|
def exp1_err(self, p, x, y):
|
||
|
return np.fabs(y - self.exp1(x, **dict([(k, p.value) for k, p in p.items()])))
|
||
|
|
||
|
@staticmethod
|
||
|
def exp2(x, dc, t1, a1, a2, delta):
|
||
|
return dc + a1 * np.exp(-x / t1) + a2 * np.exp(-x / (t1 * delta))
|
||
|
|
||
|
def exp2_err(self, p, x, y):
|
||
|
return np.fabs(y - self.exp2(x, **dict([(k, p.value) for k, p in p.items()])))
|