blob: 1ad23f5b1edac97aa0e5a7c56aaf5831468fa188 [file]
#include "tlbmc/thermal/controller/eat_controller.h"
#include <cmath>
#include <limits>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include <nlohmann/json_fwd.hpp>
#include "tlbmc/thermal/zone_manager.h"
namespace milotic_tlbmc {
namespace thermal {
absl::StatusOr<std::unique_ptr<EatController>> EatController::Create(
EatControllerParameters params) {
if (params.input_sensors.empty()) {
return absl::InvalidArgumentError(absl::StrFormat(
"No input sensor is assigned to EAT controller `%s`!", params.id));
}
if (params.affected_zone_ids.empty()) {
return absl::InvalidArgumentError(absl::StrFormat(
"No affected zone is assigned to EAT controller `%s`!", params.id));
}
return absl::WrapUnique(new EatController(
params.id, params.zone_manager, std::move(params.eat_loop),
std::move(params.input_sensors), std::move(params.affected_zones),
std::move(params.affected_zone_ids)));
}
void EatController::ProcessThermalLoop() {
double average_sensor_value = ProcessInput();
std::optional<double> eat_value =
eat_loop_->ExecuteEatLoop(average_sensor_value);
if (eat_value) {
ProcessOutput(eat_value.value());
}
}
double EatController::ProcessInput() {
int valid_sensor_input_count = 0;
double sum_sensor_value = 0.0;
for (const std::string& sensor_id : input_sensors_) {
double sensor_value =
zone_owner_->GetSensorReadings(sensor_id).scaled_value;
if (std::isnan(sensor_value) || !std::isfinite(sensor_value)) {
continue;
}
valid_sensor_input_count++;
sum_sensor_value += sensor_value;
}
return (valid_sensor_input_count > 0
? sum_sensor_value / static_cast<double>(valid_sensor_input_count)
: std::numeric_limits<double>::quiet_NaN());
}
void EatController::ProcessOutput(double output) {
for (ZoneManager* affected_zone : affected_zones_) {
affected_zone->AdjustSetpoint(output);
zone_owner_->TryLogThermalDebugMessage(absl::StrFormat(
"Zone %d offsets setpoint by %f, requested by EAT controller `%s`",
affected_zone->GetId(), output, id_));
}
if (zone_owner_->GetDebugEnabled()) {
zone_owner_->AppendSampledData(absl::StrCat(output, ","));
}
}
nlohmann::json EatController::ToJson() const {
nlohmann::json json;
json["NegativeSlewRate"] = eat_loop_->GetSlewNeg();
json["PositiveSlewRate"] = eat_loop_->GetSlewPos();
json["OutLimitMax"] = eat_loop_->GetOutputLimitMax();
json["OutLimitMin"] = eat_loop_->GetOutputLimitMin();
json["AffectedZoneIds"] = nlohmann::json::array();
for (int affected_zone_id : affected_zone_ids_) {
json["AffectedZoneIds"].push_back(affected_zone_id);
}
json["Inputs"] = nlohmann::json::array();
for (const std::string& input : input_sensors_) {
json["Inputs"].push_back(input);
}
return json;
}
} // namespace thermal
} // namespace milotic_tlbmc