mirror of
https://github.com/thooge/esp32-nmea2000-obp60.git
synced 2026-09-11 19:55:14 +02:00
Improve handling of invalid values in OBPringbuffer; avoid some double coding
This commit is contained in:
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user