lmfit模型中拟合参数的不同约束

时间:2018-05-08 14:44:15

标签: python curve-fitting lmfit

我正在尝试用lmfit创建一个多重的voigt / Gaussian / Lorentizan-peak拟合函数。 因此,我写了以下函数:

def apply_fit_mix_multy(data,modelPeak,peakPos,amplitud,**kwargs):
peakPos=np.array(peakPos)
Start=kwargs.get('Start',data[0,0])
length_data=len(data)-1
End=kwargs.get('End',data[length_data,0])
StartPeak=kwargs.get('StartPeak',data[0,0])
EndPeak=kwargs.get('EndPeak',data[length_data,0])
BackFunc=kwargs.get('BackFunc',False)
BackCut=kwargs.get('BackCut',False)
dataN=data_intervall(data,Start,End)
y=dataN[:, 1]
x=dataN[:, 0]
amplitud=amplitud
center=peakPos

mod = None
for i in range(len(peakPos)):
    this_mod = make_model(i,amplitud,center,modelPeak)
    if mod is None:
        mod = this_mod
    else:
        mod = mod + this_mod

bgy=[list() for f in range(len(x))]
if(BackFunc==True):
    bg,bgx=BackFunc
    for i in range(len(x)):
        bgy[i]=bg.best_values.get('c')        

elif(BackCut!=False):
    slope,intercept=back_ground_cut(data,BackCut[0],BackCut[1])  
    for i in range(len(x)):
        bgy[i]=slope*x[i]+intercept       

if(BackCut!=False):
    print('Background substraction model is used! (Sign=Sign-backgr(linear between two points))')
    y=y-bgy
    out = mod.fit(y, x=x)
else:  
    print('Combination model is used! (offset+Gauss/Lor/Voig)')
    offset=ConstantModel()
    mod=mod+offset

out = mod.fit(y, x=x)#out is the fitted function

area=[list() for f in range(len(peakPos))]
comps=out.eval_components(x=x)
if(BackCut!=False):
    for i in range(len(peakPos)):
        area[i]=simps(comps['peak'+str(i)+'_'],x=x,even='avg')-simps(bgy,x=x,even='avg')
    fit_dict={'signal':y, 'convol':out.best_fit,'x':x,'peak_area':area,'backgr':bgy,'comps':comps}
else:
    for i in range(len(peakPos)):
        area[i]=simps(comps['peak'+str(i)+'_'],x=x,even='avg')
    fit_dict={'convol':out.best_fit,'x':x,'peak_area':area,'comps':comps} #comps is inf. of  sperate peaks

return fit_dict

该函数读入数据集,modelPeak(例如GaussianModel)是峰位置和幅度(peakPos,幅度)的初始猜测。

在第一部分中,我初始化峰的模型(多少个峰......)

    for i in range(len(peakPos)):
    this_mod = make_model(i,amplitud,center,modelPeak)
    if mod is None:
        mod = this_mod
    else:
        mod = mod + this_mod

使用make_model funktion:

def make_model(num,amplitud,center,mod):
pref = "peak{0}_".format(num)
model = mod(prefix = pref)
model.set_param_hint(pref+'amplitud', value=amplitud[num], min=0, max=5*amplitud[num])
model.set_param_hint(pref+'center', value=center[num], min=center[num]-0.5, max=center[num]+0.5)
if(num==0):
    model.set_param_hint(pref+'sigma', value=0.3, min=0.01, max=1)
else:
    model.set_param_hint(pref+'sigma', value=0.3, min=0.01, max=1)
#print('Jetzt',center[num],amplitud[num])
return model

现在我的问题是:我想要适合,例如我发现了3个峰第一个峰的西格玛在拟合期间会发生变化,而其他峰的西格玛则取决于第一个峰的西格玛! 任何的想法? 谢谢 数学

仅供参考,这是一个合适的样子: enter image description here

1 个答案:

答案 0 :(得分:1)

如果我理解你的长期问题(删除无关的东西会有所帮助 - 并且有相当多的东西),你想创建一个包含多个峰值的Model,允许sigma从第一个峰值开始自由变化,并限制其他峰值sigma依赖于此。

为此,您可以使用参数提示(在make_model()函数中使用)或在创建Parameters对象后为参数设置表达式。对于第一种方法,类似这样的

def make_model(num,amplitud,center,mod):
    pref = "peak{0}_".format(num)
    model = mod(prefix = pref)
    model.set_param_hint(pref+'amplitud', value=amplitud[num], min=0, max=5*amplitud[num])
    model.set_param_hint(pref+'center', value=center[num], min=center[num]-0.5, max=center[num]+0.5)
    if(num==0):
        model.set_param_hint(pref+'sigma', value=0.3, min=0.01, max=1)
    else:
        ## instead of 
        # model.set_param_hint(pref+'sigma', value=0.3, min=0.01, max=1)
        ## set peakN_sigma == peak0_sigma
        model.set_param_hint(pref+'sigma', expr='peak0_sigma') 
        ## or maybe set peakN_sigma == N * peak0_sigma 
        model.set_param_hint(pref+'sigma', expr='%d*peak0_sigma' % num)
    return model

你也可以制作完整的模型(从你的代码中略微简化,但同样的想法):

model = (VoigtModel(prefix='peak0_') + VoigtModel(prefix='peak1_') +
         VoigtModel(prefix='peak2_') + LinearModel(prefix='const_'))

# create parameters with default values
params = model.make_params(peak0_amplitude=10, peak0_sigma=2, ....)

# set constraints for `sigma` params:
params['peak1_sigma'].expr = 'peak0_sigma'
params['peak2_sigma'].expr = 'peak0_sigma'

# similarly, set bounds as needed:
params['peak1_sigma'].min = 0
params['peak1_amplitude'].min = 0

希望有帮助...