将高斯拟合到测量峰值

时间:2017-09-30 13:13:24

标签: python numpy scipy curve-fitting gaussian

我有一个小的谱峰,我正在尝试使用高斯函数。我在网上搜索了一个例子,并将代码与我制作的代码混合在一起。

wveleng=[ 639.188  639.454  639.719  639.985  640.25   640.516  640.781  641.046
      641.312  641.577]
    counts=[   778.    1613.8  12977.4  32990.   33165.2  13171.    2067.2    900.8
        788.8    747.8]

我的第一个代码是以下

def gaus(x,a,mu,sigma):
    return a*exp(-(x-mu)**2/(2*sigma**2))

    a=ydata.max()
x0=ydata.mean()
sigm=ydata.std()

mean = sum(ydata*xdata)/len(ydata)
sigma = np.sqrt(sum(ydata*(xdata-mean)**2)/len(ydata))

#print(ydata.max())
popt, pcov = curve_fit(Gauss, xdata,ydata,maxfev=991,p0=[a,x0,sigm])    
#gmodel = Model(Gauss)
#result = gmodel.fit(ydata, x=xdata, a=ydata.max(),x0=ydata.mean(),sigm=ydata.std())
print(popt)
#plt.scatter(xdata,ydata,label='data points')
#plt.plot(xdata, result.best_fit, 'r-')
#popt, pcov = curve_fit(gauss, xdata, ydata,p0=[ydata.max(), ydata.mean(), ydata.std()])
xx = np.linspace(639,642, 10)
plt.plot(xx, gauss(xdata, *popt), 'r-', label='fit')

有了情节,我得到以下内容。

enter image description here

我认为它与初始猜测参数有关

第二个代码,我发现它更紧凑,更适合我。

    def gauss(x, a, x0, sigma):
    return a * np.exp(-(x - x0) ** 2 / (2 * sigma ** 2))

ydata = np.array([778.,1613.8,12977.4,32990.,33165.2,13171.,2067.2,900.8,788.8,747.8])

xx = np.arange(639,642, 100)
xdata=np.array([639.188,639.454,639.719,639.985,640.250,640.516,640.781,641.046,641.312,641.577])


#plt.plot(xdata, ydata, 'bo', label='data')
def Gauss(x, a, x0, sigm):
    return a * np.exp(-(x - x0)**2 / (2 * sigm**2))

gmodel = Model(Gauss)
result = gmodel.fit(ydata, x=xdata, a=ydata.max(),x0=ydata.mean(),sigm=ydata.std())
plt.scatter(xdata,ydata,label='data points')
plt.plot(xdata, result.best_fit, 'r-')

我与第一种方法完全一致。有没有比数据本身更适合的点

2 个答案:

答案 0 :(得分:1)

正如你所期待的那样,scipy.integrate.quad没有进行卷积。 quad(function, lower_bound, upper_bound)[0]将为边界之间的函数的积分返回单个值。

OTOH,curve_fit(func, ...)需要一个模型函数的值数组,它抱怨它有一个浮点数,而不是一个ndarray。

也许你打算做curve_fit(vfunc, ...)

你可能会发现lmfit(https://lmfit.github.io/lmfit-py/)很有用。它具有方便,高级的工具曲线拟合,并且内置了像高斯这样的简单模型函数。它还具有一个拟合模型的机制,该模型是两个函数的和或产品,甚至可以创建一个由两个函数的卷积。例如,请参阅https://lmfit.github.io/lmfit-py/model.html#composite-models-adding-or-multiplying-models中描述的示例。

答案 1 :(得分:1)

我认为你真的很亲密,但我不得不承认我不明白xx的意思。您肯定希望数据适合(ydata)和自变量(xdata)长度相同。

我认为你现在遇到的主要问题是你最初的猜测不是很好,并且你会得到很好的结果

result = gmodel.fit(ydata, x=xdata, a=ydata.max(), x0=xdata.mean(), sigma=xdata.std())

xdata代替ydata控制x0sigma的初始值。

或许更好的方法是在参数值范围内添加一些健全性检查,就像

一样
params = gmodel.make_params(a=ydata.max(),
                            x0=xdata.mean(),
                            sigma=xdata.std())
params['x0'].min = min(xdata)
params['x0'].max = max(xdata)
params['sigma'].max = 5
result = gmodel.fit(ydata, params, x=xdata)

最后,使用像GaussianModel这样的内置模型将报告sigmafwhm以及amplitude(即高斯的积分)和height(高斯所需的最大值)。所以,这个脚本:

import numpy as np
from lmfit.models import GaussianModel
import matplotlib.pyplot as plt

ydata = np.array([778.,1613.8,12977.4,32990.,33165.2,13171.,2067.2,900.8,788.8,747.8])
xdata = np.array([639.188,639.454,639.719,639.985,640.250,640.516,640.781,641.046,641.312,641.577])

gmodel = GaussianModel()
params = gmodel.make_params(amplitude=ydata.max(),
                            center=xdata.mean(),
                            sigma=xdata.std())
result = gmodel.fit(ydata, params, x=xdata)

print(result.fit_report())
plt.scatter(xdata,ydata,label='data points')
plt.plot(xdata, result.best_fit, 'r-')
plt.show()

将打印出来

[[Model]]
    Model(gaussian)
[[Fit Statistics]]
    # function evals   = 27
    # data points      = 10
    # variables        = 3
    chi-square         = 2360971.771
    reduced chi-square = 337281.682
    Akaike info crit   = 129.720
    Bayesian info crit = 130.628
[[Variables]]
    sigma:       0.27525232 +/- 0.004505 (1.64%) (init= 0.7623906)
    center:      640.119396 +/- 0.004490 (0.00%) (init= 640.3828)
    amplitude:   25633.2702 +/- 362.5571 (1.41%) (init= 33165.2)
    fwhm:        0.64816968 +/- 0.010608 (1.64%)  == '2.3548200*sigma'
    height:      37152.0777 +/- 525.0717 (1.41%)  == '0.3989423*amplitude/max(1.e-15, sigma)'
[[Correlations]] (unreported correlations are <  0.100)
    C(sigma, amplitude)          =  0.579 

并给出一个非常漂亮的合身。对于高级练习,我建议尝试添加ConstantModel()以提供背景偏移。好吧,收集更多数据点;)。