我正在尝试用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
答案 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
希望有帮助...