使用lmfit进行穆斯堡尔光谱曲线拟合时遇报错求助
穆斯堡尔光谱双洛伦兹拟合报错求助
我是lmfit新手,在处理约27000个数据点的穆斯堡尔光谱数据时持续报错,现提供报错信息、拟合代码、数据特征及数据集,恳请专业人士提供解决方案。
报错信息
RuntimeError: Optimal parameters not found: Number of calls to function has reached maxfev = 1000
数据特征
数据呈现两个明显的负向洛伦兹峰,Channel范围约0-8000,Counts为负值的峰形数据。
原始拟合代码
import numpy as np import matplotlib.pyplot as plt from lmfit import Model import pandas as pd plt.rcParams['figure.dpi'] = 300 plt.rcParams['savefig.dpi'] = 300 # Define the Lorentzian function with a negative sign def lorentzian(x, amp, cen, wid): return (-amp * wid ** 2 / ((x - cen) ** 2 + wid ** 2)) # Define the sum of two Lorentzian peaks def multi_lorentzian(x, a1, c1, w1, a2, c2, w2): return (lorentzian(x, a1, c1, w1) + lorentzian(x, a2, c2, w2)) csv_names = ['Channel', 'Energy', 'Counts'] fp2 = "C:\Users\mfern\Downloads\Data_3_8.csv" df = pd.read_csv(fp2, skiprows=23, names=csv_names).dropna() # Remove rows with NaN values xdata = df['Channel'] ydata = df['Counts'] model = Model(multi_lorentzian) params = model.make_params(a1=0, c1=0, w1=0, a2=0, c2=0, w2=0) params['a1'].min = 0 params['a2'].min = 0 params['w1'].min = 0 params['w2'].min = 0 result = model.fit(ydata, params=params, x=xdata) # Print the fit report print(result.fit_report()) # Plot the data and the fit curve plt.scatter(xdata, ydata, label='data', s=2, c='b') plt.plot(xdata, result.best_fit, 'r-', label='fit') plt.legend()
解决方案及修改后代码
问题分析
- 初始参数完全为0:拟合算法无法从全0参数出发找到有效优化方向,必须根据数据特征设置合理初始值。
- 迭代次数不足:默认最大迭代次数(maxfev=1000)不足以处理27000个数据点的拟合。
- Windows路径转义问题:原始路径中的反斜杠未转义,可能导致文件读取错误。
修改后代码
import numpy as np import matplotlib.pyplot as plt from lmfit import Model import pandas as pd plt.rcParams['figure.dpi'] = 300 plt.rcParams['savefig.dpi'] = 300 # 带负号的洛伦兹函数 def lorentzian(x, amp, cen, wid): return (-amp * wid ** 2 / ((x - cen) ** 2 + wid ** 2)) # 双洛伦兹峰求和 def multi_lorentzian(x, a1, c1, w1, a2, c2, w2): return lorentzian(x, a1, c1, w1) + lorentzian(x, a2, c2, w2) csv_names = ['Channel', 'Energy', 'Counts'] # 使用原始字符串避免Windows路径转义问题 fp2 = r"C:\Users\mfern\Downloads\Data_3_8.csv" df = pd.read_csv(fp2, skiprows=23, names=csv_names).dropna() xdata = df['Channel'].values ydata = df['Counts'].values model = Model(multi_lorentzian) # 根据数据特征设置合理初始参数 # 从数据图看,两个峰中心大概在1500和6500,峰值绝对值约500,峰宽约200 params = model.make_params(a1=500, c1=1500, w1=200, a2=500, c2=6500, w2=200) params['a1'].min = 0 params['a2'].min = 0 params['w1'].min = 0 params['w2'].min = 0 # 增加最大迭代次数,可选添加加权拟合(计数数据误差为sqrt(abs(ydata))) result = model.fit(ydata, params=params, x=xdata, max_nfev=50000, weights=1/np.sqrt(abs(ydata))) # 打印拟合报告 print(result.fit_report()) # 绘制数据与拟合曲线 plt.scatter(xdata, ydata, label='原始数据', s=2, c='b') plt.plot(xdata, result.best_fit, 'r-', label='拟合曲线') plt.xlabel('Channel') plt.ylabel('Counts') plt.legend() plt.show()
额外说明
- 初始参数的设置可以通过观察数据可视化图手动估算,越接近真实值,拟合成功率越高。
- 加权拟合能让拟合算法更关注误差小的数据点,提升拟合精度。
- 如果仍有报错,可以尝试调整优化算法,比如在fit时添加
method='leastsq'(默认)或其他优化器如'nelder'。
内容的提问来源于stack exchange,提问作者matthew fernandez
相关产品推荐
相关产品推荐

