0

我对 python 和 lmfit 模型很陌生,遇到了一些麻烦。我想为我的实验数据拟合一个峰值函数(比如高斯或 Voigtian 轮廓),但它从来没有给我任何好的结果。它的最佳拟合是线性函数,它描述了我的峰轮廓的基线。

拟合过程的 x 数据只是从 0 到 100 的数字。这是我的 y 数据:

array([ 0.99518284,  0.99449661,  0.99609029,  0.996     ,  0.994307  ,
    0.999693  ,  0.99826185,  0.99680361,  0.99474041,  0.99793228,
    0.99385553,  0.99869526,  1.00044695,  0.99625734,  0.99758916,
    0.99489842,  1.00032957,  0.9967088 ,  0.99655982,  0.99990068,
    0.99515576,  0.99665914,  0.99990068,  0.99595034,  0.99792777,
    0.9941851 ,  0.99458691,  0.99312415,  0.99815801,  0.99851919,
    0.99637472,  0.996     ,  0.99632957,  0.99185102,  0.99173363,
    0.9915395 ,  0.99038826,  0.9917246 ,  0.99315124,  0.98968397,
    0.99120993,  0.98981038,  0.9892009 ,  0.99009932,  0.98853725,
    0.98624379,  0.98620316,  0.9826772 ,  0.99204966,  0.98455982,
    0.99049661,  0.98591422,  0.98906546,  0.98664108,  0.98740858,
    0.99076298,  0.99046953,  0.99067269,  0.99255982,  0.99264108,
    0.99215801,  0.99990068,  0.9948623 ,  0.99616704,  0.99307449,
    0.99626637,  0.9934447 ,  0.99476749,  0.99636117,  0.99840181,
    0.9984921 ,  0.99782844,  0.99853273,  0.99575621,  0.9985553 ,
    0.99936343,  0.99643792,  0.99825734,  0.9964605 ,  0.99879007,
    1.00068172,  0.99580135,  0.99898871,  1.00069074,  0.99920993,
    0.9963702 ,  0.99591874,  0.99730023,  0.99765237,  0.99334537,
    0.99798194,  0.99770655,  0.99702935,  0.99716027,  0.99662754,
    0.99779684,  0.9967088 ,  0.99736343,  0.99786907,  0.9968623 ,
    0.99961174])

我尝试了以下具有不同模型函数(Gaussian、Voigtian 和 PseudoVoigtian)的方法:

>>> from lmfit.models import PseudoVoigtModel
>>> mod = PseudoVoigtModel()
>>> pars = mod.guess(y, x=x)
>>> out = mod.fit(y, pars, x=x)
>>> print(out.fit_report(min_correl=0.25))
>>> out.plot()

完全相同的代码对于我创建的配置文件测试功能非常有效,所以我想它没有任何问题。但是对于真实的测量数据,无论我选择哪种剖面模型,它总是给出一个线性函数。这是一个例子:

>>> out.best_fit
array([ 0.99410398,  0.99412124,  0.99413851,  0.99415577,  0.99417303,
    0.99419029,  0.99420755,  0.99422481,  0.99424207,  0.99425932,
    0.99427658,  0.99429383,  0.99431108,  0.99432833,  0.99434558,
    0.99436283,  0.99438007,  0.99439732,  0.99441456,  0.9944318 ,
    0.99444904,  0.99446628,  0.99448351,  0.99450075,  0.99451798,
    0.99453522,  0.99455245,  0.99456968,  0.99458691,  0.99460413,
    0.99462136,  0.99463858,  0.99465581,  0.99467303,  0.99469025,
    0.99470747,  0.99472468,  0.9947419 ,  0.99475912,  0.99477633,
    0.99479354,  0.99481075,  0.99482796,  0.99484517,  0.99486237,
    0.99487958,  0.99489678,  0.99491398,  0.99493118,  0.99494838,
    0.99496558,  0.99498278,  0.99499997,  0.99501716,  0.99503436,
    0.99505155,  0.99506874,  0.99508592,  0.99510311,  0.9951203 ,
    0.99513748,  0.99515466,  0.99517184,  0.99518902,  0.9952062 ,
    0.99522338,  0.99524055,  0.99525772,  0.9952749 ,  0.99529207,
    0.99530924,  0.9953264 ,  0.99534357,  0.99536074,  0.9953779 ,
    0.99539506,  0.99541222,  0.99542938,  0.99544654,  0.9954637 ,
    0.99548085,  0.99549801,  0.99551516,  0.99553231,  0.99554946,
    0.99556661,  0.99558376,  0.9956009 ,  0.99561805,  0.99563519,
    0.99565233,  0.99566947,  0.99568661,  0.99570375,  0.99572088,
    0.99573802,  0.99575515,  0.99577228,  0.99578941,  0.99580654,
    0.99582367])

我使用以下方法进行了另一次尝试,但在这里,它根本不适合某些东西,我只得到了 nan 值,尽管它适用于我的高斯测试函数:

from lmfit.models import GaussianModel
from lmfit import Model
import numpy as np

def gaussian(x, amp, cen, wid):
    "1-d gaussian: gaussian(x, amp, cen, wid)"
    return (amp/(sqrt(2*pi)*wid)) * exp(-(x-cen)**2 /(2*wid**2))

gmod = Model(gaussian)

mod.set_param_hint('x', value=10)
mod.set_param_hint('cent', value=47)
mod.set_param_hint('wid', value=20)
mod.set_param_hint('amp', value=0.2)
pars = gmod.make_params()

out = gmod.fit(normedy, pars, x=x)
print(out.fit_report(min_correl=0.1))
plt.figure(5, figsize=(8,8))
out.plot_fit()

我试图用原点拟合数据,它肯定有效(所以数据不是'不合适'),但我怎样才能用 python 正确地做到这一点?你有没有其他我可以尝试的方法或我可以初始化的东西来使它工作?

4

1 回答 1

1

PseudoVoigt 函数(或 Voigt 或 Gaussian 或 Lorentzian)在 +/- 无穷大处变为 0。您的数据看起来达到了 ~1.0,下降了大约 x=50。

您几乎可以肯定要在模型中添加线性或常数分量。对于线性组件,请尝试:

mod = PseudoVoigtModel()
pars = mod.guess(y, x=x)
mod = mod + LinearModel()
pars.add('intercept', value=1, vary=True)
pars.add('slope', value=0, vary=True)
out = mod.fit(y, pars, x=x)
print(out.fit_report(min_correl=0.25))

或者对于一个常数,尝试:

mod = PseudoVoigtModel()
pars = mod.guess(y, x=x)
mod = mod + ConstantModel()
pars.add('c', value=1, vary=True)
out = mod.fit(y, pars, x=x)
print(out.fit_report(min_correl=0.25))

作为该数据的更好模型。

此外,为了获得更好的参数初始值,您可以尝试:

mod = PseudoVoigtModel()
pars = mod.guess((1-y), x=x)    # Note '1-y'

因此用于初始值的曲线更像是一个正峰值。当然,幅度的符号会是错误的,但幅度会接近,起始中心和宽度会接近正确。这应该使合身更加健壮。

于 2015-12-19T05:35:34.337 回答