diff --git a/lib/obp60task/OBPRingBuffer.h b/lib/obp60task/OBPRingBuffer.h index 332dddc..d2bb015 100644 --- a/lib/obp60task/OBPRingBuffer.h +++ b/lib/obp60task/OBPRingBuffer.h @@ -80,6 +80,8 @@ public: double getMax(size_t amount) const; // Get maximum value of the last values of buffer double getMid() const; // Get mid value between and value in buffer double getMid(size_t amount) const; // Get mid value between and value of the last values of buffer + double getCircularMid() const; // Get mid value of circle (degree) values of buffer + double getCircularMid(size_t amount) const; // Get mid value of circle (degree) values of the last values of buffer double getMedian() const; // Get the median value in buffer double getMedian(size_t amount) const; // Get the median value of the last values of buffer size_t getCapacity() const; // Get the buffer capacity (maximum size) diff --git a/lib/obp60task/OBPRingBuffer.tpp b/lib/obp60task/OBPRingBuffer.tpp index 1b88498..03bda33 100644 --- a/lib/obp60task/OBPRingBuffer.tpp +++ b/lib/obp60task/OBPRingBuffer.tpp @@ -1,4 +1,3 @@ -#include "OBPRingBuffer.h" #include #include #include @@ -59,7 +58,7 @@ void RingBuffer::setMetaData(String name, String format, int updateFrequency, BUFMIN_VAL = static_cast(NUMLIMIT_LOW) / mltplr; // lowest possible buffer value; converted to external view BUFMAX_VAL = static_cast(NUMLIMIT_HIGH) / mltplr; // highest possible buffer value; converted to external view lowest = std::max(BUFMIN_VAL, minValue); // low value range, set by user - highest = std::min(std::nextafter(BUFMAX_VAL, -std::numeric_limits::infinity()), maxValue); // high value range, set by user; max. is 1 tick smaller than BUFMAX_VAL + highest = std::min(std::nextafter(BUFMAX_VAL, -std::numeric_limits::infinity()), maxValue); // high value range, set by user; maximum is 1 tick lower than BUFMAX_VAL } // Specify format of buffer content @@ -285,7 +284,7 @@ double RingBuffer::getMedian(size_t amount) const amount = count; // Create a temporary vector with current valid elements - std::vector temp; + std::vector temp; temp.reserve(amount); for (size_t i = 0; i < amount; i++) { @@ -295,16 +294,85 @@ double RingBuffer::getMedian(size_t amount) const // Sort to find median std::sort(temp.begin(), temp.end()); + if (temp[0] == BUFMAX_VAL) { // 1st element of sorted vector is already BUFMAX_VAL -> only invalid entries in buffer, so we return invalid value + return BUFMAX_VAL; + } + if (amount % 2 == 1) { // Odd number of elements - return static_cast(temp[amount / 2]); + return temp[amount / 2]; } else { // Even number of elements - return average of middle two - // Note: For integer types, this truncates. For floating point, it's exact. - return static_cast((temp[amount / 2 - 1] + temp[amount / 2]) / 2); + return (temp[amount / 2 - 1] + temp[amount / 2]) / 2; } } +// Get mid value of circle (degree) values of buffer +template +double RingBuffer::getCircularMid() const +{ + return getCircularMid(getCurrentSize()); +} + +// Get mid value of circle (degree) values of the last values of buffer +template +double RingBuffer::getCircularMid(size_t amount) const +{ + if (isEmpty() || amount <= 0) { + return BUFMAX_VAL; + } + if (amount > count) + amount = count; + + std::vector a; + // Create a temporary vector with current valid elements + std::vector temp; + temp.reserve(amount); + + for (size_t i = 0; i < amount; i++) { + temp.push_back(get(count - 1 - i)); + } + + // Sort to find largest gap + std::sort(temp.begin(), temp.end()); + + if (temp[0] == BUFMAX_VAL) { // 1st element of sorted vector is already BUFMAX_VAL -> only invalid entries in buffer, so we return invalid value + return BUFMAX_VAL; + } + + // Find the largest gap + double largestGap = BUFMIN_VAL; + std::size_t gapIndex = 0; + + for (std::size_t i = 0; i < temp.size(); ++i) + { + std::size_t next = (i + 1) % temp.size(); + + double gap; + if (next == 0) + gap = (temp[0] + M_TWOPI) - temp[i]; + else + gap = temp[next] - temp[i]; + + if (gap > largestGap) + { + largestGap = gap; + gapIndex = i; + } + } + + double start = temp[(gapIndex + 1) % temp.size()]; // Start of occupied arc = first angle after largest gap + double arcWidth = M_TWOPI - largestGap; // Width of occupied arc + arcWidth = start + arcWidth / 2.0; + arcWidth = fmod(arcWidth, M_TWOPI); + if (arcWidth < 0.0) { + arcWidth += M_TWOPI; + } + + return arcWidth; // Midpoint of occupied arc +// return WindUtils::to2PI(start + arcWidth / 2.0); // Midpoint of occupied arc +} + // Get the buffer capacity (maximum size) template size_t RingBuffer::getCapacity() const