| #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 |