双指数拟合与数据不匹配的问题排查及解决求助
双指数函数拟合优化方案
问题背景
我有一组数据,尝试用双指数函数拟合,但代码运行后拟合效果差,参数出现负值,且不符合已知约束条件(振幅和为1,衰减时间量级为10⁻¹或10⁻²)。修正绘图参数后线条平滑,但仍与数据不匹配。
原代码如下:
import numpy as np import matplotlib.pyplot as plt from scipy.optimize import curve_fit import csv from pylab import genfromtxt import scipy twofifty = genfromtxt("t vs delta E (250C).txt"); t = twofifty[:, 0] de = twofifty[:, 1]*10e3 def func(t, f_1, tau_1, f_2, tau_2): return f_1*np.exp(-t/tau_1)+f_2*np.exp(-t/tau_2) guess = (0.7, 100, 0.3, 200) popt, pcov = curve_fit(func, t, de, guess) print(popt) plt.plot(t, de, label="data") plt.plot(t, func(de, *popt), label="fit") plt.legend() plt.show()
优化步骤
1. 利用已知约束减少参数自由度
已知f_1 + f_2 = 1,将f_2 = 1 - f_1代入拟合函数,减少一个参数,避免无意义的负值振幅,同时降低拟合难度:
def func(t, f_1, tau_1, tau_2): f_2 = 1 - f_1 return f_1*np.exp(-t/tau_1) + f_2*np.exp(-t/tau_2)
对应的初始猜测值需调整为(0.7, 0.1, 0.01)(匹配预期的振幅和衰减时间量级)。
2. 修正初始猜测值的量级
原猜测中tau的量级(100/200)与实际预期(10⁻¹/10⁻²)完全相反,这是拟合失败的核心原因之一。必须将初始猜测调整到合理范围内:
guess = (0.7, 0.1, 0.01) # f1=0.7, tau1=0.1, tau2=0.01
3. 添加参数边界约束
使用curve_fit的bounds参数,强制tau为正(衰减时间不能为负),同时限制f_1在0到1之间(保证f_2=1-f_1也在合理范围内):
# 边界格式:(下限元组, 上限元组) bounds = ((0, 1e-3, 1e-3), (1, 1, 1)) popt, pcov = curve_fit(func, t, de, p0=guess, bounds=bounds)
4. 数据预处理与量级验证
检查t的单位是否与tau匹配:如果t是毫秒级,需先转换为秒,避免指数值过大导致数值溢出;同时用10**4替代10e3,保证y轴缩放的准确性。
5. 保留正确的拟合曲线调用
确保拟合曲线使用t作为输入,而非de:
plt.plot(t, func(t, *popt), label="fit")
完整优化代码
import numpy as np import matplotlib.pyplot as plt from scipy.optimize import curve_fit from pylab import genfromtxt # 读取数据 twofifty = genfromtxt("t vs delta E (250C).txt") t = twofifty[:, 0] de = twofifty[:, 1] * 10**4 # 准确匹配原数据10^4量级 # 带约束的双指数函数 def func(t, f_1, tau_1, tau_2): f_2 = 1 - f_1 return f_1 * np.exp(-t / tau_1) + f_2 * np.exp(-t / tau_2) # 合理的初始猜测 guess = (0.7, 0.1, 0.01) # 参数边界:f1∈[0,1], tau1/tau2∈[0.001,1] bounds = ((0, 1e-3, 1e-3), (1, 1, 1)) # 执行拟合 popt, pcov = curve_fit(func, t, de, p0=guess, bounds=bounds) f1_fit, tau1_fit, tau2_fit = popt f2_fit = 1 - f1_fit print(f"拟合结果:f1={f1_fit:.4f}, f2={f2_fit:.4f}, tau1={tau1_fit:.4f}, tau2={tau2_fit:.4f}") # 绘图 plt.plot(t, de, label="原始数据") plt.plot(t, func(t, *popt), label="拟合曲线", linestyle="--") plt.xlabel("时间t") plt.ylabel("ΔE") plt.legend() plt.show()
内容的提问来源于stack exchange,提问作者jbl
相关产品推荐
相关产品推荐

