曲线拟合 - 单调递增导数

时间:2014-03-06 12:48:58

标签: python numpy scipy curve-fitting

我试图获得一些物理上非常适合某些实验数据。我知道,y值不仅会随x单调增加,而且dy / dx也会单调增加。我已经尝试了许多拟合函数,包括多项式拟合和单变量样条,但这些都没有让我产生我正在寻找的拟合。

所以,我正在寻找一个曲线拟合函数(scipy?),这将允许我定义最终曲线的已知约束。下面是我的数据示例,其中一条拟合线不显示单调递增的导数。

import numpy as np
import matplotlib.pyplot as plt

data =  np.array([[  6.30991828, -10.22329935],
                  [  6.30991828, -10.2127338 ],
                  [  6.47697236, -10.01359361],
                  [  6.47697236,  -9.89353722],
                  [  6.47697236,  -9.81708052],
                  [  6.55108034,  -9.42113403],
                  [  6.55108034,  -9.21932801],
                  [  6.58617165,  -8.40428977],
                  [  6.62007321,  -7.6500927 ]])

interp = np.linspace(min(data[:,0]), max(data[:,0]), 20)
f = np.polyfit(data[:,0], data[:,-1], 3)
data_interp = np.polyval(f, interp)
plt.plot(data[:,0], data[:,1], 'x', interp, data_interp, '-')
编辑:我相信你可以在MATLAB中用slmengine做到这一点。

2 个答案:

答案 0 :(得分:1)

您的数据很有趣:您有三个不连续点:位于6.30991828,6.47697236和6.55108034。那是真的吗?那是你想要捕捉的吗?

没有连续功能可以正确捕获这些不连续性。你唯一的希望是在不连续的两边分段拟合。你将有三个适合:

  1. x< 6.47697236
  2. 6.47697236< x< 6.55108034
  3. x> 6.55108034
  4. 当然,该函数在不连续处是多值的。

    如果那些对你没有意义,我会说任何三次多项式都会给你一个连续的,增加的一阶导数。

    enter image description here

答案 1 :(得分:1)

编辑:另一次尝试。我之前发过半生不熟的回答。而且我读书也失败了。我希望这更好。

from scipy.optimize import minimize
import numpy as np
import matplotlib.pyplot as plt

data = np.array([[  6.30991828, -10.22329935],
                  [  6.30991828, -10.2127338 ],
                  [  6.47697236, -10.01359361],
                  [  6.47697236,  -9.89353722],
                  [  6.47697236,  -9.81708052],
                  [  6.55108034,  -9.42113403],
                  [  6.55108034,  -9.21932801],
                  [  6.58617165,  -8.40428977],
                  [  6.62007321,  -7.6500927 ]])

x = data[:, 0]

def polynomial(p, x):
    return p[0]+p[1]*x+p[2]*x**2+p[3]*x**3

def constraint_2nd_der(p):
    return 2*p[2]+6*p[3]*x

def constraint_1st_der(p):
    return p[1]+2*p[2]*x+3*p[3]*x**2

def objective(p):
    return ((polynomial(p, x)-data[:, 1])**2).sum()


cons = (dict(type='ineq', fun=constraint_1st_der), dict(type='ineq', fun=constraint_2nd_der))
res = minimize(objective, x0=np.array([0., 0., 0., 0.]), method='SLSQP', constraints=cons)
if res.success:
    pars = res.x
    x = np.linspace(data[:, 0].min(), data[:, 0].max(), 100)
    pol = polynomial(pars, x)
    plt.plot(data[:, 0], data[:, 1], 'x', x, pol, '-')
    plt.show()
else:
    print 'Failed'