blob: fe388d7d17dcd85648a6c9ac3462b7a62580a70d [file]
#include "tlbmc/thermal/controller/algorithm/utils/nonlinear_tracking_differentiator.h"
#include <cmath>
#include <cstdlib>
namespace milotic_tlbmc {
namespace thermal {
double NonlinearTrackingDifferentiator::Fhan(double v1, double v2, double r,
double h0) {
// Calculate the linear boundary zone threshold.
double d = r * h0 * h0;
// Predict the distance the system will coast over one time step.
double a0 = h0 * v2;
// Predict the position error one time-step into the future.
double y = v1 + a0;
// Compute an intermediate geometric curve variable.
// Standard formula: `a_{0std} = sqrt((r * h0)^{2} + 8 * r * |y|)`.
// By keeping the terms scaled by `h_{0}^{2}` inside the square root, this
// efficiently computes the equivalent of `(h_{0} * a_{0std})` without needing
// any division.
double a1 = std::sqrt(d * (d + 8.0 * std::abs(y)));
// Evaluate which side of the linear boundary the predicted error is in.
double a;
if (std::abs(y) > d) {
a = a0 + 0.5 * (a1 - d) * (y > 0 ? 1.0 : -1.0);
} else {
a = a0 + y;
}
// Output the final optimal tracking control action.
// Apply maximum acceleration if `a` is outside the boundary, otherwise simply
// apply a linearly scaled fraction of `r`.
return (std::abs(a) > d ? r * (a > 0 ? 1.0 : -1.0) : r * a / d);
}
NtdOutput NonlinearTrackingDifferentiator::FilterInput(double input) {
double error = ntd_output_.filtered_output - input;
double f = Fhan(error, ntd_output_.filtered_derivative, r_, h0_);
// Discrete integration via Euler-forward to update tracking states.
ntd_output_.filtered_output +=
ntd_sample_time_sec_ * ntd_output_.filtered_derivative;
ntd_output_.filtered_derivative -= ntd_sample_time_sec_ * f;
return ntd_output_;
}
} // namespace thermal
} // namespace milotic_tlbmc