自定义函数curve_fit拟合结果异常,寻求技术解决方案
问题排查与解决方法
1. 修正模型公式的核心错误
你当前的模型函数完全写错了电容项的形式:原始公式中电容项是指数衰减,但你误用了幂函数计算,这是拟合失败的首要原因。
- 正确的电容项公式:$i_C = \frac{E}{R_S} e^{-\frac{t}{R_S C_{DL}}}$
- 你错误的实现:
math.pow(E/Rs, -(x/Rs*CDL))
修正后的模型函数直接用numpy数组运算替代np.vectorize(更高效且避免标量运算问题):
import numpy as np def model_f(x, E, Rs, CDL, B): # 电容项:指数衰减形式 capacitive = (E / Rs) * np.exp(-x / (Rs * CDL)) # 扩散项:B/√x diffusive = B / np.sqrt(x) # 总电流:电容项 + 扩散项 + 基线常数E return capacitive + diffusive + E
2. 调整拟合的初始值与边界
你设置的bounds=(1,3)把所有参数限制在1-3之间,但数据中Y存在负数(最低至-0.0018),常数项E明显应为负数,这个不合理的边界直接导致拟合失效。同时初始值p0=(1,1,1,1)和数据量级严重不匹配:
- 建议初始值:
p0 = [-0.002, 10, 1e-6, 4](E对应数据基线,Rs取欧姆级典型值,CDL取微法级,B根据扩散项量级估算) - 合理边界:
bounds=([-0.01, 0.1, 1e-8, 0], [0, 100, 1e-3, 10])(给每个参数符合物理意义的范围)
3. 优化拟合代码
去掉冗余的循环和np.vectorize,用numpy数组直接计算各分量,简化代码:
import pandas as pd import numpy as np import matplotlib.pyplot as plt from scipy.optimize import curve_fit # 读取数据(假设df已加载) x_data = df['X'].values y_data = df['Y'].values # 修正后的模型函数 def model_f(x, E, Rs, CDL, B): capacitive = (E / Rs) * np.exp(-x / (Rs * CDL)) diffusive = B / np.sqrt(x) return capacitive + diffusive + E # 设置初始值与边界 p0 = [-0.002, 10, 1e-6, 4] bounds = ([-0.01, 0.1, 1e-8, 0], [0, 100, 1e-3, 10]) # 执行拟合 popt, pcov = curve_fit(f=model_f, xdata=x_data, ydata=y_data, p0=p0, bounds=bounds) E, Rs, CDL, B = popt # 计算各分量与拟合总曲线 diffusive_y = B / np.sqrt(x_data) capacitive_y = (E / Rs) * np.exp(-x_data / (Rs * CDL)) total_fit_y = capacitive_y + diffusive_y + E # 绘图展示 plt.figure(figsize=(10,6)) plt.plot(x_data, y_data, label='Original data', alpha=0.6) plt.plot(x_data, diffusive_y, 'r--', label='Difusiva') plt.plot(x_data, capacitive_y, 'b--', label='Capacitiva') plt.plot(x_data, total_fit_y, 'g-', label='Fitted total') plt.legend() plt.xlabel('Time') plt.ylabel('i_T') plt.show() # 打印拟合参数 print(f"拟合参数:E={E:.6f}, Rs={Rs:.3f}, CDL={CDL:.8f}, B={B:.3f}")
4. 额外优化建议
- 异常值处理:数据中x=1149时Y=0.11远高于其他点,属于异常值,建议先剔除或用移动平滑处理,避免干扰拟合结果。
- 单位一致性检查:确保时间x的单位(秒)与Rs(欧姆)、CDL(法拉)的单位匹配,否则指数项量级会完全错误。
- lmfit进阶拟合:如果scipy拟合仍不理想,可使用lmfit进行更灵活的参数约束与结果分析:
from lmfit import Model model = Model(model_f) params = model.make_params(E=-0.002, Rs=10, CDL=1e-6, B=4) params['E'].set(min=-0.01, max=0) params['Rs'].set(min=0.1, max=100) params['CDL'].set(min=1e-8, max=1e-3) params['B'].set(min=0, max=10) result = model.fit(y_data, params, x=x_data) print(result.fit_report()) result.plot_fit() plt.show()
内容的提问来源于stack exchange,提问作者Carlos Torres
相关产品推荐
相关产品推荐

