Python 噪声和'上的高斯拟合;有趣';数据集
我有一些数据(X射线衍射)如下所示: 我想将高斯分布拟合到这个数据集中,以得到“更宽”部分的半高宽。θ7度左右的双峰不是重要信息,来自不必要的来源 为了让自己更清楚,我想要这样的东西(我用油漆做的:): 我尝试使用以下代码在python中编写脚本:Python 噪声和'上的高斯拟合;有趣';数据集,python,numpy,matplotlib,scipy,Python,Numpy,Matplotlib,Scipy,我有一些数据(X射线衍射)如下所示: 我想将高斯分布拟合到这个数据集中,以得到“更宽”部分的半高宽。θ7度左右的双峰不是重要信息,来自不必要的来源 为了让自己更清楚,我想要这样的东西(我用油漆做的:): 我尝试使用以下代码在python中编写脚本: import math from pylab import * import numpy as np import scipy as sp import matplotlib.pyplot as plt from scipy.optimize i
import math
from pylab import *
import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
data2=np.loadtxt('FWHM.spc')
x2,y2=data2[:,0],data2[:,7]
plt.title('Full Width Half Max of 002 Peak')
plt.plot(x2, y2, color='b')
plt.xlabel('$\\theta$', fontsize=10)
plt.ylabel('Intensity', fontsize=10)
plt.xlim([3,11])
plt.xticks(np.arange(3, 12, 1), fontsize=10)
plt.yticks(fontsize=10)
def func(x, a, x0, sigma):
return a*np.exp(-(x-x0)**2/(2*sigma**2))
mean = sum(x2*y2)/sum(y2)
sigma2 = sqrt(abs(sum((x2-mean)**2*y2)/sum(y2)))
popt, pcov = curve_fit(func, x2, y2, p0 = [1, mean, sigma2])
ym = func(x2, popt[0], popt[1], popt[2])
plt.plot(x2, ym, c='r', label='Best fit')
FWHM = round(2*np.sqrt(2*np.log(2))*popt[2],4)
axvspan(popt[1]-FWHM/2, popt[1]+FWHM/2, facecolor='g', alpha=0.3, label='FWHM = %s'%(FWHM))
plt.legend(fontsize=10)
plt.show()
我得到以下输出:
显然,这与人们所期望的相去甚远。有谁能告诉我如何做到这一点吗
(我在这里附上了数据:)正如OP评论中提到的,在存在不需要的数据时约束信号的方法之一是将其与所需信号一起建模。当然,只有当那些污染数据有一个有效的模型可用时,这种方法才有效。对于所提供的数据,可以考虑一个组合模型,它对以下组件进行求和:
曲线拟合
,所有四个分量(双峰计数两次)都可以同时拟合:
def composite_spectrum(x, # data
a, b, # linear baseline
a1, x01, sigma1, # 1st line
a2, x02, sigma2, # 2nd line
a3, x03, sigma3 ): # 3rd line
return (x*a + b + func(x, a1, x01, sigma1)
+ func(x, a2, x02, sigma2)
+ func(x, a3, x03, sigma3))
guess = [1, 200, 1000, 7, 0.05, 1000, 6.85, 0.05, 400, 7, 0.6]
popt, pcov = curve_fit(composite_spectrum, x2, y2, p0 = guess)
plt.plot(x2, composite_spectrum(x2, *popt), 'k', label='Total fit')
plt.plot(x2, func(x2, *popt[-3:])+x2*popt[0]+popt[1], c='r', label='Broad component')
FWHM = round(2*np.sqrt(2*np.log(2))*popt[10],4)
plt.axvspan(popt[9]-FWHM/2, popt[9]+FWHM/2, facecolor='g', alpha=0.3, label='FWHM = %s'%(FWHM))
plt.legend(fontsize=10)
plt.show()
在不需要的源无法正确建模的情况下,不需要的不连续性可以按照以下建议进行掩盖。对于最简单的情况,您甚至可以简单地屏蔽
[6.5;7.4]
间隔内的所有内容。建议:将p0
更改为[650,mean,sigma2]
并在最后一个图上绘制初始猜测。这将帮助我更好地形象化这个问题:plt.plot(x2,func(x2,650,mean,sigma2),c='r',linestyle=':',label='Initial Guess')
另外,是否有一致的方法来识别不连续性?例如,我们可以说,例如,y值与上一点的y值相差超过100的数据点是垃圾吗?@MadPhysician当然,狭窄的“污染”峰值也可以像你所说的那样被掩盖。但是IMO拟合一个更复杂的模型并对狭窄的部分进行拟合可能比用任意的启发式方法标记数据更容易。@VlasSokolov。那要看情况。OP说在θ7度左右的双峰不是重要的信息,来自不必要的来源。
从科学的角度来看,在进行分析之前,我们希望去除这些数据。我假设OP根本不想花时间根据我上面引用的句子对这个峰值进行建模。这正是我想要的!非常感谢。我们应该补充一点,高斯函数通常并不理想,因为它不能描述衍射轮廓。原则上,它们具有洛伦兹形状,由于实验设置,其经历高斯展宽。为了提高计算速度,通常使用伪Voigt剖面。这种函数也可以产生类似于数据中所示的斜率。@D你是说我应该在曲线上拟合洛伦兹曲线吗?这不会真正影响半高宽——或者?我认为使用伪voigt函数进行衍射(高斯函数和洛伦兹函数的混合)是正常的。半高宽原则上会受到影响。但它们被用来更好地描述衍射图案,因为纯高斯经常衰减得太快而无法描述斜率。这只是一句话。无论如何,如果你只对半高宽感兴趣,有比拟合轮廓更直接、更简单、更快的方法来获得它。