scipy.curve_fit返回的不合逻辑的参数

时间:2018-04-30 14:46:11

标签: python scipy curve-fitting

我正在使用Python中的流体模拟一个球,并使用阻尼系数(ab)和流体的密度将模型函数拟合到一组数据点,但是流体密度的拟合值回到负值,我不知道代码中有什么问题。我的代码如下:

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
from scipy.optimize import curve_fit


##%%Parameters and constants 
m       = 0.1                               #mass of object in kg
g       = 9.81                              #acceleration due to gravity in m/s**2
rho     = 700                               #density of object in kg/m**3
v0      = 0                                 #velocity at t=0
y0      = 0                                 #position at t=0
V       = m / rho                           #volume in cubic meters
r       = ((3/4)*(V/np.pi))**(1/3)          #radius of the sphere
asample = 0.0001                            #sample value for a 
bsample = 0.0001                            #sample value for b

#%%Defining integrating function 
##fuction => y'' = g*(1-(rhof/rho))-((a/m)y'+(b/m)y'**2)
##   y' = v
##   v' = g*(1-rhof/rho)-((a/m)v+(b/m)v**2)

def sinkingball(Y, time, a, b, rhof):
    return [Y[1],(1/m)*(V*g*(rho-rhof)-a*Y[1]-b*(Y[1]**2))]

def balldepth(time, a, b, rhof):
    solutions = odeint(sinkingball, [y0,v0], time, args=(a, b, rhof))
    return solutions[:,0] 

time    = np.linspace(0,15,151)

# imported some experimental values and named the array data

a, b, rhof = curve_fit(balldepth, time, data, p0=(asample, bsample, 100))[0]
print(a,b,rhof) 

1 个答案:

答案 0 :(得分:-1)

提供实际获得的输出会很有帮助,time未被sinkingball()使用的评论值得关注。

你可能会发现lmfit(https://lmfit.github.io/lmfit-py)很有用。这为曲线拟合提供了更高级别的界面,除其他外,它允许在参数上设置界限,以便它们可以保持物理上的合理性。我认为您的问题会从curve_fit转换为lmfit

from lmfit import Model
def balldepth(time, a, b, rhof):
    solutions = odeint(sinkingball, [y0,v0], time, args=(a, b, rhof))
    return solutions[:,0] 

# create a model based on the model function "balldepth"
ballmodel = Model(balldepth)

# create parameters, which will be named using the names of the
# function arguments, and provide initial values
params = bollmodel.make_params(a=0.001, b=0.001, rhof=100)

# you wanted rhof to **not** vary in the fit:
params['rhof'].vary = False

# set min/max values on `a` and `b`:
params['a'].min = 0
params['b'].min = 0

# run the fit
result = ballmodel.fit(data, params, time=time)

# print out full report of results
print(result.fit_report())

# get / print out best-fit parameters:
for parname, param in result.params.items():
    print("%s = %f +/- %f" % (parname, param.value, param.stderr))