scipy.optimize.curve_fit曲线拟合时无法估计参数协方差
警告核心产生原因
这个警告本质是优化算法没有收敛到稳定的最优解,无法通过雅可比矩阵计算参数的协方差,对应到你的代码里有三个明确的硬错误:
- 模型函数参数顺序错误:
scipy.optimize.curve_fit强制要求传入的自定义模型,第一个位置必须是自变量,后续位置才是待拟合的未知参数。你写的cal_omiga_tstar(omiga,tstar,f)把自变量频率f放在了最后,待拟合参数omiga、tstar放在了最前面,优化器会直接把你传入的频率数组、幅值数组错当成参数初始值传入,完全跑错逻辑。 - 频率数组定义语法错误:你写的
np.array(0.,8.19672131,...)没有给数值序列加外层方括号,numpy只会把第一个值0.识别为输入数据,后面所有数值都会被当成np.array的无关参数,实际生成的频率数组根本不是你预期的等间隔序列,自变量和因变量数据完全不匹配。 - 参数初始值偏差过大:curve_fit默认所有待拟合参数初始值为1,你的幅值数据全在1e-8~1e-10量级,omiga的真实值和默认初始值差了8个数量级,优化器很容易直接发散或者卡在无意义的局部最优区间。
另外你的数据本身也有不符合模型趋势的问题:f=8.19Hz处的幅值比f=0处的幅值还高,但你用的模型在f≥0区间是严格单调衰减的,这个异常点也会严重干扰拟合收敛。
排查解决步骤
- 第一步:修正模型函数参数顺序,把自变量f放到第一个参数位:
def cal_omiga_tstar(f, omiga, tstar): return omiga * np.exp(-np.pi * f * tstar) / (1 + (f / 18.15)**2)
- 第二步:修正频率数组的写法,给所有数值加上外层方括号,同时加一行校验确保自变量、因变量长度一致:
p_freqs = np.array([0.,8.19672131,16.39344262,24.59016393,32.78688525, 40.98360656,49.18032787,57.37704918,65.57377049,73.7704918, 81.96721311,90.16393443,98.36065574,106.55737705,114.75409836, 122.95081967,131.14754098,139.3442623, 147.54098361,155.73770492, 163.93442623,172.13114754,180.32786885,188.52459016,196.72131148, 204.91803279,213.1147541, 221.31147541,229.50819672,237.70491803, 245.90163934]) # 校验数组长度匹配 assert len(p_freqs) == len(p_fft_amp1), "自变量和因变量数据长度不一致"
- 第三步:给待拟合参数设置符合物理意义/数据量级的初始值,通过
p0参数传入。你的模型在f=0处的输出值就是omiga,对应数据里f=0的幅值是3.34e-8,直接把omiga初始值设为3e-8即可;tstar是衰减参数,常规量级在0.01~0.1区间,初始值可先设为0.05。同时可以通过bounds参数给参数加合理边界,避免出现无物理意义的负值:
popt, pcov = optimize.curve_fit( cal_omiga_tstar, p_freqs, p_fft_amp1, p0=[3e-8, 0.05], # 参数顺序和函数定义保持一致:[omiga, tstar] bounds=([0, 0], [np.inf, 1]) # 两个参数都取非负值,tstar上限设为1 ) omiga, tstar = popt
- 第四步:如果修正以上问题后仍报警告,先剔除f=8.19Hz处的异常高点再重新拟合,这个点不符合模型的单调衰减规律,会直接拉偏拟合结果。
额外排查技巧:拟合完成后可以打印pcov矩阵,如果矩阵中存在inf、nan值,就说明优化仍未收敛,可以进一步微调tstar的初始值(比如在0.01~0.2区间遍历试错),直到pcov矩阵为全有限值的实矩阵即可。
内容的提问来源于stack exchange,提问作者ch song
相关产品推荐
相关产品推荐

