From 5f21b925dad3a99819402bb294cef9182c956c45 Mon Sep 17 00:00:00 2001 From: synco Date: Mon, 20 Sep 2021 19:12:50 +1200 Subject: [PATCH] Calculating the AC only component of the samples (#1906) Co-authored-by: Synco Reynders Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../components/ct_clamp/ct_clamp_sensor.cpp | 46 ++++--------------- esphome/components/ct_clamp/ct_clamp_sensor.h | 15 +++--- 2 files changed, 18 insertions(+), 43 deletions(-) diff --git a/esphome/components/ct_clamp/ct_clamp_sensor.cpp b/esphome/components/ct_clamp/ct_clamp_sensor.cpp index c27134d6ac..130cdfefba 100644 --- a/esphome/components/ct_clamp/ct_clamp_sensor.cpp +++ b/esphome/components/ct_clamp/ct_clamp_sensor.cpp @@ -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_sum_ += value; + this->sample_squared_sum_ += value * value; this->num_samples_++; } diff --git a/esphome/components/ct_clamp/ct_clamp_sensor.h b/esphome/components/ct_clamp/ct_clamp_sensor.h index c709f6718b..2f201c11a0 100644 --- a/esphome/components/ct_clamp/ct_clamp_sensor.h +++ b/esphome/components/ct_clamp/ct_clamp_sensor.h @@ -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