93 lines
3.3 KiB
Plaintext
93 lines
3.3 KiB
Plaintext
[/
|
|
Copyright (c) 2020 Nick Thompson
|
|
Use, modification and distribution are subject to the
|
|
Boost Software License, Version 1.0. (See accompanying file
|
|
LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
]
|
|
|
|
[section:makima Modified Akima interpolation]
|
|
|
|
[heading Synopsis]
|
|
|
|
#include <boost/math/interpolators/makima.hpp>
|
|
|
|
namespace boost::math::interpolators {
|
|
|
|
template <class RandomAccessContainer>
|
|
class makima
|
|
{
|
|
public:
|
|
|
|
using Real = RandomAccessContainer::value_type;
|
|
|
|
makima(RandomAccessContainer&& abscissas, RandomAccessContainer&& ordinates,
|
|
Real left_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN(),
|
|
Real right_endpoint_derivative = std::numeric_limits<Real>::quiet_NaN());
|
|
|
|
Real operator()(Real x) const;
|
|
|
|
Real prime(Real x) const;
|
|
|
|
void push_back(Real x, Real y);
|
|
|
|
friend std::ostream& operator<<(std::ostream & os, const makima & m);
|
|
};
|
|
|
|
} // namespaces
|
|
|
|
|
|
[heading Modified Akima Interpolation]
|
|
|
|
The modified Akima interpolant takes non-equispaced data and interpolates between them via cubic Hermite polynomials whose slopes are chosen by a modification of a geometric construction proposed by [@https://doi.org/10.1145/321607.321609 Akima].
|
|
The modification is given by [@https://blogs.mathworks.com/cleve/2019/04/29/makima-piecewise-cubic-interpolation/ Cosmin Ionita] and agrees with Matlab's version.
|
|
The interpolant is /C/[super 1] and evaluation has [bigo](log(/N/)) complexity.
|
|
This is faster than barycentric rational interpolation, but also less smooth.
|
|
An example usage is as follows:
|
|
|
|
std::vector<double> x{1, 5, 9 , 12};
|
|
std::vector<double> y{8,17, 4, -3};
|
|
using boost::math::interpolators::makima;
|
|
auto spline = makima(std::move(x), std::move(y));
|
|
// evaluate at a point:
|
|
double z = spline(3.4);
|
|
// evaluate derivative at a point:
|
|
double zprime = spline.prime(3.4);
|
|
|
|
Periodically, it is helpful to see what data the interpolator has, and the slopes it has chosen.
|
|
This can be achieved via
|
|
|
|
std::cout << spline << "\n";
|
|
|
|
Note that the interpolator is pimpl'd, so that copying the class is cheap, and hence it can be shared between threads.
|
|
(The call operator and `.prime()` are threadsafe.)
|
|
|
|
One unique aspect of this interpolator is that it can be updated in constant time.
|
|
Hence we can use `boost::circular_buffer` to do real-time interpolation:
|
|
|
|
#include <boost/circular_buffer.hpp>
|
|
...
|
|
boost::circular_buffer<double> initial_x{1,2,3,4};
|
|
boost::circular_buffer<double> initial_y{4,5,6,7};
|
|
auto circular_akima = makima(std::move(initial_x), std::move(initial_y));
|
|
// interpolate via call operation:
|
|
double y = circular_akima(3.5);
|
|
// add new data:
|
|
circular_akima.push_back(5, 8);
|
|
// interpolat at 4.5:
|
|
y = circular_akima(4.5);
|
|
|
|
|
|
|
|
[$../graphs/makima_vs_cubic_b.svg]
|
|
|
|
The modified Akima spline compared to the cubic /B/-spline.
|
|
The modified Akima spline oscillates less than the cubic spline, but has less smoothness and is not exact on quadratic polynomials.
|
|
|
|
|
|
[heading Complexity and Performance]
|
|
|
|
The complexity and performance is identical to that of the cubic Hermite interpolator, since this object simply constructs derivatives and forwards the data to `cubic_hermite.hpp`.
|
|
|
|
[endsect]
|
|
[/section:makima]
|