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"; | ||||
|  | ||||
| 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() { | ||||
|   LOG_SENSOR("", "CT Clamp Sensor", this); | ||||
|   ESP_LOGCONFIG(TAG, "  Sample Duration: %.2fs", this->sample_duration_ / 1e3f); | ||||
| @@ -27,9 +15,6 @@ void CTClampSensor::dump_config() { | ||||
| } | ||||
|  | ||||
| void CTClampSensor::update() { | ||||
|   if (this->is_calibrating_offset_) | ||||
|     return; | ||||
|  | ||||
|   // Update only starts the sampling phase, in loop() the actual sampling is happening. | ||||
|  | ||||
|   // Request a high loop() execution interval during sampling phase. | ||||
| @@ -46,20 +31,23 @@ void CTClampSensor::update() { | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     float raw = this->sample_sum_ / this->num_samples_; | ||||
|     float irms = std::sqrt(raw); | ||||
|     ESP_LOGD(TAG, "'%s' - Raw Value: %.2fA", this->name_.c_str(), irms); | ||||
|     this->publish_state(irms); | ||||
|     float dc = this->sample_sum_ / this->num_samples_; | ||||
|     float var = (this->sample_squared_sum_ / this->num_samples_) - dc * dc; | ||||
|     float ac = std::sqrt(var); | ||||
|     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 | ||||
|   this->is_sampling_ = true; | ||||
|   this->num_samples_ = 0; | ||||
|   this->sample_sum_ = 0.0f; | ||||
|   this->sample_squared_sum_ = 0.0f; | ||||
| } | ||||
|  | ||||
| void CTClampSensor::loop() { | ||||
|   if (!this->is_sampling_ && !this->is_calibrating_offset_) | ||||
|   if (!this->is_sampling_) | ||||
|     return; | ||||
|  | ||||
|   // Perform a single sample | ||||
| @@ -67,22 +55,8 @@ void CTClampSensor::loop() { | ||||
|   if (isnan(value)) | ||||
|     return; | ||||
|  | ||||
|   if (this->is_calibrating_offset_) { | ||||
|   this->sample_sum_ += value; | ||||
|     this->num_samples_++; | ||||
|     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->sample_squared_sum_ += value * value; | ||||
|   this->num_samples_++; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -10,7 +10,6 @@ namespace ct_clamp { | ||||
|  | ||||
| class CTClampSensor : public sensor::Sensor, public PollingComponent { | ||||
|  public: | ||||
|   void setup() override; | ||||
|   void update() override; | ||||
|   void loop() 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 | ||||
|    * | ||||
|    * This is automatically calculated with an exponential moving average/digital low pass filter. | ||||
|    * | ||||
|    * 0.5 is a good initial approximation to start with for most ESP8266 setups. | ||||
|    * 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, | ||||
|    * 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_squared_sum_ = 0.0f; | ||||
|   uint32_t num_samples_ = 0; | ||||
|   bool is_sampling_ = false; | ||||
|   /// Calibrate offset value once at boot | ||||
|   bool is_calibrating_offset_ = false; | ||||
| }; | ||||
|  | ||||
| }  // namespace ct_clamp | ||||
|   | ||||
		Reference in New Issue
	
	Block a user