I've been investigating spline interpolation and here is some of my results.
I wanted to find out if there was any way to bridge the gap between the commonly used 4-point cubic spline and 512-point sinc interpolation, both in terms of performance and quality.
All code below is placed in the public domain.
Spline polynomials of third order (aka cubic splines):
- Continuous first derivate everywhere.
- Continuous second derivate on all segments except the last.
Code: Select all
template<class T, class BufT>
T interpolate_spline3_6pt(const T t, const BufT* x)
{
return (t*(t*(t*(T(17)*(x[2]-x[3]) + T(9)*(x[4]-x[1]) + T(2)*(x[0]-x[5])) +
(T(20)*(x[1]+x[3]) + T(2)*x[5] - T(4)*x[0] - T(7)*x[4] - T(31)*x[2])) +
(T(11)*(x[3]-x[1]) + T(2)*(x[0]-x[4])))) / T(14) + x[2];
}
Code: Select all
template<class T, class BufT>
T interpolate_spline3_8pt(const T t, const BufT* x)
{
return (t*(t*(t*(T(91)*(x[3]-x[4]) + T(45)*(x[5]-x[2]) + T(13)*(x[1]-x[6]) + T(3)*(x[7]-x[0])) +
(T(106)*(x[2]+x[4]) + T(10)*x[6] + T(6)*x[0] - T(3)*x[7] - T(29)*(x[1]+x[5]) - T(167)*x[3])) +
(T(61)*(x[4]-x[2]) + T(16)*(x[1]-x[5]) + T(3)*(x[6]-x[0])))) / T(76) + x[3];
}
Spline polynomials of fifth order (aka quintic splines):
- Continuous first, second and third derivate everywhere.
- Continuous fourth derivate on all segments except the last.
Code: Select all
template<class T, class BufT>
T interpolate_spline5_6pt(const T t, const BufT* x)
{
return (t*(t*(t*(t*(t*(T(841)*(x[3]-x[2]) + T(677)*(x[1]-x[4]) + T(238)*(x[5]-x[0])) +
(T(2379)*x[2] + T(1559)*x[4] + T(452)*x[0] - T(738)*x[5] - T(1826)*(x[1]+x[3]))) +
(T(606)*(x[1]-x[3]) + T(500)*(x[5]-x[2]) + T(72)*(x[0]-x[4]))) +
(T(1820)*(x[1]+x[3]) - T(548)*(x[0]+x[4]) - T(2544)*x[2])) +
(T(1277)*(x[3]-x[1]) + T(262)*(x[0]-x[4])))) / T(1506) + x[2];
}
Code: Select all
template<class T, class BufT>
T interpolate_spline5_8pt(const T t, const BufT* x)
{
return (t*(t*(t*(t*(t*(T(6489)*(x[4]-x[3]) + T(4831)*(x[2]-x[5]) + T(3089)*(x[6]-x[1]) + T(1063)*(x[0]-x[7])) +
(T(17352)*x[3] + T(9062)*(x[1]+x[5]) + T(3204)*x[7] - T(2111)*x[0] - T(6383)*x[6] - T(15093)*(x[2]+x[4]))) +
(T(6659)*(x[2]-x[4]) + T(5403)*(x[5]-x[1]) + T(2141)*(x[3]-x[7]) + T(45)*(x[6]-x[0]))) +
(T(17169)*(x[2]+x[4]) + T(2171)*(x[0]+x[6]) - T(5102)*(x[1]+x[5]) - T(28476)*x[3])) +
(T(13566)*(x[4]-x[2]) + T(4532)*(x[1]-x[5]) + T(1078)*(x[6]-x[0])))) / T(15472) + x[3];
}
Why not have second (or fourth) derivate continuous everywhere?
I had a constraint that there must be unity gain for all values of t, and give straight lines when interpolating stair-steps. This is important since otherwise you'd get "wobbly" lines, which results in a high pitched signal artifact.
This constraint is why the splines can't have their second (or fourth) derivate continuous everywhere, as there is no solution to the equation systems that fulfill both constraints.
Plot of impulse response, together with the 5-point spline from musicdsp:

Close-up of the passband:




