Note: AI was used in the creation of this example.
GTSAM provides gtsam::CardinalSplineBasis in gtsam/basis/CardinalSplineBasis.h for cubic cardinal-spline interpolation of scalar or vector coefficients. This example inspects the dense weights, evaluates a scalar curve, and differentiates it.
Use this class when your control values live in a vector space and the sample coordinate is known. Do not use these dense weights to blend poses or rotations. For Pose2, Pose3, Rot2, or Rot3, use the separate CumulativeSplineTrajectory example, which works with Lie-group increments.
Primary contributor: Brett Downing.
Contents¶
import gtsam
import numpy as np
import plotly.graph_objects as go
from plotly.subplots import make_subplotsWhat we are building¶
We start with six ordinary scalar coefficients. At each coordinate , CalculateWeights returns one weight per coefficient. Their dot product is the spline value:
This linear combination is exactly what makes CardinalSplineBasis appropriate for scalars and vectors. A pose cannot be substituted for because scalar multiplication and addition are not defined for poses.
control_values = np.array([0.0, 1.2, -0.4, 1.6, 0.5, 1.0])
sample_times = np.linspace(0.0, len(control_values) + 2.0, 501)1. Inspect the basis weights¶
CardinalSplineBasis.CalculateWeights returns weights with local support that change smoothly and sum to one. That partition-of-unity property preserves a constant set of coefficients. Near the ends, the first and last weights absorb the padded tails.
basis_weights = np.vstack([
gtsam.CardinalSplineBasis.CalculateWeights(len(control_values), float(time))
for time in sample_times
])
np.testing.assert_allclose(basis_weights.sum(axis=1), 1.0, atol=1e-12)Source
weights_figure = go.Figure()
for index in range(len(control_values)):
weights_figure.add_scatter(
x=sample_times,
y=basis_weights[:, index],
name=f"B{index}(t)",
)
weights_figure.update_layout(
title="Cubic cardinal-spline basis weights from C++",
xaxis_title="coordinate t",
yaxis_title="basis weight",
template="plotly_white",
hovermode="x unified",
)
weights_figure.show()2. Evaluate and differentiate a scalar spline¶
The curve is a matrix-vector product between the sampled basis weights and the coefficients. DerivativeWeights supplies the analytic derivative of the same C++ basis, so no finite differencing or Python spline implementation is needed.
derivative_weights = np.vstack([
gtsam.CardinalSplineBasis.DerivativeWeights(
len(control_values), float(time)
)
for time in sample_times
])
spline_values = basis_weights @ control_values
spline_derivatives = derivative_weights @ control_valuesSource
curve_figure = make_subplots(
rows=2,
cols=1,
shared_xaxes=True,
subplot_titles=("scalar spline", "analytic derivative"),
)
curve_figure.add_scatter(
x=sample_times, y=spline_values, name="f(t)", row=1, col=1
)
curve_figure.add_scatter(
x=sample_times,
y=spline_derivatives,
name="df/dt",
row=2,
col=1,
)
curve_figure.update_xaxes(title_text="coordinate t", row=2, col=1)
curve_figure.update_yaxes(title_text="value", row=1, col=1)
curve_figure.update_yaxes(title_text="value / coordinate", row=2, col=1)
curve_figure.update_layout(
title="A scalar curve evaluated with CardinalSplineBasis",
template="plotly_white",
hovermode="x unified",
height=650,
)
curve_figure.show()Which spline API should I use?¶
Use CardinalSplineBasis when the coefficients are scalars or vectors and the sample coordinate is known. Its dense weights integrate with GTSAM’s Basis functors and basis factors.
Use CumulativeSplineTrajectory<T> when the controls are poses, rotations, or another Lie group; when the sample time is an expression; or when a bounded time window should keep the expression graph sparse. It weights tangent-space increments rather than applying dense weights directly to group elements.
Both constructions use the cubic IrwinHallCDF2 kernel internally, but they are not interchangeable APIs for Lie-group data. Continue with the CardinalSplineBasis user guide for the mathematical relationship and C++ usage, or the separate CumulativeSplineTrajectory guide for Lie-group trajectories.