我有两个数据数组,我需要在它们上拟合非线性曲线。我正在使用
scipy.optimize
,它返回如此奇怪的结果,当我将其绘制在数据点旁边时,曲线看起来完全错误。我在 stackoverflow 或 youtube 上没有找到任何有用的东西,这是我最后的手段。
我正在尝试在我的数据点上拟合形状为
y = Asin^2(Bx^2 + C/2)
的曲线。
我当前的代码如下所示:
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
I3 = np.array([12.5, 73.2, 99.5, 96.8, 73.2, 50, 27.1, 10.6, 3.1, 1.31, 0.40, 0.33, 0.41, 0.47, 0.55, 0.56, 0.55, 0.54])
U = np.array([951, 888, 808, 737, 683, 639, 581, 508, 437, 392, 232, 255, 201, 166, 93, 68, 4.5, 3.4])
def fit_func3(x, a, b, c):
return a * (np.sin(b* x ** 2) + c/2) ** 2
popt, _ = curve_fit(fit_func3, U, I3)
a, b, c = popt
I3_fit = fit_func3(U, a, b, c)
plt.xlabel('Voltage [$\mu$V]')
plt.ylabel('Current [$\mu$A]')
plt.plot(U, I3_fit, color='red', label=f'y = I$_0$ sin$^2$($\pi$BLU$^2$/d$^2$ + C/2)')
plt.scatter(U, I3, color='black', label='podatki')
plt.errorbar(U, I3, xerr=U_err, yerr=I3_err, fmt='o', capsize=5, color='black')
plt.legend(loc='upper left')
plt.savefig('graph3.png')
plt.show()
生成的曲线如下所示:
我知道正常的
y = sin^2(x^2)
看起来非常接近数据点,但不知何故拟合无法正常工作。我还没有找到任何方法来限制域以使数据正确适合。
我什至尝试人为地添加数据点以提高拟合质量,但这只是让它稍微不那么混乱和狂野(如果这对发布在这里有帮助的话):
I3_fill = []
U_fill = []
for i in range(len(I3) - 1):
I3_fill.extend(np.linspace(I3[i], I3[i+1], 12)[0:-1])
U_fill.extend(np.linspace(U[i], U[i+1], 12)[0:-1])
I3_fill.append(I3[-1])
U_fill.append(U[-1])
I3_fill = np.array(I3_fill)
U_fill = np.array(U_fill)
我也尝试将参数减少到只有 2 个,如
y = a * (np.sin(b * x ** 2)) ** 2
所示,但这根本没有帮助。
我尝试了2个在线试衣工具,无论我如何修改它们,它们都返回相同的结果。
我猜 scipy 用于优化的方法在这种情况下不好?
我们可能会质疑具有以下通用形式的模型:
通过选择适当的猜测,可以以某种方式强制拟合该模型:
popt, pcov = optimize.curve_fit(model, U, I3, p0=[100., 1e-7, 0.])
#(array([ 1.51118541e+02, 2.59631991e-06, -4.73406696e-01]),
# array([[ 4.74332686e+02, -2.01357369e-08, -1.82194008e+00],
# [-2.01357369e-08, 5.83657181e-15, 1.68952039e-10],
# [-1.82194008e+00, 1.68952039e-10, 8.38560358e-03]]))
这会带来更多的健身效果:
但显然并不令人满意。问题不是
curve_fit
,而是你的数据集或模型。
以下模型可以更好地捕获数据的行为:
def model(x, a, b, c):
return a * (np.sin(b * (x - c) ** 2)) ** 2
但这在小规模来说并不完美
U
: