Here's a simple example using just `scipy.interpolate.splev`. Since you know at least some about splines, I'll skip much documentation. It's a pretty straightforward use of `splev` and B-splines (here, cubic). To be clear, you could use `splrep` to generate a spline representation, which does handle endpoints well.
Here, I just sort of hardwire in the offsets and the extra knots and so on. You can explore that and play with the spline functions all you like. The point here is that you want the spline coefficients to be the variables. Also note that the values are such that you also can get decent guesses from the data to be interpolated (assuming you have that).
#!/usr/bin/env python
import numpy as np
from scipy.interpolate import splev
from lmfit import Parameters, minimize, fit_report
import matplotlib.pyplot as plt
FMT_COEF = 'coef_%2.2i'
def index_of(arrval, value):
"""return index of array *at or below* value """
if value < min(arrval):
return 0
return max(np.where(arrval <= value)[0])
def spline_eval(params, xdata, xknots, degree=3):
coefs = [params[FMT_COEF % i].value for i in range(ncoefs-degree-1)]
return splev(xdata, [xknots, coefs, degree])
def residual(params, xdata, ydata, xknots, degree=3):
return ydata - spline_eval(params, xdata, xknots, degree=degree)
xdata = np.linspace(0, 100, 201)
ydata = 8 + xdata/2.0 + 2*np.sin(xdata/2.5) + 5 * np.sin((xdata-2)/8)
ydata += np.random.normal(scale=0.1, size=len(xdata))
# create a limited number of spline "knots":
# they don't need to be evenly spaced in "x", but they are here for simplicity
ncoefs = 12
xknots = np.linspace(0, 100, ncoefs)
# now build ncoefs-4 (for 3rd-degree spline) parameters.
# note that you can get a pretty decent guess of the value
# by using the data point value close to x=xknot[i],
params = Parameters()
for i in range(ncoefs-4):
params.add(name=FMT_COEF % i, value=ydata[index_of(xdata, xknots[i])])
print(params)
yinit = spline_eval(params, xdata, xknots)
result = minimize(residual, params, kws=dict(xdata=xdata, ydata=ydata, xknots=xknots))
print(fit_report(result, min_correl=0.5))
plt.plot(xdata, ydata, label='data')
plt.plot(xdata, yinit, label='init')
plt.plot(xdata, spline_eval(result.params, xdata, xknots), label='spline fit')
plt.legend()
plt.show()
#######
--Matt