简体   繁体   English

使用 python 和 lmfit 与测量的 irf 进行迭代再卷积拟合

[英]Iterative reconvolution fitting with measured irf using python and lmfit

I am trying to fit an exponential decay function with convolution to a measured instrument response using python and lmfit .我正在尝试使用pythonlmfit将指数衰减 function 与测量仪器响应进行卷积拟合。

I am new to python and I am trying to follow the code in https://groups.google.com/group/lmfit-py/attach/90f51c25ebb39a52/deconvol_exp2.py?part=0.1&authuser=0 .我是 python 的新手,我正在尝试遵循https://groups.google.com/group/lmfit-py/attach/90f51c25ebb39a52/deconvol_exp2.py?part=0.1&authuser=0中的代码。

import numpy as np
from lmfit import Model 
import matplotlib.pyplot as plt
import requests

# Load data
url = requests.get('https://groups.google.com/group/lmfit-py/attach/73a983d40ad945b1/tcspcdatashifted.csv?part=0.1&authuser=0')

x,decay1,irf=np.loadtxt(url.iter_lines(),delimiter=',',unpack=True,dtype='float')

plt.figure(1)
plt.semilogy(x,decay1,x,irf)
plt.show()

在此处输入图像描述

# Define weights
wWeights=1/np.sqrt(decay1+1)


# define the double exponential model
def jumpexpmodel(x,tau1,ampl1,tau2,ampl2,y0,x0,args=(irf)):
    ymodel=np.zeros(x.size) 
    t=x
    c=x0
    n=len(irf)
    irf_s1=np.remainder(np.remainder(t-np.floor(c)-1, n)+n,n)
    irf_s11=(1-c+np.floor(c))*irf[irf_s1.astype(int)]
    irf_s2=np.remainder(np.remainder(t-np.ceil(c)-1,n)+n,n)
    irf_s22=(c-np.floor(c))*irf[irf_s2.astype(int)]
    irf_shift=irf_s11+irf_s22   
    irf_reshaped_norm=irf_shift/sum(irf_shift)    
    ymodel = ampl1*np.exp(-(x)/tau1)
    ymodel+= ampl2*np.exp(-(x)/tau2)  
    z=Convol(ymodel,irf_reshaped_norm)
    z+=y0
    return z

# convolution using fft (x and h of equal length)
def Convol(x,h):
    X=np.fft.fft(x)
    H=np.fft.fft(h)
    xch=np.real(np.fft.ifft(X*H))
    return xch    

# assign the model for fitting    
mod=Model(jumpexpmodel)

When defining the initial parameters for the fit, I am getting the error .在定义拟合的初始参数时,我得到了错误

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

#initialize the parameters - showing error
pars = mod.make_params(tau1=10,ampl1=1000,tau2=10,ampl2=1000,y0=0,x0=10,args=irf)
pars['x0'].vary =True
pars['y0'].vary =True

print(pars)

# fit this model with weights, initial parameters
result = mod.fit(decay1,params=pars,weights=wWeights,method='leastsq',x=x)

# print results
print(result.fit_report())

# plot results
plt.figure(5)
plt.subplot(2,1,1)
plt.semilogy(x,decay1,'r-',x,result.best_fit,'b')
plt.subplot(2,1,2)
plt.plot(x,result.residual)
plt.show()

Based on the documentation for lmfit.model , I suspect, this is because of how argument irf is defined in model as args=(irf) .根据lmfit.model的文档,我怀疑这是因为参数irf在 model 中定义为args=(irf) I have tried to pass irf to model instead of params .我试图将irf传递给model而不是params I have also tried to use **kwargs .我也尝试过使用**kwargs

What is the correct way to incorporate irf into the model for convolution and fit the data?irf合并到model进行卷积并拟合数据的正确方法是什么?

I believe that you want to consider irf as an additional independent variable of the model function - a value that you pass in to the function but is not treated as a variable in the fit.我相信您想将irf视为 model function 的附加自变量- 您传递给 function 的值但不被视为变量。

To do that, just modify the signature of your model function jumpexpmodel() to be the simpler为此,只需将 model function jumpexpmodel()的签名修改为更简单

def jumpexpmodel(x, tau1, ampl1, tau2, ampl2, y0, x0, irf):

the body of the function is fine (in fact the args=(irf) would not have worked because you would have needed to unpack args -- the signature here is really what you wanted anyway). function 的主体很好(实际上args=(irf)不会起作用,因为您需要解压缩args ——无论如何,这里的签名确实是您想要的)。

Then tell lmfit.Model() that irf is an independent variable - the default is that the first argument is the only independent variable:然后告诉lmfit.Model() irf是一个自变量——默认是第一个参数是唯一的自变量:

mod = Model(jumpexpmodel, independent_vars=('x', 'irf'))

Then, when making the parameters, do not include irf or args :然后,在制作参数时,不要包含irfargs

pars = mod.make_params(tau1=10, ampl1=1000, tau2=10, ampl2=1000, y0=0, x0=10)

but rather now pass in irf along with x to mod.fit() :而是现在将irfx一起传递给mod.fit()

result = mod.fit(decay1, params=pars, weights=wWeights, method='leastsq', x=x, irf=irf)

The rest of your program looks fine and the resulting fit will work reasonably well, giving a report of您的程序的 rest 看起来不错,结果拟合效果很好,给出的报告

[[Model]]
    Model(jumpexpmodel)
[[Fit Statistics]]
    # fitting method   = leastsq
    # function evals   = 138
    # data points      = 2797
    # variables        = 6
    chi-square         = 3795.52585
    reduced chi-square = 1.35991610
    Akaike info crit   = 865.855713
    Bayesian info crit = 901.473529
[[Variables]]
    tau1:   50.4330421 +/- 0.68246203 (1.35%) (init = 10)
    ampl1:  2630.30664 +/- 20.1552948 (0.77%) (init = 1000)
    tau2:   225.392872 +/- 2.75674753 (1.22%) (init = 10)
    ampl2:  523.257894 +/- 12.4451921 (2.38%) (init = 1000)
    y0:     20.7975212 +/- 0.14165429 (0.68%) (init = 0)
    x0:    -9.70588133 +/- 0.12597936 (1.30%) (init = 10)
[[Correlations]] (unreported correlations are < 0.100)
    C(tau2, ampl2) = -0.947
    C(tau1, ampl2) = -0.805
    C(tau1, tau2)  =  0.706
    C(tau1, x0)    = -0.562
    C(ampl1, x0)   =  0.514
    C(tau1, ampl1) = -0.453
    C(tau2, y0)    = -0.426
    C(ampl2, y0)   =  0.314
    C(ampl2, x0)   =  0.291
    C(tau2, x0)    = -0.260
    C(tau1, y0)    = -0.212
    C(ampl1, tau2) =  0.119

and a plot like this:和这样的 plot :

在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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