cubSplineTcb¶
Computes a tension-continuity-bias (TCB) cubic spline interpolant. This is also called a Kochanek-Bartels spline and is a generalization of the Catmull–Rom spline.
Synopsis¶
cubSplineTcb (xdata, fdata)
Required Arguments¶
- float
xdata[]
(Input) - Array with
ndata
components containing the abscissas of the interpolation problem. - float
fdata[]
(Input) - Array with
ndata
components containing the ordinates for the interpolation problem.
Return Value¶
The structure that represents the interpolant. If an interpolant cannot be
computed, None
is returned.
Optional Arguments¶
tension
, float[]
(Input)Sets the tension values at the data points. The array
tension
is of lengthndata
and contains tension values in the interval [-1,1]. For each point, if the tension value is near +1 the curve is tightened at that point. If it is near -1, the curve is slack.Default: All values of
tension
are zero.continuity
, float[]
(Input)Sets the continuity values at the data points. The array
continuity
is of lengthndata
and contains continuity values in the interval [-1,1]. For each point, if the continuity value is zero the curve is \(C^1\) at that point. Otherwise the curve has a corner at that point, but is still continuous (\(C^0\)).Default: All values of
continuity
are zero.bias
, float[]
(Input)Sets the bias values at the data points. The array
bias
is of lengthndata
and contains bias values in the interval [-1,1]. For each point, if the bias value is zero the left and right side tangents are equally weighted. If the value is near +1 the left-side tangent dominates. If the value is near -1 the right-side tangent dominates.Default: All values of
bias
are zero.left
, float (Input)Sets the value of the tangent at the leftmost endpoint.
Default:
left
= 0.right
, float (Input)Sets the value of the tangent at the rightmost endpoint.
Default:
right
= 0.
Description¶
The function cubSplineTcb
computes the Kochanek-Bartels spline, a
piecewise cubic Hermite spline interpolant to a set of data points
\(\{x_i, f_i\}\) for I = 0, …, ndata
-1. The breakpoints of the spline
are the abscissas. As with all of the univariate interpolation functions, the
abscissas need not be sorted.
The \(\{x_i\}\) values are the knots, so the i-th interval is \(\left[x_i, x_{i+1}\right]\). (To simplify the explanation, it is assumed that the data points are given in increasing order.) The cubic Hermite in the i-th segment has a starting value of \(f_i\) and an ending value of \(f_{i+1}\). Its incoming tangent is
where \(t_i\) is the i-th tension value, \(c_i\) is the i-th continuity value, and \(b_i\) is the i-th bias value. Its outgoing tangent is
The optional arguments left
and right
are used at the endpoints:
and
Both left and right default to zero.
The spline has a continuous first derivative (is \(C^1\)) if at each data point the left and right tangents are equal. This is true if the continuity parameters, \(c_i\), are all zero. For any values of the parameters the spline is continuous (\(C^0\)).
If \(t_i = c_i = b_i = 0\) for all i, then the curve is the Catmull-Rom spline.
The following chart shows the same data points interpolated with different parameter values. All of the tension, continuity and bias parameters are zero except for the labeled parameter, which has the indicated value at all data points.
Tension controls how sharply the spline bends at the data points. If
tension
is near +1, the curve tightens. If tension
is near -1, the
curve slackens.
The continuity parameter controls the continuity of the first derivative. If continuity is zero, the spline’s first derivative is continuous, so the spline is \(C^1\).
The bias parameter controls the weighting of the left and right tangents. If zero, the tangents are equally weighted. If the bias parameter is near +1, the left tangent dominates. If the bias parameter is near -1, the right tangent dominates.
Figure 3.3 — Data Points Interpolated with Different Parameter Values
Examples¶
Example 1¶
This example interpolates to a set of points. At \(x = 3\) the continuity and tension parameters are -1. At all other points, they are zero. Interpolated values are then printed.
from __future__ import print_function
from numpy import *
from pyimsl.math.cubSplineTcb import cubSplineTcb
from pyimsl.math.cubSplineValue import cubSplineValue
xdata = [0, 1, 2, 3, 4, 5]
fdata = [5, 2, 3, 5, 1, 2]
continuity = [0, 0, 0, -1, 0, 0]
tension = [0, 0, 0, -1, 0, 0]
m = 2
ppoly = cubSplineTcb(xdata, fdata,
continuity=continuity,
tension=tension)
for i in range(0, m * len(xdata) - 1):
x = float(i) / m
y = cubSplineValue(x, ppoly)
print(" %6.3f %10.4f" % (x, y))
Output¶
0.000 5.0000
0.500 3.4375
1.000 2.0000
1.500 2.1875
2.000 3.0000
2.500 3.6875
3.000 5.0000
3.500 2.1875
4.000 1.0000
4.500 1.2500
5.000 2.0000
Example 2¶
It is possible to use an interpolating spline for approximation by using an optimization function to compute its parameters. In this example a series of n interest rates, \(r_i\), for different maturities, \(x_i\), is given, \(\{x_i, r_i\}\) for \(i = 0, …, n-1\). Since the dates are given on a widely varying time scale, the base 10 logarithm of the dates is used for interpolation.
A TCB spline is constructed using a subset of the given data points for knot locations, \(\{p_i, q_i\}\), for \(i = 0, …, m-1\). The p values are a subset of the \(log_{10}x_i\) values. The q values are to be determined by the optimizer. The spline has non-zero values of the continuity parameter, \(c_i\), for \(i = 0, …, m-1\).
The optimization problem finds the spline, \(s\left( r_i; p, q, c, \mathit{left}, \mathit{right} \right)\) , which interpolates the points \(\{p_i, q_i\}\) and has continuity parameters, c, and specified left and right parameters.
The optimization problem is
subject to the bounds, for all i.
The function constrainedNlp is used as the
optimizer. The unknowns q, c, left and right are packed into the
array x
, respectively.
from __future__ import print_function
from numpy import *
from pyimsl.math.cubSplineTcb import cubSplineTcb
from pyimsl.math.cubSplineValue import cubSplineValue
from pyimsl.math.constrainedNlp import constrainedNlp
N_DATA = 15
days = array([3, 31, 62, 94, 185, 367, 731, 1096, 1461, 1826, 2194,
2558, 2922, 3287, 3653])
rate = array([5.01772, 4.98284, 4.97234, 4.96157, 4.99058,
5.09389, 5.79733, 6.30595, 6.73464, 6.94816, 7.08807, 7.27527,
7.30852, 7.3979, 7.49015])
# Knots are set on a subset of the data points
N_KNOTS = 4
subset = [0, 5, 10, 14]
xknots = zeros(N_KNOTS)
Y_KNOTS = 0
CONTINUITY = Y_KNOTS + N_KNOTS
LEFT = CONTINUITY + N_KNOTS
RIGHT = LEFT + 1
N_VARIABLES = RIGHT + 1
# Function passed to imsl_d_constrained_nlp
def fcn(n, x, iact, result, ierr):
if (iact == 0):
result[0] = objective(
x[Y_KNOTS:N_KNOTS], x[CONTINUITY:CONTINUITY + N_KNOTS], x[LEFT], x[RIGHT])
return
# Compute the objective function, the sum of squares error
def objective(yknots, continuity, left, right):
ppoly = cubSplineTcb(xknots, yknots,
continuity=continuity,
left=left,
right=right)
error = 0.0
for i in range(0, N_DATA):
y = cubSplineValue(log_days[i], ppoly)
diff = (y - rate[i])
error += diff * diff
return error / N_DATA
# Note: xlb and xub need to be List variables when passed to constrainedNlp
xlb = list(range(0, N_VARIABLES))
xub = list(range(0, N_VARIABLES))
xguess = zeros(N_VARIABLES)
n_constraints = 0
ibtype = 0
for i in range(0, N_KNOTS):
xlb[Y_KNOTS + i] = 0.1 # lower bound on rate
xub[Y_KNOTS + i] = 10.0 # upper bound on rate
xlb[CONTINUITY + i] = -0.95 # lower bound on continuity
xub[CONTINUITY + i] = 0.95 # upper bound on continuity
# Set bounds wide enough on LEFT and RIGHT so they are not binding
xlb[LEFT] = -100.0
xub[LEFT] = 100.0
xlb[RIGHT] = -100.0
xub[RIGHT] = 100.0
log_days = zeros(len(days))
for i in range(0, N_DATA):
log_days[i] = log10(days[i])
for i in range(0, N_KNOTS):
xknots[i] = log_days[subset[i]]
xguess[Y_KNOTS + i] = rate[subset[i]]
xguess[CONTINUITY + i] = 0.0
xguess[LEFT] = xguess[RIGHT] = 0.0
# Find the optimial curve
x = constrainedNlp(fcn, n_constraints, 0, ibtype, xlb, xub,
xguess=xguess,
difftype=3)
# Report results
ppoly = cubSplineTcb(xknots, x[0:N_KNOTS],
continuity=x[CONTINUITY:CONTINUITY + N_KNOTS])
print("Days Rate Curve Error")
for i in range(0, N_DATA):
y = cubSplineValue(log_days[i], ppoly)
print("%4d %6.3f %6.3f %6.3f" % (days[i], rate[i], y, y - rate[i]))
print()
for i in range(0, N_KNOTS):
print(" continuity[%2d] = %6.3f" % (days[i], x[CONTINUITY + i]))
print("\n left = %6.3f\n right = %6.3f" % (x[LEFT], x[RIGHT]))
Output¶
Days Rate Curve Error
3 5.018 5.019 0.002
31 4.983 4.926 -0.057
62 4.972 4.911 -0.061
94 4.962 4.919 -0.043
185 4.991 4.970 -0.021
367 5.094 5.084 -0.010
731 5.797 5.842 0.045
1096 6.306 6.340 0.034
1461 6.735 6.683 -0.052
1826 6.948 6.931 -0.017
2194 7.088 7.118 0.030
2558 7.275 7.240 -0.035
2922 7.309 7.332 0.023
3287 7.398 7.409 0.011
3653 7.490 7.479 -0.011
continuity[ 3] = 0.009
continuity[31] = -0.630
continuity[62] = -0.184
continuity[94] = -0.950
left = 0.534
right = 0.266