问题
I have a discrete set of points (x_n, y_n) that I would like to approximate/represent as a linear combination of B-spline basis functions. I need to be able to manually change the number of B-spline basis functions used by the method, and I am trying to implement this in python using scipy. To be specific, below is a bit of code that I am using:
import scipy
spl = scipy.interpolate.splrep(x, y)
However, unless I have misunderstood or missed something in the documentation, it seems I cannot change the number of B-spline basis functions that scipy uses. That seems to be set by the size of x and y. So, my specific questions are:
Can I change the number of B-spline basis functions used by scipy in the "splrep" function that I used above?
Once I have performed the transformation shown in the code above, how can I access the coefficients of the linear combination? Am I correct in thinking that these coefficients are stored in the vector spl[1]?
Is there a better method/toolbox that I should be using?
Thanks in advance for any help/guidance you can provide.
回答1:
Yes, spl[1] are the coefficients, and spl[0] contains the knot vector.
However, if you want to have a better control, you can manipulate the BSpline objects and construct them with make_interp_spline or make_lsq_spline, which accepts the knot vector and that determines the b-spline basis functions to use.
回答2:
You can change the number of B-spline basis functions, by supplying a knot vector with the t
parameter. Since there is a connection number of knots = number of coefficients + degree + 1
, the number of knots will also define the number of coefficients (== the number of basis functions).
The usage of the t
parameter is not so intuitive since the given knots should be only the inner knots. So, for example, if you want 7 coefficients for a cubic spline you need to give 3 inner knots. Inside the function it pads the first and last (degree+1) knots with the xb
and xe
(clamped end conditions see for example here).
Furthermore, as the documentation says, the knots should satisfy the Schoenberg-Whitney conditions.
Here is an example code that does this:
# Input:
x = np.linspace(0,2*np.pi, 9)
y = np.sin(x)
# Your code:
spl = scipy.interpolate.splrep(x, y)
t,c,k = spl # knots, coefficients, degree (==3 for cubic)
# Computing the inner knots and using them:
t3 = np.linspace(x[0],x[-1],5) # five equally spaced knots in the interval
t3 = t3[1:-1] # take only the three inner values
spl3 = scipy.interpolate.splrep(x, y, t=t3)
Regarding your second question, you're right that the coefficients are indeed stored in spl[1]
. However, note that (as the documentation says) the last (degree+1) values are zero-padded and should be ignored.
In order to evaluate the resulting B-spline you can use the function splev
or the class BSpline
.
Below is some example code that evaluates and draws the above splines (resulting in the following figure):
xx = np.linspace(x[0], x[-1], 101) # sample points
yy = scipy.interpolate.splev(xx, spl) # evaluate original spline
yy3 = scipy.interpolate.splev(xx, spl3) # evaluate new spline
plot(x,y,'b.') # plot original interpolation points
plot(xx,yy,'r-', label='spl')
plot(xx,yy3,'g-', label='spl3')
来源:https://stackoverflow.com/questions/51195964/how-can-i-change-the-number-of-basis-functions-when-performing-b-spline-fitting