Cubic Spline Interpolation

C²-continuous spline interpolation with smooth first and second derivatives.


Two Fundamental BC Categories

Cubic splines require boundary conditions at both endpoints. There are two fundamentally different approaches:

CategoryAlgorithmMathematical Meaning
BCPairStandard tridiagonalIndependent constraints at each endpoint
PeriodicBCSherman-Morrison cyclicTrue periodic: $S(x) = S(x+\tau)$ with C² continuity

1. BCPair: Independent Endpoint Constraints

Each endpoint has its own PointBC constraint — either first or second derivative:

BCPair(left::PointBC, right::PointBC)

# PointBC types:
Deriv1(v)   # S'(endpoint) = v   (slope)
Deriv2(v)   # S''(endpoint) = v  (curvature)

Examples:

BCPair(Deriv2(0), Deriv2(0))      # Natural: zero curvature at both ends
BCPair(Deriv1(0), Deriv1(0))      # Clamped: zero slope at both ends
BCPair(Deriv1(1.0), Deriv2(0))    # Mixed: slope=1 at left, curvature=0 at right
BCPair(Deriv2(-2.0), Deriv1(0.5)) # Mixed: curvature=-2 at left, slope=0.5 at right

Convenience shortcuts:

ShortcutEquivalentMeaning
NaturalBC()BCPair(Deriv2(0), Deriv2(0))S''=0 at both ends — default
ClampedBC()BCPair(Deriv1(0), Deriv1(0))S'=0 at both ends (flat)

2. PeriodicBC: True Periodic C² Continuity

The spline satisfies periodicity with period $\tau = x_n - x_0$:

\[S(x) = S(x + \tau), \quad S'(x) = S'(x + \tau), \quad S''(x) = S''(x + \tau)\]

PeriodicBC()
Periodicity Requirement

Your data must satisfy y[1] ≈ y[end]. If this condition is violated, the spline will still be computed but won't represent a truly periodic function.

Different Algorithm

PeriodicBC uses the Sherman-Morrison formula to solve a cyclic tridiagonal system. This is fundamentally different from BCPair's standard tridiagonal solver.


Usage

using FastInterpolations

x = range(0.0, 2π, 15)
y = sin.(x)

# One-shot evaluation (default: NaturalBC)
cubic_interp(x, y, 1.0)
cubic_interp(x, y, 1.0; bc=ClampedBC())            # flat endpoints
cubic_interp(x, y, 1.0; bc=BCPair(Deriv1(1), Deriv2(0)))  # custom

# Periodic (closed curve) - requires y[1] ≈ y[end]
cubic_interp(x, y, 1.0; bc=PeriodicBC())

# In-place evaluation (zero allocation)
xq = range(x[1], x[end], 200)
out = similar(xq)
cubic_interp!(out, x, y, xq)

# Create reusable interpolant
itp = cubic_interp(x, y; bc=NaturalBC())
itp(1.0)    # evaluate at single point
itp(xq)     # evaluate at multiple points

# Derivatives
cubic_interp(x, y, 1.0; deriv=1)  # continuous first derivative
d1 = deriv1(itp); d1(1.0)         # same via interpolant
d2 = deriv2(itp); d2(1.0)         # continuous second derivative

When to Use Each BC

SituationRecommended BC
General data, unknown endpoint behaviorNaturalBC() (default)
Endpoints should be flat (zero slope)ClampedBC()
Known endpoint derivatives (physics)BCPair(Deriv1(...), Deriv1(...))
Cyclic data (angles, phases, time-of-day)PeriodicBC()

Visual Comparison: NaturalBC vs PeriodicBC

Comparing cos(x) interpolation — note that cos''(x) = -cos(x) ≠ 0 at endpoints:

using FastInterpolations

# Uniform grid (9 points)
x = range(0, 2π, 9)
y = cos.(x)
xq = range(0, 2π, 500)

itp_natural = cubic_interp(x, y; bc=NaturalBC())
itp_periodic = cubic_interp(x, y; bc=PeriodicBC())

# Compare: S(x), S'(x), S''(x) for both BCs
d1_nat, d2_nat = deriv1(itp_natural), deriv2(itp_natural)
d1_per, d2_per = deriv1(itp_periodic), deriv2(itp_periodic)
Example block output
Key Observation
  • NaturalBC forces S''(0) = S''(2π) = 0, but true cos''(x) = -cos(x) = -1 at endpoints → mismatch
  • PeriodicBC allows S''(0) = S''(2π) to match naturally through cyclic continuity