Scipy(Python JupyterLab环境)下实验数据无法拟合至指定函数的求助
Scipy(Python JupyterLab环境)下实验数据无法拟合至指定函数的求助
嗨,各位大佬!我最近在处理一组实验数据的拟合问题,教授给了一个固定的拟合函数,但不管用scipy.optimize.curve_fit还是lmfit,拟合效果都很差,实在搞不懂哪里出问题了,想请大家帮忙看看。
我需要把下面的实验数据拟合到教授指定的函数里,函数形式不能改。其中RLC电路的电阻(R_tot-R_G)、电感L、电容C都是用专门设备实测得到的,理论上只有振幅参数A是未知的,但拟合出来的结果完全不对,残差也很不理想。
以下是我用到的完整代码和实验数据:
import numpy as np from scipy.optimize import curve_fit import matplotlib.pyplot as plt import numpy.ma as ma from math import sqrt # 实验数据 x1 = np.array([200. , 220. , 240. , 260. , 280. , 300. , 320. , 340. , 360. , 380. , 390. , 392.5 , 395. , 397.5 , 400. , 402.5 , 405. , 407.5 , 410. , 411.25, 412.5 , 413.75, 414. , 415.25, 416.5 , 417.75, 418.5 , 420. , 422.5 , 425. , 427.5 , 430. , 432.5 , 435. , 437.5 , 440. , 450. , 460. , 480. , 500. , 510. , 520. , 540. , 560. , 570. , 580. , 600. ]) y1 = np.array([0.00787402, 0.00904762, 0.01079365, 0.01269841, 0.01539683, 0.01857143, 0.02321429, 0.0302 , 0.04303279, 0.06767896, 0.09456265, 0.10338983, 0.11410579, 0.12545932, 0.14700855, 0.16944444, 0.19692833, 0.22965779, 0.27434783, 0.28681818, 0.32079208, 0.32562814, 0.32893401, 0.33061224, 0.32727273, 0.31268293, 0.30236967, 0.28940092, 0.24274194, 0.20989011, 0.18052805, 0.15531915, 0.13259053, 0.11627907, 0.10341463, 0.07345133, 0.07455357, 0.06403509, 0.04163265, 0.03811475, 0.02948207, 0.0272 , 0.02301587, 0.02027559, 0.01968254, 0.01795276, 0.01672584]) σ_y1 = np.array([0.00021564, 0.00023222, 0.00025707, 0.00028599, 0.00032924, 0.00038243, 0.00046297, 0.00058876, 0.0008021 , 0.00127062, 0.00180749, 0.00196919, 0.00217276, 0.00239208, 0.00284333, 0.00317296, 0.00368032, 0.00432658, 0.00507593, 0.00532676, 0.0060111 , 0.00611128, 0.00618 , 0.00621495, 0.00607953, 0.0057964 , 0.0056074 , 0.00536185, 0.00463023, 0.00401191, 0.00347255, 0.00303842, 0.00250275, 0.00219007, 0.00196289, 0.0014738 , 0.00139797, 0.00129955, 0.00077378, 0.00082702, 0.00054713, 0.00053481, 0.00043752, 0.00041071, 0.0003831 , 0.00037095, 0.00033556]) # 教授指定的拟合函数 def fitfunc1(x, A, R, L, C): # 频率f单位为kHz ω = 2*np.pi*x δ = R/(2*L) Ω = 1/sqrt(L*C) return A*ω/sqrt(ω**4-2*ω**2*(Ω**2-2*δ**2)+Ω**4) # 实测的电路参数 R_tot = 77.54 R_G = 48 L = 308*1E-6 C = 508*1E-9 # 参数初始值:只有A是未知,其余为实测值 p_init1 = [31454, R_tot-R_G, L, C] # 执行拟合 p_best1, cov1 = curve_fit( fitfunc1, x1, y1, sigma=σ_y1, p0=p_init1, bounds=(0, +np.inf) ) # 残差计算 res1 = (y1-fitfunc1(x1, *p_best1)) sum_res1 = sum(res1) σ_post1 = ma.sqrt(sum_res1/(y1.size)) # 输出拟合结果 print("---------------------------") print("Best fit values:") print("---------------------------") print("A = (%.5f +/- %.5f) 百分比误差 = %.5f" % (p_best1[0],sqrt(cov1[0,0]),sqrt(cov1[0,0])*100/p_best1[0])) print("R = (%.5f +/- %.5f) Ω 百分比误差 = %.5f" % (p_best1[1],sqrt(cov1[1,1]),sqrt(cov1[1,1])*100/p_best1[1])) print("L = (%.5f +/- %.5f) μH 百分比误差 = %.5f" % (p_best1[2]*1E+6,sqrt(cov1[2,2])*1E+6,sqrt(cov1[2,2])*100/p_best1[2])) print("C = (%.5f +/- %.5f) pF 百分比误差 = %.5f" % (p_best1[3]*1E+12,sqrt(cov1[3,3])*1E+12,sqrt(cov1[3,3])*100/p_best1[3])) print("---------------------------") # 绘制拟合图与残差图 fig1 = plt.figure(1, figsize=(9,7)) frame1a=fig1.add_axes((.1,.3,.7,.5)) plt.errorbar(x1, y1, yerr=σ_y1, fmt='.', label='实验数据', capsize = 4) _pts = np.linspace(x1[0], x1[-1], 1000) plt.plot(_pts, fitfunc1(_pts, *p_best1), label='拟合曲线') plt.title("R两端的放大倍数") plt.xlabel("频率 [kHz]") plt.ylabel(r"A = $V_{out}/V_{in}$") plt.legend() plt.tick_params(bottom = False) plt.grid() frame1a.set_xticklabels([]) # 残差图 frame1b=fig1.add_axes((.1,.1,.7,.19)) plt.errorbar(x1, res1, yerr = σ_y1, fmt ='.', capsize = 4) plt.xlabel("频率 [kHz]") plt.ylabel(r"$A_{测量}-A_{拟合}$") plt.grid() # plt.savefig("fit_result.png", dpi = 200, bbox_inches = "tight")
我已经尝试过这些方法,但都没有解决问题:
- 去掉参数的
bounds=(0, +np.inf)限制,但这样得到的参数误差大到离谱,完全不合理; - 给参数重命名,避免和初始值变量名冲突,但没有改善;
- 调整初始参数值(虽然理论上这些初始值是实测的,应该没问题),拟合效果还是很差;
- 尝试用
lmfit库进行拟合,结果同样不理想。
我实在搞不懂问题出在哪,明明只有A是未知参数,拟合却完全不对。有没有大佬能帮我看看函数实现、拟合设置或者数据处理哪里有问题?万分感谢!
备注:内容来源于stack exchange,提问作者Gabriele
相关产品推荐
相关产品推荐

