mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Climate PID Autotune Logging fixes (#4136)
* pid autotune logging fixes * fixed clang-format request * improved and clarified logging * changed logging not to alter the TAG * logging now does not alter TAG. fixed clang formattting * fixed string issues * playing with strings to please the clang gods * playing with strings * Delete secrets.yaml * Delete console-fan-autotune-test.yaml * Update esphome/components/pid/pid_autotuner.cpp Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> * Update esphome/components/pid/pid_autotuner.cpp Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> * Update esphome/components/pid/pid_autotuner.cpp Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> * Update esphome/components/pid/pid_autotuner.cpp Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> * Update esphome/components/pid/pid_autotuner.cpp Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --------- Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
		| @@ -1,6 +1,10 @@ | |||||||
| #include "pid_autotuner.h" | #include "pid_autotuner.h" | ||||||
| #include "esphome/core/log.h" | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
|  | #ifndef M_PI | ||||||
|  | #define M_PI 3.1415926535897932384626433 | ||||||
|  | #endif | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace pid { | namespace pid { | ||||||
|  |  | ||||||
| @@ -73,7 +77,7 @@ PIDAutotuner::PIDAutotuneResult PIDAutotuner::update(float setpoint, float proce | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (!std::isnan(this->setpoint_) && this->setpoint_ != setpoint) { |   if (!std::isnan(this->setpoint_) && this->setpoint_ != setpoint) { | ||||||
|     ESP_LOGW(TAG, "Setpoint changed during autotune! The result will not be accurate!"); |     ESP_LOGW(TAG, "%s: Setpoint changed during autotune! The result will not be accurate!", this->id_.c_str()); | ||||||
|   } |   } | ||||||
|   this->setpoint_ = setpoint; |   this->setpoint_ = setpoint; | ||||||
|  |  | ||||||
| @@ -87,7 +91,7 @@ PIDAutotuner::PIDAutotuneResult PIDAutotuner::update(float setpoint, float proce | |||||||
|  |  | ||||||
|   if (!this->frequency_detector_.has_enough_data() || !this->amplitude_detector_.has_enough_data()) { |   if (!this->frequency_detector_.has_enough_data() || !this->amplitude_detector_.has_enough_data()) { | ||||||
|     // not enough data for calculation yet |     // not enough data for calculation yet | ||||||
|     ESP_LOGV(TAG, "  Not enough data yet for aututuner"); |     ESP_LOGV(TAG, "%s:   Not enough data yet for autotuner", this->id_.c_str()); | ||||||
|     return res; |     return res; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -97,12 +101,13 @@ PIDAutotuner::PIDAutotuneResult PIDAutotuner::update(float setpoint, float proce | |||||||
|     // The frequency/amplitude is not fully accurate yet, try to wait |     // The frequency/amplitude is not fully accurate yet, try to wait | ||||||
|     // until the fault clears, or terminate after a while anyway |     // until the fault clears, or terminate after a while anyway | ||||||
|     if (zc_symmetrical) { |     if (zc_symmetrical) { | ||||||
|       ESP_LOGVV(TAG, "  ZC is not symmetrical"); |       ESP_LOGVV(TAG, "%s:   ZC is not symmetrical", this->id_.c_str()); | ||||||
|     } |     } | ||||||
|     if (amplitude_convergent) { |     if (amplitude_convergent) { | ||||||
|       ESP_LOGVV(TAG, "  Amplitude is not convergent"); |       ESP_LOGVV(TAG, "%s:   Amplitude is not convergent", this->id_.c_str()); | ||||||
|     } |     } | ||||||
|     uint32_t phase = this->relay_function_.phase_count; |     uint32_t phase = this->relay_function_.phase_count; | ||||||
|  |     ESP_LOGVV(TAG, "%s: >", this->id_.c_str()); | ||||||
|     ESP_LOGVV(TAG, "  Phase %u, enough=%u", phase, enough_data_phase_); |     ESP_LOGVV(TAG, "  Phase %u, enough=%u", phase, enough_data_phase_); | ||||||
|  |  | ||||||
|     if (this->enough_data_phase_ == 0) { |     if (this->enough_data_phase_ == 0) { | ||||||
| @@ -116,7 +121,7 @@ PIDAutotuner::PIDAutotuneResult PIDAutotuner::update(float setpoint, float proce | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   ESP_LOGI(TAG, "PID Autotune finished!"); |   ESP_LOGI(TAG, "%s: PID Autotune finished!", this->id_.c_str()); | ||||||
|  |  | ||||||
|   float osc_ampl = this->amplitude_detector_.get_mean_oscillation_amplitude(); |   float osc_ampl = this->amplitude_detector_.get_mean_oscillation_amplitude(); | ||||||
|   float d = (this->relay_function_.output_positive - this->relay_function_.output_negative) / 2.0f; |   float d = (this->relay_function_.output_positive - this->relay_function_.output_negative) / 2.0f; | ||||||
| @@ -131,12 +136,12 @@ PIDAutotuner::PIDAutotuneResult PIDAutotuner::update(float setpoint, float proce | |||||||
|   return res; |   return res; | ||||||
| } | } | ||||||
| void PIDAutotuner::dump_config() { | void PIDAutotuner::dump_config() { | ||||||
|   ESP_LOGI(TAG, "PID Autotune:"); |  | ||||||
|   if (this->state_ == AUTOTUNE_SUCCEEDED) { |   if (this->state_ == AUTOTUNE_SUCCEEDED) { | ||||||
|  |     ESP_LOGI(TAG, "%s: PID Autotune:", this->id_.c_str()); | ||||||
|     ESP_LOGI(TAG, "  State: Succeeded!"); |     ESP_LOGI(TAG, "  State: Succeeded!"); | ||||||
|     bool has_issue = false; |     bool has_issue = false; | ||||||
|     if (!this->amplitude_detector_.is_amplitude_convergent()) { |     if (!this->amplitude_detector_.is_amplitude_convergent()) { | ||||||
|       ESP_LOGW(TAG, "  Could not reliable determine oscillation amplitude, PID parameters may be inaccurate!"); |       ESP_LOGW(TAG, "  Could not reliably determine oscillation amplitude, PID parameters may be inaccurate!"); | ||||||
|       ESP_LOGW(TAG, "    Please make sure you eliminate all outside influences on the measured temperature."); |       ESP_LOGW(TAG, "    Please make sure you eliminate all outside influences on the measured temperature."); | ||||||
|       has_issue = true; |       has_issue = true; | ||||||
|     } |     } | ||||||
| @@ -173,10 +178,12 @@ void PIDAutotuner::dump_config() { | |||||||
|     print_rule_("Pessen Integral PID", 0.7f, 1.75f, 0.105f); |     print_rule_("Pessen Integral PID", 0.7f, 1.75f, 0.105f); | ||||||
|     print_rule_("Some Overshoot PID", 0.333f, 0.667f, 0.111f); |     print_rule_("Some Overshoot PID", 0.333f, 0.667f, 0.111f); | ||||||
|     print_rule_("No Overshoot PID", 0.2f, 0.4f, 0.0625f); |     print_rule_("No Overshoot PID", 0.2f, 0.4f, 0.0625f); | ||||||
|  |     ESP_LOGI(TAG, "%s: Autotune completed", this->id_.c_str()); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (this->state_ == AUTOTUNE_RUNNING) { |   if (this->state_ == AUTOTUNE_RUNNING) { | ||||||
|     ESP_LOGI(TAG, "  Autotune is still running!"); |     ESP_LOGD(TAG, "%s: PID Autotune:", this->id_.c_str()); | ||||||
|  |     ESP_LOGD(TAG, "  Autotune is still running!"); | ||||||
|     ESP_LOGD(TAG, "  Status: Trying to reach %.2f °C", setpoint_ - relay_function_.current_target_error()); |     ESP_LOGD(TAG, "  Status: Trying to reach %.2f °C", setpoint_ - relay_function_.current_target_error()); | ||||||
|     ESP_LOGD(TAG, "  Stats so far:"); |     ESP_LOGD(TAG, "  Stats so far:"); | ||||||
|     ESP_LOGD(TAG, "    Phases: %u", relay_function_.phase_count); |     ESP_LOGD(TAG, "    Phases: %u", relay_function_.phase_count); | ||||||
| @@ -221,7 +228,6 @@ float PIDAutotuner::RelayFunction::update(float error) { | |||||||
|   float output = state == RELAY_FUNCTION_POSITIVE ? output_positive : output_negative; |   float output = state == RELAY_FUNCTION_POSITIVE ? output_positive : output_negative; | ||||||
|   if (change) { |   if (change) { | ||||||
|     this->phase_count++; |     this->phase_count++; | ||||||
|     ESP_LOGV(TAG, "Autotune: Turning output to %.1f%%", output * 100); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   return output; |   return output; | ||||||
| @@ -245,10 +251,8 @@ void PIDAutotuner::OscillationFrequencyDetector::update(uint32_t now, float erro | |||||||
|  |  | ||||||
|   if (had_crossing) { |   if (had_crossing) { | ||||||
|     // Had crossing above hysteresis threshold, record |     // Had crossing above hysteresis threshold, record | ||||||
|     ESP_LOGV(TAG, "Autotune: Detected Zero-Cross at %u", now); |  | ||||||
|     if (this->last_zerocross != 0) { |     if (this->last_zerocross != 0) { | ||||||
|       uint32_t dt = now - this->last_zerocross; |       uint32_t dt = now - this->last_zerocross; | ||||||
|       ESP_LOGV(TAG, "  dt: %u", dt); |  | ||||||
|       this->zerocrossing_intervals.push_back(dt); |       this->zerocrossing_intervals.push_back(dt); | ||||||
|     } |     } | ||||||
|     this->last_zerocross = now; |     this->last_zerocross = now; | ||||||
| @@ -297,13 +301,11 @@ void PIDAutotuner::OscillationAmplitudeDetector::update(float error, | |||||||
|       // The positive error peak must have been in previous segment (180° shifted) |       // The positive error peak must have been in previous segment (180° shifted) | ||||||
|       // record phase_max |       // record phase_max | ||||||
|       this->phase_maxs.push_back(phase_max); |       this->phase_maxs.push_back(phase_max); | ||||||
|       ESP_LOGV(TAG, "Autotune: Phase Max: %f", phase_max); |  | ||||||
|     } else if (last_relay_state == RelayFunction::RELAY_FUNCTION_NEGATIVE) { |     } else if (last_relay_state == RelayFunction::RELAY_FUNCTION_NEGATIVE) { | ||||||
|       // Transitioned from negative error to positive error. |       // Transitioned from negative error to positive error. | ||||||
|       // The negative error peak must have been in previous segment (180° shifted) |       // The negative error peak must have been in previous segment (180° shifted) | ||||||
|       // record phase_min |       // record phase_min | ||||||
|       this->phase_mins.push_back(phase_min); |       this->phase_mins.push_back(phase_min); | ||||||
|       ESP_LOGV(TAG, "Autotune: Phase Min: %f", phase_min); |  | ||||||
|     } |     } | ||||||
|     // reset phase values for next phase |     // reset phase values for next phase | ||||||
|     this->phase_min = error; |     this->phase_min = error; | ||||||
|   | |||||||
| @@ -31,6 +31,8 @@ class PIDAutotuner { | |||||||
|  |  | ||||||
|   void dump_config(); |   void dump_config(); | ||||||
|  |  | ||||||
|  |   void set_autotuner_id(std::string id) { this->id_ = std::move(id); } | ||||||
|  |  | ||||||
|   void set_noiseband(float noiseband) { |   void set_noiseband(float noiseband) { | ||||||
|     relay_function_.noiseband = noiseband; |     relay_function_.noiseband = noiseband; | ||||||
|     // ZC detector uses 1/4 the noiseband of relay function (noise suppression) |     // ZC detector uses 1/4 the noiseband of relay function (noise suppression) | ||||||
| @@ -106,6 +108,7 @@ class PIDAutotuner { | |||||||
|   } state_ = AUTOTUNE_RUNNING; |   } state_ = AUTOTUNE_RUNNING; | ||||||
|   float ku_; |   float ku_; | ||||||
|   float pu_; |   float pu_; | ||||||
|  |   std::string id_; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| }  // namespace pid | }  // namespace pid | ||||||
|   | |||||||
| @@ -130,9 +130,6 @@ void PIDClimate::update_pid_() { | |||||||
|         // keep autotuner instance so that subsequent dump_configs will print the long result message. |         // keep autotuner instance so that subsequent dump_configs will print the long result message. | ||||||
|       } else { |       } else { | ||||||
|         value = res.output; |         value = res.output; | ||||||
|         if (mode != climate::CLIMATE_MODE_HEAT_COOL) { |  | ||||||
|           ESP_LOGW(TAG, "For PID autotuner you need to set AUTO (also called heat/cool) mode!"); |  | ||||||
|         } |  | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @@ -151,10 +148,24 @@ void PIDClimate::start_autotune(std::unique_ptr<PIDAutotuner> &&autotune) { | |||||||
|   float min_value = this->supports_cool_() ? -1.0f : 0.0f; |   float min_value = this->supports_cool_() ? -1.0f : 0.0f; | ||||||
|   float max_value = this->supports_heat_() ? 1.0f : 0.0f; |   float max_value = this->supports_heat_() ? 1.0f : 0.0f; | ||||||
|   this->autotuner_->config(min_value, max_value); |   this->autotuner_->config(min_value, max_value); | ||||||
|  |   this->autotuner_->set_autotuner_id(this->get_object_id()); | ||||||
|  |  | ||||||
|  |   ESP_LOGI(TAG, | ||||||
|  |            "%s: Autotune has started. This can take a long time depending on the " | ||||||
|  |            "responsiveness of your system. Your system " | ||||||
|  |            "output will be altered to deliberately oscillate above and below the setpoint multiple times. " | ||||||
|  |            "Until your sensor provides a reading, the autotuner may display \'nan\'", | ||||||
|  |            this->get_object_id().c_str()); | ||||||
|  |  | ||||||
|   this->set_interval("autotune-progress", 10000, [this]() { |   this->set_interval("autotune-progress", 10000, [this]() { | ||||||
|     if (this->autotuner_ != nullptr && !this->autotuner_->is_finished()) |     if (this->autotuner_ != nullptr && !this->autotuner_->is_finished()) | ||||||
|       this->autotuner_->dump_config(); |       this->autotuner_->dump_config(); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|  |   if (mode != climate::CLIMATE_MODE_HEAT_COOL) { | ||||||
|  |     ESP_LOGW(TAG, "%s: !!! For PID autotuner you need to set AUTO (also called heat/cool) mode!", | ||||||
|  |              this->get_object_id().c_str()); | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| void PIDClimate::reset_integral_term() { this->controller_.reset_accumulated_integral(); } | void PIDClimate::reset_integral_term() { this->controller_.reset_accumulated_integral(); } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user