如何限制lmfit拟合精度?峰值位置拟合误差过大求助
lmfit拟合精度优化及参数异常问题求解
我的实验光谱受采样限制(X轴相邻点间距约0.013),用lmfit拟合时遇到两个参数异常问题,希望优化拟合结果:
- 半峰全宽(FWHM)趋近0时:拟合得到的FWHM低至0.00000005,误差达数百万%,明显不合理。我目前通过给FWHM设置合理下限解决,拟合Voigt轮廓时,若洛伦兹宽度出现类似情况,会转为纯高斯轮廓,请问这个处理逻辑是否正确?
- 峰值位置趋近0时:出现类似的过度精确问题,比如拟合结果中
pos2的误差高达226.65%,但不知道该如何限制参数的过度拟合。
问题代码与拟合结果
import lmfit from lmfit import Model, Parameters import matplotlib.pyplot as plt import numpy as np x=[-0.3933, -0.38, -0.3667, -0.3533, -0.34, -0.3267, -0.3133, -0.3, -0.2867, -0.2733, -0.26, -0.2467, -0.2333, -0.22, -0.2067, -0.1933, -0.18, -0.1667, -0.1533, -0.14, -0.1267, -0.1133, -0.1, -0.0867, -0.0733, -0.06, -0.0467, -0.0333, -0.02, -0.0067, 0.0067, 0.02, 0.0333, 0.0467, 0.06, 0.0733, 0.0867, 0.1, 0.1133, 0.1267, 0.14, 0.1533, 0.1667, 0.18, 0.1933, 0.2067, 0.22, 0.2333, 0.2467, 0.26, 0.2733, 0.2867] y=[0.0048, 0.005, 0.0035, 0.0034, 0.0038, 0.004, 0.0034, 0.0036, 0.0038, 0.0046, 0.0038, 0.0039, 0.0054, 0.0065, 0.0073, 0.0086, 0.0079, 0.0102, 0.0105, 0.0141, 0.0192, 0.0259, 0.0275, 0.0279, 0.0257, 0.0247, 0.022, 0.0244, 0.0268, 0.0295, 0.0275, 0.0227, 0.0192, 0.0138, 0.0075, 0.0088, 0.0081, 0.005, 0.0041, 0.0034, 0.0023, 0.0019, 0.0021, 0.0019, 0.0016, 0.0013, 0.0022, 0.002, 0.0019, 0.0014, 0.0022, 0.0012] def gfunction_norm(x, pos, gfwhm, int): gwid = gfwhm/(2*np.sqrt(2*np.log(2))); gauss= (1/(gwid*(np.sqrt(2*np.pi))))*(np.exp((-1.0/2)*((((x-pos)/gwid))**2))) return int*(gauss-gauss.min())/(gauss.max()-gauss.min()) def final(x, a, b, int2, pos2, gfwhm2, int3, pos3, gfwhm3): return a*x+b + gfunction_norm(x, pos2, gfwhm2, int2) + gfunction_norm(x, pos3, gfwhm3, int3) params1=Parameters() params1.add('a', value=-2.8e-04) params1.add('b', value=0.003) params1.add('int2', value=0.04, min=0.01) params1.add('pos2', value=0, min=-0.05, max=0.05) params1.add('gfwhm2', value=0.05, min = 0.005, max=0.2) params1.add('int3', value=0.04, min=0.01) params1.add('pos3', value=-0.11, min=-0.13, max=-0.06) params1.add('gfwhm3', value=0.090001, min=0.078, max=0.2) model1 = Model(final) result1 = model1.fit(y, params1, x=x) print(result1.fit_report()) plt.plot(x, y, 'bo', markersize=4) plt.plot(x, result1.best_fit, 'r-', label='best fit', linewidth=2) plt.plot(x, gfunction_norm(x, result1.params['pos2'].value, result1.params['gfwhm2'].value, result1.params['int2'].value)) plt.plot(x, gfunction_norm(x, result1.params['pos3'].value, result1.params['gfwhm3'].value, result1.params['int3'].value)) plt.legend() plt.show()
拟合结果:
a: -0.00427895 +/- 0.00102828 (24.03%) (init = -0.00028) b: 0.00331554 +/- 2.6486e-04 (7.99%) (init = 0.003) int2: 0.02301220 +/- 9.6324e-04 (4.19%) (init = 0.04) pos2: 0.00175738 +/- 0.00398305 (226.65%) (init = 0) gfwhm2: 0.08657191 +/- 0.00708478 (8.18%) (init = 0.05) int3: 0.02261912 +/- 8.7317e-04 (3.86%) (init = 0.04) pos3: -0.09568096 +/- 0.00432018 (4.52%) (init = -0.11) gfwhm3: 0.09304840 +/- 0.00797209 (8.57%) (init = 0.090001)
问题分析与解决建议
1. FWHM参数处理逻辑的合理性
给FWHM设置下限的思路完全正确——采样分辨率决定了能分辨的最小峰宽,小于采样间距的FWHM在实验中没有物理意义,强行拟合只会带来无意义的参数波动。
对于Voigt轮廓的处理:当洛伦兹宽度趋近于0时,Voigt确实退化为高斯轮廓,这个转换逻辑没问题。不过更简洁的方式是直接给洛伦兹宽度设置不低于采样间距一半的下限,这样既避免了额外的分支判断,又保证了参数的物理合理性。
2. 峰值位置的过度精确限制
pos2误差过大的核心原因是该峰的位置在采样点之间缺乏足够的数据支撑拟合精度。可以从以下几个方面解决:
- 设置参数步长约束:用lmfit的
Parameters.add()方法中的brute_step参数,把峰值位置的步长设为采样间距(0.013),强制参数只能在采样点或合理间隔内取值,示例代码:params1.add('pos2', value=0, min=-0.05, max=0.05, brute_step=0.013) - 缩小参数范围:根据你提供的数据,0附近的采样点是-0.0067和0.0067,可将
pos2的上下限缩小到这个范围,比如min=-0.0067, max=0.0067,让参数只在有数据支撑的区间内拟合。 - 添加拟合权重:如果部分数据点噪声较大,可以给拟合数据加权重,比如
model1.fit(y, params1, x=x, weights=1/np.array(y_err))(需要先估算每个y点的误差y_err),让拟合更侧重数据可靠的区域。 - 验证模型合理性:观察你的数据,0附近的峰特征是否明显?如果该峰的信号很弱,可能是模型多设了一个峰,导致参数无法被有效约束。建议先尝试拟合单个峰,再判断是否需要添加第二个峰。
内容的提问来源于stack exchange,提问作者Amyx
相关产品推荐
相关产品推荐

