blob: f4bbe511a433347548add6b45c94e27ed81e582f [file]
#include "tlbmc/thermal/controller/algorithm/second_order_adrc.h"
#include <algorithm>
#include <vector>
#include "absl/log/log.h"
#include "absl/strings/str_format.h"
#include "absl/types/span.h"
#include "tlbmc/thermal/controller/algorithm/utils/nonlinear_tracking_differentiator.h"
namespace milotic_tlbmc {
namespace thermal {
double SecondOrderAdrcThermalLoop::ExecuteSecondOrderAdrcLoop(
double setpoint, double input, absl::Span<const double> disturbances,
bool enable_calculation_log) {
// Attempt to filter `input` if NTD is configured.
if (tracking_differentiator_.has_value()) {
NtdOutput ntd_out = tracking_differentiator_->FilterInput(input);
// Note that the filtered derivative is not used explicitly in 2nd order
// ADRC, as `x_hat_[1]` already provides the derivative estimation.
input = ntd_out.filtered_output;
}
// Derive the error
double y_hat = x_hat_[0] / kp_over_b0_;
double error = input - y_hat;
// Calculate and clamp `u(t)`
double u_t = u_precompute_ - (gain_sum_ * error);
u_t = std::clamp(u_t, second_order_adrc_params_.u_limit_min(),
second_order_adrc_params_.u_limit_max());
// Calculate disturbance sum for observer update and precomputation.
double disturbance_sum = 0.0;
if (!disturbances.empty()) {
for (int i = 0; i < disturbance_factors_.size(); ++i) {
disturbance_sum +=
disturbance_factors_[i].d *
(disturbance_factors_[i].reference_setpoint - disturbances[i]);
}
}
// Update observer states
double corr[3];
for (int i = 0; i < 3; ++i) {
corr[i] = x_hat_[i] + l_hat_[i] * error;
}
double next_x[3];
for (int i = 0; i < 3; ++i) {
next_x[i] =
b_hat_[i] * (u_t + disturbance_sum / second_order_adrc_params_.b0());
for (int j = 0; j < 3; ++j) {
next_x[i] += a_hat_[i][j] * corr[j];
}
}
// Shift states
x_hat_[0] = next_x[0];
x_hat_[1] = next_x[1];
if (!IsSaturated(u_t)) {
x_hat_[2] = next_x[2];
}
// Precompute for the next sampling period (i.e., `u(t + 1)`)
u_precompute_ = (kp_over_b0_ * setpoint) -
(x_hat_[0] + x_hat_[1] + x_hat_[2]) -
(disturbance_sum / second_order_adrc_params_.b0());
if (enable_calculation_log) {
LOG(WARNING)
<< "[Thermal Debug]: "
<< absl::StrFormat(
"Executed 2nd-order ADRC loop: setpoint = %lf; input = %lf; "
"disturbance_sum = %lf; y_hat = %lf; error = %lf; u_t = %lf; "
"x_hat_ = [%lf, %lf, %lf]; u_precompute_ = %lf",
setpoint, input, disturbance_sum, y_hat, error, u_t, x_hat_[0],
x_hat_[1], x_hat_[2], u_precompute_);
}
return u_t;
}
} // namespace thermal
} // namespace milotic_tlbmc