blob: 9d26e56bdb24dc6ae68b493a2b15749e23ca8f7a [file]
#ifndef THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_THERMAL_CONTROLLER_EAT_H_
#define THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_THERMAL_CONTROLLER_EAT_H_
#include <chrono> // NOLINT
#include <optional>
#include "absl/time/time.h"
#include "thermal_config.pb.h"
namespace milotic_tlbmc {
namespace thermal {
/*
* `EatThermalLoop` is the Entering Air Temperature thermal loop, which is
* used to adjust setpoint of the other thermal controllers, based on concurrent
* ambient temperature, to save energies.
*
* An EAT (Entering Air Temperature) based loop can enhance the Cooling Enhanced
* Reliability (CER) system. It leverages the relationship between CAT (Cool Air
* Temperature) and component temperature setpoints. As the CAT decreases, the
* system temperature setpoint can be lowered accordingly. By proactively
* adapting to fluctuations in CAT, the system can operate within optimal
* temperature ranges, thereby mitigating the risk of thermal stress and
* premature failure.
*
* This class is not thread-safe. This is copiable and movable.
*
* Reference:
* https://quanta-bmc-private.git.corp.google.com/misc/+/refs/heads/master/hdd-setpoint-control
* go/eat-neutron
*/
class EatThermalLoop {
public:
EatThermalLoop() = default;
explicit EatThermalLoop(const EatLoopConfig& eat_params,
std::chrono::steady_clock::time_point now =
std::chrono::steady_clock::now())
: eat_params_(eat_params) {
// If no valid EAT calculation interval is provided, set it to 24 (hours) by
// default.
if (eat_params.calculation_interval_hour() <= 0) {
eat_params_.set_calculation_interval_hour(24);
}
Reset(now);
}
/*
* `ExecuteEatLoop` performs exactly one iteration of a DFF loop with the
* current input.
*
* If it has passed the calculation interval since the last calculation,
* `ExecuteEatLoop` will return the calculated EAT value using the average
* recorded temperatures. Otherwise, it will record `temperature` and return
* nullopt.
*/
std::optional<double> ExecuteEatLoop(
double temperature, std::chrono::steady_clock::time_point now =
std::chrono::steady_clock::now());
double GetOutputLimitMax() const { return eat_params_.output_limit_max(); }
double GetOutputLimitMin() const { return eat_params_.output_limit_min(); }
double GetSlewNeg() const { return eat_params_.slew_neg(); }
double GetSlewPos() const { return eat_params_.slew_pos(); }
double GetCalculationIntervalHour() const {
return eat_params_.calculation_interval_hour();
}
double GetReferenceEat() const { return eat_params_.reference_eat(); }
/*
* `CalculateAndSetReferenceEat` calculates the new reference EAT based on the
* average EAT and the current reference EAT, and updates & returns the newly
* derived reference EAT.
*/
double CalculateAndSetReferenceEat(double average_eat);
/*
* `Reset` resets the sum of ambient temperature and the recorded temperature
* count to 0, and the last calculation time to `now`.
*/
void Reset(std::chrono::steady_clock::time_point now =
std::chrono::steady_clock::now());
private:
double sum_ambient_temperature_ = 0.0;
int recorded_temperature_count_ = 0;
// The last time when the EAT calculation was executed.
std::chrono::steady_clock::time_point last_calculation_time_;
// `tolerable_interval_epsilon_` enables a small flexibility in the interval
// between the current time and the last calculation time. By using
// `std::chrono::steady_clock::time_point`, sometimes when `EatThermalLoop`
// receive a calculation request, there can be a minor chance to miss, as the
// precision of `time_point` is extremely high and down to ns (e.g.,
// 59m59.99999996s).
absl::Duration tolerable_interval_epsilon_ = absl::Seconds(60);
// The parameters for this EAT thermal loop.
EatLoopConfig eat_params_;
};
} // namespace thermal
} // namespace milotic_tlbmc
#endif // THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_THERMAL_CONTROLLER_EAT_H_