Python 用scipy曲线拟合背景信号
下面是我当前问题的玩具模型。我有一个宽高斯形状的背景和一个尖锐的信号峰值,它与背景平均值有点偏离中心。 我想提取尖峰的属性(即宽度、峰值位置等)。以下是一个链接,指向与峰值拟合失败的绘图: 奇怪的是,对于参数的初始猜测,当使用比分布的实际标准偏差大得多的值时,拟合效果更好……有些地方出错了,但无法确定。如果您能给我一些关于如何将山峰与背景搭配的建议,我将不胜感激 下面是我试过的Python 用scipy曲线拟合背景信号,python,scipy,curve-fitting,Python,Scipy,Curve Fitting,下面是我当前问题的玩具模型。我有一个宽高斯形状的背景和一个尖锐的信号峰值,它与背景平均值有点偏离中心。 我想提取尖峰的属性(即宽度、峰值位置等)。以下是一个链接,指向与峰值拟合失败的绘图: 奇怪的是,对于参数的初始猜测,当使用比分布的实际标准偏差大得多的值时,拟合效果更好……有些地方出错了,但无法确定。如果您能给我一些关于如何将山峰与背景搭配的建议,我将不胜感激 下面是我试过的 #Fake Data data = np.random.normal(loc=3.25, scale=0.01,
#Fake Data
data = np.random.normal(loc=3.25, scale=0.01, size=15000)
data2 = np.random.normal(loc=3.0, scale=0.3, size=25000)
#Bins
bins = np.arange(0, 6.1, 0.1)
#Hitogram with its defined bins
data_entries_1, bins = np.histogram(data, bins=bins)
data_entries_2, bins = np.histogram(data2, bins=bins)
#Add two generated histograms - Final y data
data_entries = data_entries_1 + data_entries_2
#Cetner of each bins - Final x data
bin_centers = np.array([0.5*(bins[i] + bins[i+1]) for i in range(len(bins)-1)])
#fit func 1
def fit_func1(x, A, mu, sigma):
#Define functions here
first_func = A*np.exp(-1.0*(x - mu)**2 / (2*sigma**2))
return first_func
#fit func 2
def fit_func2(x, B, mu2, sigma2):
#Define functions here
second_func = B*np.exp(-1.0*(x - mu2)**2 / (2*sigma2**2))
return second_func
#total fit function
def fit_func(x, A, mu, sigma, B, mu2, sigma2):
#Define functions here
first_func = A*np.exp(-1.0*(x - mu)**2 / (2*sigma**2))
second_func = B*np.exp(-1.0*(x - mu2)**2 / (2*sigma2**2))
final_func = first_func + second_func
return final_func
#Fit it
popt1, pconv1 = curve_fit(fit_func1, xdata=bin_centers, ydata=data_entries_1, p0=[20000, 3.25, 1.])
popt2, pconv2 = curve_fit(fit_func2, xdata=bin_centers, ydata=data_entries_2, p0=[2000, 3.0, 0.3])
popt, pconv = curve_fit(fit_func, xdata=bin_centers, ydata=data_entries, p0=[20000, 3.25, 1.,\
2000, 3.0, 0.3])
# Generate enough x values to make the curves look smooth.
xspace = np.linspace(0, 6, 100)
# Plot the histogram and the fitted function.
plt.step(bin_centers, data_entries, label=r'Histogram entries')
plt.plot(xspace, fit_func1(xspace, *popt1), label='Fitted function1')
plt.plot(xspace, fit_func2(xspace, *popt2), label='Fitted function2')
plt.plot(xspace, fit_func(xspace, *popt), label='Fitted function', linestyle="--")
plt.xlim(1, 5)
plt.legend()
plt.show()
更新
根据所选答案的建议,料仓宽度减小到小于拟拟合实际峰值的西格玛。此外,为了减少拟合自由参数的#,将拟合高斯函数的μ固定为常数(分布的实际平均值)
有几个问题
plt.step
函数的作用与您认为的不同。它取垃圾箱的边缘,而不是垃圾箱的中心fit_func1
以获取两个参数:峰高和峰位置(mu)。将sigma固定到bin\u width/6
。您必须对拟合结果进行后处理,以使峰值下的面积与直方图一致
如果减小存储单元大小,直方图将有噪声。使用curve_fit
的sigma
参数可能是个好主意;设定为
np.sqrt(data_entries + 0.25)
这在统计上并不完全正确,但比假设所有直方图条目都存在固定误差要好得多。(您可以使用0.25值;它应该大于0且小于1)。如果您的目标是分析峰值特性,则可以不进行拟合。要获得峰值位置,只需执行以下操作:
peak_pos = bin_centers[data_entries.argmax()]
如果你有多个这样的峰值,你也可以使用
要获得峰值宽度,可以使用。或者,您可以在分析峰值之前拟合背景并进行减法运算。您的示例代码由于
xspace
而出现错误。抱歉,刚刚更新了缺少的部分。
np.sqrt(data_entries + 0.25)
peak_pos = bin_centers[data_entries.argmax()]