From 3deb80b2c65300a4422cbb6c6db1137cc8d04d02 Mon Sep 17 00:00:00 2001 From: Ulrich Meine Date: Thu, 26 Mar 2026 22:08:00 +0100 Subject: [PATCH] Add smoothing option for any chart plot --- lib/obp60task/OBPcharts.cpp | 31 +++++++++++++++++++++++++++++-- lib/obp60task/OBPcharts.h | 5 +++-- lib/obp60task/PageWindPlot.cpp | 2 +- lib/obp60task/config_obp40.json | 11 +++++++++++ lib/obp60task/config_obp60.json | 11 +++++++++++ 5 files changed, 55 insertions(+), 5 deletions(-) diff --git a/lib/obp60task/OBPcharts.cpp b/lib/obp60task/OBPcharts.cpp index 071007a..d384db8 100644 --- a/lib/obp60task/OBPcharts.cpp +++ b/lib/obp60task/OBPcharts.cpp @@ -42,6 +42,11 @@ Chart::Chart(RingBuffer& dataBuf, double dfltRng, CommonData& common, dbMAX_VAL = dataBuf.getMaxVal(); bufSize = dataBuf.getCapacity(); + smoothCharts = common.config->getBool(common.config->smoothCharts); + if (smoothCharts) { + chrtAvg.begin(); + } + // Initialize chart data format; shorter version of standard format indicator if (dbFormat == "formatCourse" || dbFormat == "formatWind" || dbFormat == "formatRot") { chrtDataFmt = WIND; // Chart is showing data of course / wind format @@ -337,6 +342,23 @@ void Chart::drawChartLines(const char direction, const int8_t chrtIntv, const do double chrtVal; // Current data value Pos point, prevPoint; // current and previous chart point + if (smoothCharts) { + // prime moving average filter to ensure the first plotted point is already averaged + + chrtAvg.reset(); + + // Feed the filter the 10 values preceding bufStart + for (int p = 10; p > 0; p--) { + // Calculate index with wrapping: (start - offset + size) % size + int primeIdx = (bufStart - (p * chrtIntv)); + double primeVal = dataBuf.get(primeIdx); + + if (primeVal != dbMAX_VAL) { + chrtAvg.reading(primeVal); + } + } + } + for (int i = 0; i < (numBufVals / chrtIntv); i++) { chrtVal = dataBuf.get(bufStart + (i * chrtIntv)); // show the latest wind values in buffer; keep 1st value constant in a rolling buffer @@ -345,6 +367,11 @@ void Chart::drawChartLines(const char direction, const int8_t chrtIntv, const do chrtPrevVal = dbMAX_VAL; } else { + if (smoothCharts) { + // if chart lines shall be smoothed, apply moving average filter of the last 10 values + chrtVal = chrtAvg.reading(chrtVal); + } + point = setCurrentChartPoint(i, direction, chrtVal, chrtScale); // if (i >= (numBufVals / chrtIntv) - 5) // log chart data of 1 line (adjust for test purposes) @@ -399,7 +426,7 @@ void Chart::drawChartLines(const char direction, const int8_t chrtIntv, const do if (chrtDataFmt == WIND) { // degree of course or wind recalcRngMid = true; - LOG_DEBUG(GwLog::DEBUG, "PageWindPlot: chart end: timAxis: %d, i: %d, bufStart: %d, numBufVals: %d, recalcRngCntr: %d", timAxis, i, bufStart, numBufVals, recalcRngMid); + // LOG_DEBUG(GwLog::DEBUG, "PageWindPlot: chart end: timAxis: %d, i: %d, bufStart: %d, numBufVals: %d, recalcRngCntr: %d", timAxis, i, bufStart, numBufVals, recalcRngMid); } break; } @@ -454,7 +481,7 @@ void Chart::drawChrtTimeAxis(const char chrtDir, const int8_t chrtSz, const int8 if (chrtDir == HORIZONTAL) { getdisplay().fillRect(0, cRoot.y, dWidth, 2, fgColor); - LOG_DEBUG(GwLog::DEBUG, "Chart::drawChrtTimeAxis: intv: %d, axSlots: %d, timAxis: %d, chrtIntv: %d", intv, axSlots, timAxis, chrtIntv); + // LOG_DEBUG(GwLog::DEBUG, "Chart::drawChrtTimeAxis: intv: %d, axSlots: %d, timAxis: %d, chrtIntv: %d", intv, axSlots, timAxis, chrtIntv); for (int j = intv; j < timAxis - 1; j += intv) { // fill time axis with values but keep area free on right hand side for value label // draw text with appropriate offset diff --git a/lib/obp60task/OBPcharts.h b/lib/obp60task/OBPcharts.h index fbdcddd..8978fd3 100644 --- a/lib/obp60task/OBPcharts.h +++ b/lib/obp60task/OBPcharts.h @@ -2,6 +2,7 @@ #pragma once #include "Pagedata.h" #include "OBP60Extensions.h" +#include "movingAvg.h" struct Pos { int x; @@ -44,12 +45,11 @@ protected: static constexpr bool NO_SIMUDATA = true; // switch off simulation feature of function RingBuffer& dataBuf; // Buffer to display - //char chrtDir; // Chart timeline direction: 'H' = horizontal, 'V' = vertical - //int8_t chrtSz; // Chart size: [0] = full size, [1] = half size left/top, [2] half size right/bottom double dfltRng; // Default range of chart, e.g. 30 = [0..30] uint16_t fgColor; // color code for any screen writing uint16_t bgColor; // color code for screen background bool useSimuData; // flag to indicate if simulation data is active + bool smoothCharts; // flag to indicate if charts shall be printed with smoothed gradient String tempFormat; // user defined format for temperature double zeroValue; // "0" SI value for temperature @@ -84,6 +84,7 @@ protected: bool bufDataValid = false; // Flag to indicate if buffer data is valid int oldChrtIntv = 0; // remember recent user selection of data interval + movingAvg chrtAvg{7}; // Store average of the last 7 chart values if chart gradient shall be smoothed double chrtPrevVal; // Last data value in chart area int x, y; // x and y coordinates for drawing int prevX, prevY; // Last x and y coordinates for drawing diff --git a/lib/obp60task/PageWindPlot.cpp b/lib/obp60task/PageWindPlot.cpp index 48b8d78..8f6554c 100644 --- a/lib/obp60task/PageWindPlot.cpp +++ b/lib/obp60task/PageWindPlot.cpp @@ -37,7 +37,7 @@ private: bool oldShowTruW = false; // remember recent user selection of wind data type int8_t dataIntv = 1; // Update interval for wind history chart: - // (1)|(2)|(3)|(4)|(8) x 240 seconds for 4, 8, 12, 16, 32 min. history chart + // (1)|(2)|(3)|(4)|(8) seconds for up to 32 min. history chart bool useSimuData; // bool holdValues; String flashLED; diff --git a/lib/obp60task/config_obp40.json b/lib/obp60task/config_obp40.json index 7d2662d..0926692 100644 --- a/lib/obp60task/config_obp40.json +++ b/lib/obp60task/config_obp40.json @@ -230,6 +230,17 @@ "obp40": "true" } }, + { + "name": "smoothCharts", + "label": "Smooth chart lines", + "type": "boolean", + "default": "false", + "description": "Print chart lines with a smoothed gradient", + "category": "OBP40 Settings", + "capabilities": { + "obp40": "true" + } + }, { "name": "lengthFormat", "label": "Length Format", diff --git a/lib/obp60task/config_obp60.json b/lib/obp60task/config_obp60.json index 305688f..a51f1f5 100644 --- a/lib/obp60task/config_obp60.json +++ b/lib/obp60task/config_obp60.json @@ -230,6 +230,17 @@ "obp60": "true" } }, + { + "name": "smoothCharts", + "label": "Smooth chart lines", + "type": "boolean", + "default": "false", + "description": "Print chart lines with a smoothed gradient", + "category": "OBP60 Settings", + "capabilities": { + "obp40": "true" + } + }, { "name": "lengthFormat", "label": "Length Format",