Подгонка кривой-монотонно возрастающая производная


Я пытаюсь получить физическое значимое соответствие некоторым экспериментальным данным. Я знаю, что не только значения 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, '-')

EDIT: я считаю, что вы можете сделать это в MATLAB с помощью slmengine.

2 3

2 ответа:

Правка: еще одна попытка. Я уже отправил наполовину испеченный ответ. И в чтении я тоже потерпел неудачу. Надеюсь, так будет лучше.

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'

Ваши данные интересны: у вас есть три разрыва: в 6.30991828, 6.47697236 и 6.55108034. Они настоящие? Это то, что ты пытаешься поймать?

Ни одна непрерывная функция не может правильно уловить эти разрывы. Ваша единственная надежда-кусочно вписаться по обе стороны разрывов. У вас будет три припадка:

  1. x
  2. 6.47697236
  3. x > 6.55108034

Функция многозначна в точке разрывы, конечно.

Если они не имеют для вас значения, я бы сказал, что любой кубический полином даст вам непрерывную, возрастающую первую производную.

Введите описание изображения здесь