Scipy curve_fit拟合正弦平方曲线结果异常求助
解决scipy curve_fit拟合
sin²(Bx² + C/2)曲线失败的问题 你的拟合失败核心原因有两个:
- 输入的电压值(U)范围太大(3.4到951),计算
x²后数值达到1e6级别,默认初始参数下b*x²会让sin函数极端震荡,优化器无法收敛到合理参数。 curve_fit默认的初始参数[1,1,1]和实际需要的参数量级差距太大,导致优化陷入局部最优。
下面是具体的修复方案:
1. 缩放输入数据
将电压U除以一个合适的系数(比如1000),把x的范围压缩到0.00340.951,这样`x²`的范围在1e-50.9,b*x²的震荡幅度会变得可控,优化器更容易找到合适的b值。
2. 提供合理的初始参数猜测
根据你的数据特征:
a是曲线的峰值,对应I3的最大值~100,初始值设为100b控制震荡频率,缩放后的x最大为0.951,x²≈0.9,要让曲线在x从0到1之间有几个周期,初始值可以设为5c控制相位,初始值设为0即可
3. 可选:用三角恒等式重写拟合函数
将sin²(θ)展开为(1 - cos(2θ))/2,可以避免平方运算带来的数值不稳定,同时让函数形式更平滑,优化更稳定:
原函数y = A sin²(Bx² + C/2)等价于y = A*(1 - cos(2Bx² + 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]) # 替换为真实误差棒数据 U_err = np.ones_like(U) * 5 I3_err = np.ones_like(I3) * 1 # 缩放输入数据 U_scaled = U / 1000 # 用三角恒等式展开的拟合函数 def fit_func3(x, a, b, c): return a * (1 - np.cos(2*b*x**2 + c)) / 2 # 提供初始参数猜测 p0 = [100, 5, 0] # 使用误差棒作为权重提升拟合质量 popt, pcov = curve_fit(fit_func3, U_scaled, I3, p0=p0, sigma=I3_err, absolute_sigma=True) a, b, c = popt # 对U排序,避免绘图时曲线乱跳 U_sorted = np.sort(U) U_sorted_scaled = U_sorted / 1000 I3_fit = fit_func3(U_sorted_scaled, a, b, c) plt.xlabel('Voltage [\muV]') plt.ylabel('Current [\muA]') plt.plot(U_sorted, I3_fit, color='red', label=f'y = {a:.1f} sin²({b:.1f}*(U/1000)² + {c:.1f}/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() # 输出拟合参数 print(f"拟合参数:a={a:.2f}, b={b:.2f}, c={c:.2f}")
额外说明
- 绘图时对U排序可以避免原始数据无序导致的拟合曲线折线混乱,这也是你之前图中曲线杂乱的原因之一。
- 如果不需要三角恒等式的形式,也可以保留原函数,但必须缩放输入数据并提供初始参数p0,同样能得到合理结果。
- 在线拟合工具失败的原因和scipy一致:初始参数不合理+输入数据量级太大,导致优化器无法收敛。
内容的提问来源于stack exchange,提问作者harutoame
相关产品推荐
相关产品推荐

