File chebyshev_util.hpp¶
File List > astrea > math > math > chebyshev_util.hpp
Go to the documentation of this file
#pragma once
#include <array>
#include <stdexcept>
namespace astrea {
namespace math {
double transform_from_chebyshev_range(const double& x, const double& lb, const double& ub);
double transform_to_chebyshev_range(const double& x, const double& lb, const double& ub);
template <std::size_t N>
double evaluate_chebyshev_polynomial(
const double& x,
const double& lb,
const double& ub,
const std::array<double, N>& coeff,
const double& coeffZeroFactor = 0.5,
const double& extrapolationTol = 1.0e-6
)
{
// Error checking
static_assert(N > 2, "evaluate_chebyshev_polynomial() - Size of coeff vector must be greater than zero.");
if (x < lb && std::abs(x - lb) > extrapolationTol) {
throw std::invalid_argument(
"evaluate_chebyshev_polynomial() - Value provided for x is outside of the lower bound for the "
"interpolant."
);
}
else if (x > ub && std::abs(x - ub) > extrapolationTol) {
throw std::invalid_argument(
"evaluate_chebyshev_polynomial() - Value provided for x is outside of the upper bound for the "
"interpolant."
);
}
// Set the order or degree of the Chebyshev polynomial
const std::size_t order = N - 1;
// Perform change of variables
const double y = transform_to_chebyshev_range(x, lb, ub);
const double y2 = 2.0 * y;
// Apply Clenshaw's recurrence formula in reverse to preserve small numbers
double d = 0.0, dd = 0.0, sv = 0.0;
for (std::size_t k = order; k >= 1; k--) {
sv = d;
d = y2 * d - dd + coeff[k];
dd = sv;
}
// To be compatible with CSpice, don't multiply coeff[0] by 0.5
return y * d - dd + coeffZeroFactor * coeff[0];
}
template <std::size_t N>
double evaluate_chebyshev_polynomial(const double& x, const std::array<double, N>& boundsCoeff, const double& coeffZeroFactor = 0.5, const double& extrapolationTol = 1.0e-6)
{
// Error Checking
static_assert(N > 2, "evaluate_chebyshev_polynomial() - Size of boundsCoeff array must be greater than or equal to three.");
// Extract lb, ub, and coefficients
std::array<double, N - 2> coeff;
for (std::size_t k = 0; k < N - 2; k++) {
coeff[k] = boundsCoeff[k + 2];
}
// Evaluate the Chebyshev polynomial
return evaluate_chebyshev_polynomial(x, boundsCoeff[0], boundsCoeff[1], coeff, coeffZeroFactor, extrapolationTol);
}
template <size_t N>
double evaluate_chebyshev_derivative(double x, double lb, double ub, const std::array<double, N>& coeff, double extrapolationTol = 1.0e-6)
{
// Error checking
static_assert(N > 0, "evaluate_chebyshev_derivative() - Size of coeff array must be greater than zero.");
if (x < lb && std::abs(x - lb) > extrapolationTol) {
throw std::invalid_argument(
"evaluate_chebyshev_derivative() - Value provided for x is outside of the lower bound for "
"the interpolant."
);
}
else if (x > ub && std::abs(x - ub) > extrapolationTol) {
throw std::invalid_argument(
"evaluate_chebyshev_derivative() - Value provided for x is outside of the upper bound for "
"the interpolant."
);
}
// Perform change of variables
const double y = transform_to_chebyshev_range(x, lb, ub);
const double y2 = 2.0 * y;
// Apply Clenshaw's recurrence formula in reverse to preserve small numbers
double d = 0.0, dd = 0.0, sv = 0.0;
double dp = 0.0, ddp = 0.0, svp = 0.0;
for (std::size_t k = N - 1; k >= 1; k--) {
// Compute the derivative coefficient values
svp = dp;
dp = y2 * dp - ddp + 2.0 * d;
ddp = svp;
// Compute the coefficient values, which are required by the derivative
sv = d;
d = y2 * d - dd + coeff[k];
dd = sv;
}
// Normalize to the interval ub - lb
return 2.0 / (ub - lb) * (y * dp - ddp + d);
}
template <size_t N>
double evaluate_chebyshev_derivative(double x, const std::array<double, N>& boundsCoeff, double extrapolationTol = 1.0e-6)
{
// Error Checking
static_assert(N > 2, "evaluate_chebyshev_derivative() - Size of boundsCoeff array must be greater than or equal to three.");
// Extract lb, ub, and coefficients
std::array<double, N - 2> coeff;
for (std::size_t k = 0; k < N - 2; k++) {
coeff[k] = boundsCoeff[k + 2];
}
// Evaluate the Chebyshev polynomial
return evaluate_chebyshev_derivative(x, boundsCoeff[0], boundsCoeff[1], coeff, extrapolationTol);
}
} // namespace math
} // namespace astrea