mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Calculating the AC only component of the samples (#1906)
Co-authored-by: Synco Reynders <synco@deviceware.co.nz> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
		| @@ -8,18 +8,6 @@ namespace ct_clamp { | |||||||
|  |  | ||||||
| static const char *const TAG = "ct_clamp"; | static const char *const TAG = "ct_clamp"; | ||||||
|  |  | ||||||
| void CTClampSensor::setup() { |  | ||||||
|   this->is_calibrating_offset_ = true; |  | ||||||
|   this->high_freq_.start(); |  | ||||||
|   this->set_timeout("calibrate_offset", this->sample_duration_, [this]() { |  | ||||||
|     this->high_freq_.stop(); |  | ||||||
|     this->is_calibrating_offset_ = false; |  | ||||||
|     if (this->num_samples_ != 0) { |  | ||||||
|       this->offset_ = this->sample_sum_ / this->num_samples_; |  | ||||||
|     } |  | ||||||
|   }); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void CTClampSensor::dump_config() { | void CTClampSensor::dump_config() { | ||||||
|   LOG_SENSOR("", "CT Clamp Sensor", this); |   LOG_SENSOR("", "CT Clamp Sensor", this); | ||||||
|   ESP_LOGCONFIG(TAG, "  Sample Duration: %.2fs", this->sample_duration_ / 1e3f); |   ESP_LOGCONFIG(TAG, "  Sample Duration: %.2fs", this->sample_duration_ / 1e3f); | ||||||
| @@ -27,9 +15,6 @@ void CTClampSensor::dump_config() { | |||||||
| } | } | ||||||
|  |  | ||||||
| void CTClampSensor::update() { | void CTClampSensor::update() { | ||||||
|   if (this->is_calibrating_offset_) |  | ||||||
|     return; |  | ||||||
|  |  | ||||||
|   // Update only starts the sampling phase, in loop() the actual sampling is happening. |   // Update only starts the sampling phase, in loop() the actual sampling is happening. | ||||||
|  |  | ||||||
|   // Request a high loop() execution interval during sampling phase. |   // Request a high loop() execution interval during sampling phase. | ||||||
| @@ -46,20 +31,23 @@ void CTClampSensor::update() { | |||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     float raw = this->sample_sum_ / this->num_samples_; |     float dc = this->sample_sum_ / this->num_samples_; | ||||||
|     float irms = std::sqrt(raw); |     float var = (this->sample_squared_sum_ / this->num_samples_) - dc * dc; | ||||||
|     ESP_LOGD(TAG, "'%s' - Raw Value: %.2fA", this->name_.c_str(), irms); |     float ac = std::sqrt(var); | ||||||
|     this->publish_state(irms); |     ESP_LOGD(TAG, "'%s' - Got %d samples", this->name_.c_str(), this->num_samples_); | ||||||
|  |     ESP_LOGD(TAG, "'%s' - Raw AC Value: %.3fA", this->name_.c_str(), ac); | ||||||
|  |     this->publish_state(ac); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   // Set sampling values |   // Set sampling values | ||||||
|   this->is_sampling_ = true; |   this->is_sampling_ = true; | ||||||
|   this->num_samples_ = 0; |   this->num_samples_ = 0; | ||||||
|   this->sample_sum_ = 0.0f; |   this->sample_sum_ = 0.0f; | ||||||
|  |   this->sample_squared_sum_ = 0.0f; | ||||||
| } | } | ||||||
|  |  | ||||||
| void CTClampSensor::loop() { | void CTClampSensor::loop() { | ||||||
|   if (!this->is_sampling_ && !this->is_calibrating_offset_) |   if (!this->is_sampling_) | ||||||
|     return; |     return; | ||||||
|  |  | ||||||
|   // Perform a single sample |   // Perform a single sample | ||||||
| @@ -67,22 +55,8 @@ void CTClampSensor::loop() { | |||||||
|   if (isnan(value)) |   if (isnan(value)) | ||||||
|     return; |     return; | ||||||
|  |  | ||||||
|   if (this->is_calibrating_offset_) { |  | ||||||
|   this->sample_sum_ += value; |   this->sample_sum_ += value; | ||||||
|     this->num_samples_++; |   this->sample_squared_sum_ += value * value; | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // Adjust DC offset via low pass filter (exponential moving average) |  | ||||||
|   const float alpha = 0.001f; |  | ||||||
|   this->offset_ = this->offset_ * (1 - alpha) + value * alpha; |  | ||||||
|  |  | ||||||
|   // Filtered value centered around the mid-point (0V) |  | ||||||
|   float filtered = value - this->offset_; |  | ||||||
|  |  | ||||||
|   // IRMS is sqrt(∑v_i²) |  | ||||||
|   float sq = filtered * filtered; |  | ||||||
|   this->sample_sum_ += sq; |  | ||||||
|   this->num_samples_++; |   this->num_samples_++; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -10,7 +10,6 @@ namespace ct_clamp { | |||||||
|  |  | ||||||
| class CTClampSensor : public sensor::Sensor, public PollingComponent { | class CTClampSensor : public sensor::Sensor, public PollingComponent { | ||||||
|  public: |  public: | ||||||
|   void setup() override; |  | ||||||
|   void update() override; |   void update() override; | ||||||
|   void loop() override; |   void loop() override; | ||||||
|   void dump_config() override; |   void dump_config() override; | ||||||
| @@ -35,17 +34,19 @@ class CTClampSensor : public sensor::Sensor, public PollingComponent { | |||||||
|    * |    * | ||||||
|    * Diagram: https://learn.openenergymonitor.org/electricity-monitoring/ct-sensors/interface-with-arduino |    * Diagram: https://learn.openenergymonitor.org/electricity-monitoring/ct-sensors/interface-with-arduino | ||||||
|    * |    * | ||||||
|    * This is automatically calculated with an exponential moving average/digital low pass filter. |    * The current clamp only measures AC, so any DC component is an unwanted artifact from the | ||||||
|    * |    * sampling circuit. The AC component is essentially the same as the calculating the Standard-Deviation, | ||||||
|    * 0.5 is a good initial approximation to start with for most ESP8266 setups. |    * which can be done by cumulating 3 values per sample: | ||||||
|  |    *   1) Number of samples | ||||||
|  |    *   2) Sum of samples | ||||||
|  |    *   3) Sum of sample squared | ||||||
|  |    * https://en.wikipedia.org/wiki/Root_mean_square | ||||||
|    */ |    */ | ||||||
|   float offset_ = 0.5f; |  | ||||||
|  |  | ||||||
|   float sample_sum_ = 0.0f; |   float sample_sum_ = 0.0f; | ||||||
|  |   float sample_squared_sum_ = 0.0f; | ||||||
|   uint32_t num_samples_ = 0; |   uint32_t num_samples_ = 0; | ||||||
|   bool is_sampling_ = false; |   bool is_sampling_ = false; | ||||||
|   /// Calibrate offset value once at boot |  | ||||||
|   bool is_calibrating_offset_ = false; |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| }  // namespace ct_clamp | }  // namespace ct_clamp | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user