mirror of
https://github.com/esphome/esphome.git
synced 2025-10-20 18:53:47 +01:00
cleanup sorting
This commit is contained in:
@@ -65,32 +65,41 @@ optional<float> SlidingWindowFilter::new_value(float value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SortedWindowFilter
|
// SortedWindowFilter
|
||||||
FixedVector<float> SortedWindowFilter::get_sorted_values_() {
|
FixedVector<float> SortedWindowFilter::get_window_values_() {
|
||||||
// Copy window without NaN values using FixedVector (no heap allocation)
|
// Copy window without NaN values using FixedVector (no heap allocation)
|
||||||
FixedVector<float> sorted_values;
|
// Returns unsorted values - caller will use std::nth_element for partial sorting as needed
|
||||||
sorted_values.init(this->window_count_);
|
FixedVector<float> values;
|
||||||
|
values.init(this->window_count_);
|
||||||
for (size_t i = 0; i < this->window_count_; i++) {
|
for (size_t i = 0; i < this->window_count_; i++) {
|
||||||
float v = this->window_[i];
|
float v = this->window_[i];
|
||||||
if (!std::isnan(v)) {
|
if (!std::isnan(v)) {
|
||||||
sorted_values.push_back(v);
|
values.push_back(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::sort(sorted_values.begin(), sorted_values.end());
|
return values;
|
||||||
return sorted_values;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MedianFilter
|
// MedianFilter
|
||||||
float MedianFilter::compute_result() {
|
float MedianFilter::compute_result() {
|
||||||
FixedVector<float> sorted_values = this->get_sorted_values_();
|
FixedVector<float> values = this->get_window_values_();
|
||||||
if (sorted_values.empty())
|
if (values.empty())
|
||||||
return NAN;
|
return NAN;
|
||||||
|
|
||||||
size_t size = sorted_values.size();
|
size_t size = values.size();
|
||||||
|
size_t mid = size / 2;
|
||||||
|
|
||||||
if (size % 2) {
|
if (size % 2) {
|
||||||
return sorted_values[size / 2];
|
// Odd number of elements - use nth_element to find middle element
|
||||||
} else {
|
std::nth_element(values.begin(), values.begin() + mid, values.end());
|
||||||
return (sorted_values[size / 2] + sorted_values[(size / 2) - 1]) / 2.0f;
|
return values[mid];
|
||||||
}
|
}
|
||||||
|
// Even number of elements - need both middle elements
|
||||||
|
// Use nth_element to find upper middle element
|
||||||
|
std::nth_element(values.begin(), values.begin() + mid, values.end());
|
||||||
|
float upper = values[mid];
|
||||||
|
// Find the maximum of the lower half (which is now everything before mid)
|
||||||
|
float lower = *std::max_element(values.begin(), values.begin() + mid);
|
||||||
|
return (lower + upper) / 2.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SkipInitialFilter
|
// SkipInitialFilter
|
||||||
@@ -111,13 +120,16 @@ QuantileFilter::QuantileFilter(size_t window_size, size_t send_every, size_t sen
|
|||||||
: SortedWindowFilter(window_size, send_every, send_first_at), quantile_(quantile) {}
|
: SortedWindowFilter(window_size, send_every, send_first_at), quantile_(quantile) {}
|
||||||
|
|
||||||
float QuantileFilter::compute_result() {
|
float QuantileFilter::compute_result() {
|
||||||
FixedVector<float> sorted_values = this->get_sorted_values_();
|
FixedVector<float> values = this->get_window_values_();
|
||||||
if (sorted_values.empty())
|
if (values.empty())
|
||||||
return NAN;
|
return NAN;
|
||||||
|
|
||||||
size_t position = ceilf(sorted_values.size() * this->quantile_) - 1;
|
size_t position = ceilf(values.size() * this->quantile_) - 1;
|
||||||
ESP_LOGVV(TAG, "QuantileFilter(%p)::position: %zu/%zu", this, position + 1, sorted_values.size());
|
ESP_LOGVV(TAG, "QuantileFilter(%p)::position: %zu/%zu", this, position + 1, values.size());
|
||||||
return sorted_values[position];
|
|
||||||
|
// Use nth_element to find the quantile element (O(n) instead of O(n log n))
|
||||||
|
std::nth_element(values.begin(), values.begin() + position, values.end());
|
||||||
|
return values[position];
|
||||||
}
|
}
|
||||||
|
|
||||||
// MinFilter
|
// MinFilter
|
||||||
|
@@ -95,17 +95,17 @@ class MinMaxFilter : public SlidingWindowFilter {
|
|||||||
|
|
||||||
/** Base class for filters that need a sorted window (Median, Quantile).
|
/** Base class for filters that need a sorted window (Median, Quantile).
|
||||||
*
|
*
|
||||||
* Extends SlidingWindowFilter to provide a helper that creates a sorted copy
|
* Extends SlidingWindowFilter to provide a helper that filters out NaN values.
|
||||||
* of non-NaN values from the window.
|
* Derived classes use std::nth_element for efficient partial sorting.
|
||||||
*/
|
*/
|
||||||
class SortedWindowFilter : public SlidingWindowFilter {
|
class SortedWindowFilter : public SlidingWindowFilter {
|
||||||
public:
|
public:
|
||||||
using SlidingWindowFilter::SlidingWindowFilter;
|
using SlidingWindowFilter::SlidingWindowFilter;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Helper to get sorted non-NaN values from the window
|
/// Helper to get non-NaN values from the window (not sorted - caller will use nth_element)
|
||||||
/// Returns empty FixedVector if all values are NaN
|
/// Returns empty FixedVector if all values are NaN
|
||||||
FixedVector<float> get_sorted_values_();
|
FixedVector<float> get_window_values_();
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Simple quantile filter.
|
/** Simple quantile filter.
|
||||||
|
Reference in New Issue
Block a user