| #ifndef THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_THERMAL_CONTROLLER_STEPWISE_H_ |
| #define THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_THERMAL_CONTROLLER_STEPWISE_H_ |
| |
| #include <limits> |
| #include <vector> |
| |
| #include "thermal_config.pb.h" |
| |
| namespace milotic_tlbmc { |
| namespace thermal { |
| |
| /* |
| * `StepwiseThermalLoop` is a thermal control algorithm that outputs a value |
| * different from the last output only when the delta between the current and |
| * the last input that triggered an output search is large enough. |
| * |
| * If the delta is large enough, the triggered output search will return the |
| * corresponding `output` of the largest manually configured `threshold` that is |
| * smaller than or equal to `input`. |
| * |
| * This class is not thread-safe. |
| * |
| * This class is created and revised based on the stepwise structs at |
| * https://github.com/openbmc/phosphor-pid-control/blob/master/pid/ec/stepwise.hpp |
| * and the stepwise controller at |
| * https://github.com/openbmc/phosphor-pid-control/blob/master/pid/stepwisecontroller.hpp |
| */ |
| class StepwiseThermalLoop { |
| public: |
| StepwiseThermalLoop() = default; |
| |
| explicit StepwiseThermalLoop(const StepwiseLoopConfig& stepwise_params) |
| : stepwise_params_(stepwise_params) { |
| if (stepwise_params.sample_time_sec() <= 0) { |
| stepwise_params_.set_sample_time_sec(1.0); |
| } |
| } |
| |
| /* |
| * `ExecuteStepwiseLoop` performs exactly one iteration of a stepwise loop. |
| * |
| * If this is the first iteration, or the delta between the current and the |
| * last input is larger than the corresponding hysteresis value, it will |
| * proceed to the next step, otherwise, the last output will be returned. |
| * |
| * As the next step, it will output the corresponding `stepwise_output` |
| * of the largest manually configured `threshold` that is smaller than or |
| * equal to `input`. |
| * |
| * If no such critical point exists (i.e., `input` is smaller than the |
| * smallest `threshold`), it will output the `stepwise_output` of the first |
| * critical point by default. |
| */ |
| double ExecuteStepwiseLoop(double input); |
| |
| void SetCriticalPoints( |
| const std::vector<StepwiseCriticalPoint>& critical_points) { |
| stepwise_params_.clear_critical_points(); |
| for (const StepwiseCriticalPoint& critical_point : critical_points) { |
| *stepwise_params_.add_critical_points() = critical_point; |
| } |
| } |
| |
| StepwiseCriticalPoint GetCriticalPointAt(int index) const { |
| return stepwise_params_.critical_points(index); |
| } |
| int GetCriticalPointsSize() const { |
| return stepwise_params_.critical_points_size(); |
| } |
| |
| void SetPositiveHysteresis(double positive_hysteresis) { |
| stepwise_params_.set_positive_hysteresis(positive_hysteresis); |
| } |
| double GetPositiveHysteresis() const { |
| return stepwise_params_.positive_hysteresis(); |
| } |
| |
| void SetNegativeHysteresis(double negative_hysteresis) { |
| stepwise_params_.set_negative_hysteresis(negative_hysteresis); |
| } |
| double GetNegativeHysteresis() const { |
| return stepwise_params_.negative_hysteresis(); |
| } |
| |
| void SetLastInput(double last_input) { last_input_ = last_input; } |
| double GetLastInput() const { return last_input_; } |
| |
| void SetLastOutput(double last_output) { last_output_ = last_output; } |
| double GetLastOutput() const { return last_output_; } |
| |
| double GetSampleTime() const { return stepwise_params_.sample_time_sec(); } |
| |
| protected: |
| double FindStepwiseOutput(double input) const; |
| |
| private: |
| double last_input_ = std::numeric_limits<double>::quiet_NaN(); |
| double last_output_ = std::numeric_limits<double>::quiet_NaN(); |
| |
| StepwiseLoopConfig |
| stepwise_params_; // The parameters for this stepwise thermal loop. |
| }; |
| |
| } // namespace thermal |
| } // namespace milotic_tlbmc |
| |
| #endif // THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_THERMAL_CONTROLLER_STEPWISE_H_ |