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.
83 lines
2.6 KiB
83 lines
2.6 KiB
#!/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()])))
|
|
|