使用 lmfit.Model 或 scipy.optimize.curve_fit 优化函数的卷积

Optimizing the convolution of a function with lmfit.Model or scipy.optimize.curve_fit

使用 lmfit.Model 或 scipy.optimize.curve_fit 我必须优化一个函数,其输出需要与一些实验数据进行卷积,然后才能适合其他一些实验数据。总而言之,工作流程是这样的:

(1)定义了函数A(例如高斯函数)。 (2) 函数 A 的输出与称为数据 B 的实验信号进行卷积。 (3) 函数A的参数针对(2)中提到的卷积进行了优化,以完美匹配其他一些称为数据C的实验数据。

我正在使用傅立叶变换将函数 A 的输出与数据 B 进行卷积,如下所示:

from scipy.fftpack import fft, ifft

    def convolve(data_B, function_A):
        convolved = ifft(fft(IRF) * fft(model)).real
        return convolved

如何使用 lmfit.Model 或 scipy.optimize.curve_fit 将“卷积”拟合到数据 C?

编辑:作为对提交答案的回应,我已将我的卷积步骤合并到用于拟合的方程中,方式如下:

#1 component exponential distribution:
def ExpDecay_1(x, ampl1, tau1, y0, x0, args=(new_y_irf)): # new_y_irf is a list. 
    h = np.zeros(x.size) 
    lengthVec = len(new_y_decay)
    
    shift_1 = np.remainder(np.remainder(x-np.floor(x0)-1, lengthVec) + lengthVec, lengthVec)
    shift_Incr1 = (1 - x0 + np.floor(x0))*new_y_irf[shift_1.astype(int)]
    
    shift_2 = np.remainder(np.remainder(x-np.ceil(x0)-1, lengthVec) + lengthVec, lengthVec)
    shift_Incr2 = (x0 - np.floor(x0))*new_y_irf[shift_2.astype(int)]
    
    irf_shifted = (shift_Incr1 + shift_Incr2)
    irf_norm = irf_shifted/sum(irf_shifted)
    h = ampl1*np.exp(-(x)/tau1)
    conv = ifft(fft(h) * fft(irf_norm)).real # This is the convolution step.
    return conv

然而,当我尝试这样做时:

gmodel = Model(ExpDecay_1)

我明白了:

gmodel = Model(ExpDecay_1) Traceback (most recent call last):

File "", line 1, in gmodel = Model(ExpDecay_1)

File "C:\Users\lopez\Anaconda3\lib\site-packages\lmfit\model.py", line 273, in init self._parse_params()

File "C:\Users\lopez\Anaconda3\lib\site-packages\lmfit\model.py", line 477, in _parse_params if fpar.default == fpar.empty:

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

编辑 2:我设法使其工作如下:

import pandas as pd
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d
import numpy as np
from lmfit import Model
from scipy.fftpack import fft, ifft

def Test_fit2(x, arg=new_y_irf, data=new_y_decay, num_decay=1):
    IRF = arg
    DATA = data
    def Exp(x, ampl1=1.0, tau1=3.0): # This generates an exponential model.
        res = ampl1*np.exp(-x/tau1)
        return res
    def Conv(IRF,decay): # This convolves a model with the data (data = Instrument Response Function, IRF).
        conv = ifft(fft(decay) * fft(IRF)).real
        return conv
    if num_decay == 1: # If the user chooses to use a model equation with one exponential term.
        def fitting(x, ampl1=1.0, tau1=3.0): 
            exponential = Exp(x,ampl1,tau1)
            convolved = Conv(IRF,exponential)
            return convolved
        modelling = Model(fitting)
        res = modelling.fit(DATA,x=new_x_decay,ampl1=1.0,tau1=2.0)
    if num_decay == 2: # If the user chooses to use a model equation with two exponential terms.
        def fitting(x, ampl1=1.0, tau1=3.0, ampl2=1.0, tau2=1.0): 
            exponential = Exp(x,ampl1,tau1)+Exp(x,ampl2,tau2)
            convolved = Conv(IRF,exponential)
            return convolved
        modelling = Model(fitting)
        res = modelling.fit(DATA,x=new_x_decay,ampl1=1.0,tau1=2.0)
    if num_decay == 3: # If the user chooses to use a model equation with three exponential terms.
        def fitting(x, ampl1=1.0, tau1=3.0, ampl2=2.0, tau2=1.0, ampl3=3.0, tau3=5.0): 
            exponential = Exp(x,ampl1,tau1)+Exp(x,ampl2,tau2)+Exp(x,ampl3,tau3)
            convolved = Conv(IRF,exponential)
            return convolved
        modelling = Model(fitting)
        res = modelling.fit(DATA,x=new_x_decay,ampl1=1.0,tau1=2.0)
    if num_decay == 4: # If the user chooses to use a model equation with four exponential terms.
        def fitting(x, ampl1=1.0, tau1=0.1, ampl2=2.0, tau2=1.0, ampl3=3.0, tau3=5.0, ampl4=1.0, tau4=10.0): 
            exponential = Exp(x,ampl1,tau1)+Exp(x,ampl2,tau2)+Exp(x,ampl3,tau3)+Exp(x,ampl4,tau4)
            convolved = Conv(IRF,exponential)
            return convolved
        modelling = Model(fitting)
        res = modelling.fit(DATA,x=new_x_decay,ampl1=1.0,tau1=2.0)
    return res

总是 有助于 post 一个完整的、最小的例子来说明您正在尝试做的事情。没有完整的例子,只能给出模糊的答案。

您可以简单地在 lmfit.Model 包装的模型函数中进行卷积,传入内核数组以在卷积中使用。或者您可以创建卷积核和函数,并将卷积作为建模过程的一部分,如 https://lmfit.github.io/lmfit-py/examples/documentation/model_composite.html

中所述

我想如果内核实际上并不打算在拟合期间更改,那么第一种方法会更容易,但如果没有更多细节,很难确定这一点。