You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用scipy.odr拟合曲线:解决曲线过平及参数异常问题

解决SciPy ODR拟合曲线不贴合、参数异常的问题

问题背景

我最近在尝试用依赖mudr(xdata)和dmss22(sdata)的自定义函数拟合一组实验数据时,遇到了两个棘手的问题:

  • 拟合曲线过于平缓,完全贴合不了数据点的趋势
  • 用scipy.odr拟合后,参数结果完全不符合物理预期:
    • 拟合函数中的p[0]*X[1]项本应远小于1,但得到的p[0]是1e-18量级,和dmss22(1e+17量级)相乘后完全不满足条件
    • p[0]为负值,导致函数呈现下降趋势,和数据的上升趋势完全相反

我最初使用的拟合代码如下:

import numpy as np
from math import pi, sqrt, log
from scipy import optimize
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from scipy.odr import *

# 数据准备
mudr=np.array([ 57.43708609, 46.26119205, 55.60688742, 33.21615894, 28.27072848, 22.54649007, 21.80662252, 11.21483444, 5.80211921])
dme=np.array([ 128662.54890776, 105265.32915726, 128652.56835434, 77968.67019573, 66273.56542068, 58464.58559543, 54570.66624991, 27286.90038703, 19480.92689266])
dmss22=np.array([ 4.90050000e+17]*9)
dmse=np.array([ 1.09777592e+21, 1.11512117e+21, 1.13381702e+21, 1.15033267e+21, 1.14883089e+21, 1.27076265e+21, 1.22637165e+21, 1.19237598e+21, 1.64539205e+21])
F=np.array([ 115.01944248, 110.24354867, 112.77812389, 104.81830088, 104.35746903, 101.32016814, 100.54513274, 96.94226549, 93.00424779])
dF=np.array([ 72710.75386699, 72590.6256987 , 176539.40403673, 130555.27503081, 124299.52080164, 176426.64340597, 143013.52848306, 122117.93022746, 157547.78395513])

# 自定义拟合函数(注:afij为提前初始化的数组)
def Ffitsso(p,X,B=2.58,Fc=92.2,mu=770,Za=0.9468):
    temp1 = (2*B*X[0])/(4*pi*Fc)**2
    temp2 = temp1*(afij[0]+afij[1]*np.log((2*B*X[0])/mu**2))
    temp3 = temp1**2*(afij[2]+afij[3]*np.log((2*B*X[0])/mu**2)+afij[4]*(np.log((2*B*X[0])/mu**2))**2)
    temp4 = temp1**3*(afij[5]+afij[6]*np.log((2*B*X[0])/mu**2)+afij[7]*(np.log((2*B*X[0])/mu**2))**2+afij[8]*(np.log((2*B*X[0])/mu**2))**3)
    return Fc/Za*(1+p[0]*X[1])*(1+temp2+temp3+temp4)+p[1]

# ODR拟合(初始版本)
xtot=np.row_stack( (mudr, dmss22) )
etot=np.row_stack( (dme, dmse) )
fitting = Model(Ffitsso)
mydata = RealData(xtot, F, sx=etot, sy=dF)
myodr = ODR(mydata, fitting, beta0=[0, 100])
myoutput = myodr.run()
myoutput.pprint()
bet=myoutput.beta
plt.plot(mudr,F,"b^")
plt.plot(mudr,Ffitsso(bet,[mudr,dmss22]))
plt.show()

问题排查与解决

经过反复测试和调整,我发现问题的核心在于ODR拟合对初始参数值beta0非常敏感:

  • 最初设置的beta0=[0, 100],对于p[0]来说初始值离真实值太远,拟合算法陷入了局部最优解,导致参数异常、曲线趋势错误
  • 结合物理预期(p[0]*X[1]远小于1,且p[0]应为正值),我将初始参数调整为beta0=[1.5e-15, 100]——这个值是根据X[1](1e+17量级)估算的,确保p[0]*X[1]在1e-2左右,符合预期范围

调整后的关键拟合代码片段:

# 调整初始参数后的ODR拟合
myodr = ODR(mydata, fitting, beta0=[1.5e-15, 100])
myoutput = myodr.run()
myoutput.pprint()
bet=myoutput.beta
plt.plot(mudr,F,"b^")
plt.plot(mudr,Ffitsso(bet,[mudr,dmss22]))
plt.show()

效果验证

调整初始参数后,拟合结果完全符合预期:

  • 拟合曲线完美贴合数据点的趋势
  • p[0]变为正值,且量级合适,p[0]*X[1]远小于1,满足物理约束

内容的提问来源于stack exchange,提问作者Linus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 03:47:37