用python和lmfit对实测irf进行迭代再卷积拟合

2024-05-14 04:26:29 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图用pythonlmfit将指数衰减函数与测量仪器响应进行卷积拟合

我是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()

enter image description here

# 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)

定义拟合的初始参数时,我会得到错误

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()

根据lmfit.model的文档,我怀疑这是因为参数irf在模型中是如何定义为args=(irf)。我试图将irf传递给model,而不是params。我还尝试使用**kwargs

irf合并到model进行卷积并拟合数据的正确方法是什么?


Tags: importfftmodelnppltresultfitlmfit
1条回答
网友
1楼 · 发布于 2024-05-14 04:26:29

我相信你想把^ {CD1>}作为模型函数的附加独立变量——一个值,你传递给函数,但在拟合中不被当作变量。

为此,只需修改模型函数jumpexpmodel()的签名,使其更简单

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

函数的主体很好(实际上args=(irf)不起作用,因为您需要解包args这里的签名确实是您想要的)

然后告诉lmfit.Model()irf是一个自变量-默认情况下第一个参数是唯一的自变量:

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

然后,在制作参数时,不要包括irfargs

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

而是现在将{}与{}一起传递给{}:

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

程序的其余部分看起来很好,由此产生的拟合效果会相当好,并给出一份

[[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

像这样的情节:

enter image description here

相关问题 更多 >