Improve handling of invalid values in OBPringbuffer; avoid some double coding

This commit is contained in:
Ulrich Meine
2026-06-21 02:15:16 +02:00
parent c17f8238a4
commit 63af2807fb
2 changed files with 42 additions and 100 deletions
+5 -5
View File
@@ -45,9 +45,9 @@ private:
size_t last; // Points to the last (newest) valid element size_t last; // Points to the last (newest) valid element
size_t count; // Number of valid elements currently in buffer size_t count; // Number of valid elements currently in buffer
bool is_Full; // Indicates that all buffer elements are used and ringing is in use bool is_Full; // Indicates that all buffer elements are used and ringing is in use
T MIN_VAL; // lowest possible value of buffer of type <T> T NUMLIMIT_LOW; // internally lowest possible value of buffer of type <T>
T MAX_VAL; // highest possible value of buffer of type <T> -> indicates invalid value in buffer T NUMLIMIT_HIGH; // internally highest possible value of buffer of type <T>
double dblMIN_VAL, dblMAX_VAL; // MIN_VAL, MAX_VAL in double format double BUFMIN_VAL, BUFMAX_VAL; // lowest/highest possible buffer value considering multiplier -> externally used
mutable SemaphoreHandle_t bufLocker; mutable SemaphoreHandle_t bufLocker;
// metadata for buffer // metadata for buffer
@@ -55,8 +55,8 @@ private:
String dataFmt; // Format of boat data in buffer String dataFmt; // Format of boat data in buffer
int updFreq; // Update frequency in milliseconds int updFreq; // Update frequency in milliseconds
double mltplr; // Multiplier which transforms original <double> value into buffer type format double mltplr; // Multiplier which transforms original <double> value into buffer type format
double smallest; // Value range of buffer: smallest value; needs to be => MIN_VAL double lowest; // low value range for boat data in this buffer; needs to be => BUFMIN_VAL
double largest; // Value range of buffer: biggest value; needs to be < MAX_VAL, since MAX_VAL indicates invalid entries double highest; // high value range for boat data in this buffer; needs to be < BUFMAX_VAL, since BUFMAX_VAL indicates invalid entries
void initCommon(); void initCommon();
+37 -95
View File
@@ -6,16 +6,16 @@
template <typename T> template <typename T>
void RingBuffer<T>::initCommon() void RingBuffer<T>::initCommon()
{ {
MIN_VAL = std::numeric_limits<T>::lowest(); NUMLIMIT_LOW = std::numeric_limits<T>::lowest();
MAX_VAL = std::numeric_limits<T>::max(); NUMLIMIT_HIGH = std::numeric_limits<T>::max();
dblMIN_VAL = static_cast<double>(MIN_VAL);
dblMAX_VAL = static_cast<double>(MAX_VAL);
dataName = ""; dataName = "";
dataFmt = ""; dataFmt = "";
updFreq = -1; updFreq = -1;
mltplr = 1; mltplr = 1;
smallest = dblMIN_VAL; BUFMIN_VAL = static_cast<double>(NUMLIMIT_LOW);
largest = dblMAX_VAL; BUFMAX_VAL = static_cast<double>(NUMLIMIT_HIGH);
lowest = BUFMIN_VAL;
highest = BUFMAX_VAL;
bufLocker = xSemaphoreCreateMutex(); bufLocker = xSemaphoreCreateMutex();
} }
@@ -44,7 +44,7 @@ RingBuffer<T>::RingBuffer(size_t size)
initCommon(); initCommon();
buffer.reserve(size); buffer.reserve(size);
buffer.resize(size, MAX_VAL); // MAX_VAL indicate invalid values buffer.resize(size, NUMLIMIT_HIGH); // NUMLIMIT_HIGH indicate invalid values
} }
// Specify meta data of buffer content // Specify meta data of buffer content
@@ -56,8 +56,10 @@ void RingBuffer<T>::setMetaData(String name, String format, int updateFrequency,
dataFmt = format; dataFmt = format;
updFreq = updateFrequency; updFreq = updateFrequency;
mltplr = multiplier; mltplr = multiplier;
smallest = std::max(dblMIN_VAL, minValue); BUFMIN_VAL = static_cast<double>(NUMLIMIT_LOW) / mltplr; // lowest possible buffer value; converted to external view
largest = std::min(dblMAX_VAL, maxValue); BUFMAX_VAL = static_cast<double>(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<double>::infinity()), maxValue); // high value range, set by user; max. is 1 tick smaller than BUFMAX_VAL
} }
// Specify format of buffer content // Specify format of buffer content
@@ -81,8 +83,8 @@ bool RingBuffer<T>::getMetaData(String& name, String& format, int& updateFrequen
format = dataFmt; format = dataFmt;
updateFrequency = updFreq; updateFrequency = updFreq;
multiplier = mltplr; multiplier = mltplr;
minValue = smallest; minValue = lowest;
maxValue = largest; maxValue = highest;
return true; return true;
} }
@@ -126,8 +128,8 @@ template <typename T>
void RingBuffer<T>::add(const double& value) void RingBuffer<T>::add(const double& value)
{ {
GWSYNCHRONIZED(&bufLocker); GWSYNCHRONIZED(&bufLocker);
if (value < smallest || value > largest) { if (value < lowest || value > highest) {
buffer[head] = MAX_VAL; // Store MAX_VAL if value is out of range buffer[head] = NUMLIMIT_HIGH; // Store maximum buffer value if data value is out of range
} else { } else {
buffer[head] = static_cast<T>(std::round(value * mltplr)); buffer[head] = static_cast<T>(std::round(value * mltplr));
} }
@@ -151,11 +153,11 @@ double RingBuffer<T>::get(size_t index) const
{ {
GWSYNCHRONIZED(&bufLocker); GWSYNCHRONIZED(&bufLocker);
if (isEmpty() || index < 0 || index >= count) { if (isEmpty() || index < 0 || index >= count) {
return dblMAX_VAL; return BUFMAX_VAL;
} }
size_t realIndex = (first + index) % capacity; size_t realIndex = (first + index) % capacity;
return static_cast<double>(buffer[realIndex] / mltplr); return static_cast<double>(buffer[realIndex] / mltplr); // is BUFMAX_VAL if value is invalid
} }
// Operator[] for convenient access (same as get()) // Operator[] for convenient access (same as get())
@@ -170,7 +172,7 @@ template <typename T>
double RingBuffer<T>::getFirst() const double RingBuffer<T>::getFirst() const
{ {
if (isEmpty()) { if (isEmpty()) {
return dblMAX_VAL; return BUFMAX_VAL;
} }
return get(0); return get(0);
} }
@@ -180,7 +182,7 @@ template <typename T>
double RingBuffer<T>::getLast() const double RingBuffer<T>::getLast() const
{ {
if (isEmpty()) { if (isEmpty()) {
return dblMAX_VAL; return BUFMAX_VAL;
} }
return get(count - 1); return get(count - 1);
} }
@@ -189,19 +191,7 @@ double RingBuffer<T>::getLast() const
template <typename T> template <typename T>
double RingBuffer<T>::getMin() const double RingBuffer<T>::getMin() const
{ {
if (isEmpty()) { return getMin(getCurrentSize());
return dblMAX_VAL;
}
double minVal = dblMAX_VAL;
double value;
for (size_t i = 0; i < count; i++) {
value = get(i);
if (value < minVal && value != dblMAX_VAL) {
minVal = value;
}
}
return minVal;
} }
// Get minimum value of the last <amount> values of buffer // Get minimum value of the last <amount> values of buffer
@@ -209,16 +199,16 @@ template <typename T>
double RingBuffer<T>::getMin(size_t amount) const double RingBuffer<T>::getMin(size_t amount) const
{ {
if (isEmpty() || amount <= 0) { if (isEmpty() || amount <= 0) {
return dblMAX_VAL; return BUFMAX_VAL;
} }
if (amount > count) if (amount > count)
amount = count; amount = count;
double minVal = dblMAX_VAL; double minVal = BUFMAX_VAL;
double value; double value;
for (size_t i = 0; i < amount; i++) { for (size_t i = 0; i < amount; i++) {
value = get(count - 1 - i); value = get(count - 1 - i);
if (value < minVal && value != dblMAX_VAL) { if (value < minVal && value != BUFMAX_VAL) {
minVal = value; minVal = value;
} }
} }
@@ -229,22 +219,7 @@ double RingBuffer<T>::getMin(size_t amount) const
template <typename T> template <typename T>
double RingBuffer<T>::getMax() const double RingBuffer<T>::getMax() const
{ {
if (isEmpty()) { return getMax(getCurrentSize());
return dblMAX_VAL;
}
double maxVal = dblMIN_VAL;
double value;
for (size_t i = 0; i < count; i++) {
value = get(i);
if (value > maxVal && value != dblMAX_VAL) {
maxVal = value;
}
}
if (maxVal == dblMIN_VAL) { // no change of initial value -> buffer has only invalid values (MAX_VAL)
maxVal = dblMAX_VAL;
}
return maxVal;
} }
// Get maximum value of the last <amount> values of buffer // Get maximum value of the last <amount> values of buffer
@@ -252,21 +227,21 @@ template <typename T>
double RingBuffer<T>::getMax(size_t amount) const double RingBuffer<T>::getMax(size_t amount) const
{ {
if (isEmpty() || amount <= 0) { if (isEmpty() || amount <= 0) {
return dblMAX_VAL; return BUFMAX_VAL;
} }
if (amount > count) if (amount > count)
amount = count; amount = count;
double maxVal = dblMIN_VAL; double maxVal = BUFMIN_VAL;
double value; double value;
for (size_t i = 0; i < amount; i++) { for (size_t i = 0; i < amount; i++) {
value = get(count - 1 - i); value = get(count - 1 - i);
if (value > maxVal && value != dblMAX_VAL) { if (value > maxVal && value != BUFMAX_VAL) {
maxVal = value; maxVal = value;
} }
} }
if (maxVal == dblMIN_VAL) { // no change of initial value -> buffer has only invalid values (MAX_VAL) if (maxVal == BUFMIN_VAL) { // no change of initial value -> buffer has only invalid values (BUFMAX_VAL)
maxVal = dblMAX_VAL; maxVal = BUFMAX_VAL;
} }
return maxVal; return maxVal;
} }
@@ -275,11 +250,7 @@ double RingBuffer<T>::getMax(size_t amount) const
template <typename T> template <typename T>
double RingBuffer<T>::getMid() const double RingBuffer<T>::getMid() const
{ {
if (isEmpty()) { return getMid(getCurrentSize());
return dblMAX_VAL;
}
return (getMin() + getMax()) / 2;
} }
// Get mid value between <min> and <max> value of the last <amount> values of buffer // Get mid value between <min> and <max> value of the last <amount> values of buffer
@@ -287,7 +258,7 @@ template <typename T>
double RingBuffer<T>::getMid(size_t amount) const double RingBuffer<T>::getMid(size_t amount) const
{ {
if (isEmpty() || amount <= 0) { if (isEmpty() || amount <= 0) {
return dblMAX_VAL; return BUFMAX_VAL;
} }
if (amount > count) if (amount > count)
@@ -300,29 +271,7 @@ double RingBuffer<T>::getMid(size_t amount) const
template <typename T> template <typename T>
double RingBuffer<T>::getMedian() const double RingBuffer<T>::getMedian() const
{ {
if (isEmpty()) { return getMedian(getCurrentSize());
return dblMAX_VAL;
}
// Create a temporary vector with current valid elements
std::vector<T> temp;
temp.reserve(count);
for (size_t i = 0; i < count; i++) {
temp.push_back(get(i));
}
// Sort to find median
std::sort(temp.begin(), temp.end());
if (count % 2 == 1) {
// Odd number of elements
return static_cast<double>(temp[count / 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<double>((temp[count / 2 - 1] + temp[count / 2]) / 2);
}
} }
// Get the median value of the last <amount> values of buffer // Get the median value of the last <amount> values of buffer
@@ -330,7 +279,7 @@ template <typename T>
double RingBuffer<T>::getMedian(size_t amount) const double RingBuffer<T>::getMedian(size_t amount) const
{ {
if (isEmpty() || amount <= 0) { if (isEmpty() || amount <= 0) {
return dblMAX_VAL; return BUFMAX_VAL;
} }
if (amount > count) if (amount > count)
amount = count; amount = count;
@@ -402,14 +351,14 @@ bool RingBuffer<T>::isFull() const
template <typename T> template <typename T>
double RingBuffer<T>::getMinVal() const double RingBuffer<T>::getMinVal() const
{ {
return dblMIN_VAL; return BUFMIN_VAL;
} }
// Get highest possible value for buffer; used for unset/invalid buffer data // Get highest possible value for buffer; used for unset/invalid buffer data
template <typename T> template <typename T>
double RingBuffer<T>::getMaxVal() const double RingBuffer<T>::getMaxVal() const
{ {
return dblMAX_VAL; return BUFMAX_VAL;
} }
// Clear buffer // Clear buffer
@@ -438,21 +387,14 @@ void RingBuffer<T>::resize(size_t newSize)
buffer.clear(); buffer.clear();
buffer.reserve(newSize); buffer.reserve(newSize);
buffer.resize(newSize, MAX_VAL); buffer.resize(newSize, NUMLIMIT_HIGH);
} }
// Get all current values in native buffer format as a vector // Get all current values in native buffer format as a vector
template <typename T> template <typename T>
std::vector<double> RingBuffer<T>::getAllValues() const std::vector<double> RingBuffer<T>::getAllValues() const
{ {
std::vector<double> result; return getAllValues(getCurrentSize());
result.reserve(count);
for (size_t i = 0; i < count; i++) {
result.push_back(get(i));
}
return result;
} }
// Get last <amount> values in native buffer format as a vector // Get last <amount> values in native buffer format as a vector