diff --git a/lib/obp60task/BoatDataCalibration.cpp b/lib/obp60task/BoatDataCalibration.cpp deleted file mode 100644 index 9543926..0000000 --- a/lib/obp60task/BoatDataCalibration.cpp +++ /dev/null @@ -1,190 +0,0 @@ -#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3 - -#include "BoatDataCalibration.h" -#include -#include -#include - -CalibrationDataList calibrationData; -std::unordered_map CalibrationDataList::calibMap; // list of calibration data instances - -void CalibrationDataList::readConfig(GwConfigHandler* config, GwLog* logger) -// Initial load of calibration data into internal list -// This method is called once at init phase of to read the configuration values -{ - std::string instance; - double offset; - double slope; - double smooth; - - String calInstance = ""; - String calOffset = ""; - String calSlope = ""; - String calSmooth = ""; - - // Load user format configuration values - String lengthFormat = config->getString(config->lengthFormat); // [m|ft] - String distanceFormat = config->getString(config->distanceFormat); // [m|km|nm] - String speedFormat = config->getString(config->speedFormat); // [m/s|km/h|kn] - String windspeedFormat = config->getString(config->windspeedFormat); // [m/s|km/h|kn|bft] - String tempFormat = config->getString(config->tempFormat); // [K|C|F] - - // Read calibration settings for data instances - for (int i = 0; i < MAX_CALIBRATION_DATA; i++) { - calInstance = "calInstance" + String(i + 1); - calOffset = "calOffset" + String(i + 1); - calSlope = "calSlope" + String(i + 1); - calSmooth = "calSmooth" + String(i + 1); - - instance = std::string(config->getString(calInstance, "---").c_str()); - if (instance == "---") { - LOG_DEBUG(GwLog::LOG, "no calibration data for instance no. %d", i + 1); - continue; - } - calibMap[instance] = { 0.0f, 1.0f, 1.0f, 0.0f, false }; - offset = (config->getString(calOffset, "")).toFloat(); - slope = (config->getString(calSlope, "")).toFloat(); - smooth = (config->getString(calSmooth, "")).toInt(); // user input is int; further math is done with double - - // Convert calibration values to internal standard formats - if (instance == "AWS" || instance == "TWS") { - if (windspeedFormat == "m/s") { - // No conversion needed - } else if (windspeedFormat == "km/h") { - offset /= 3.6; // Convert km/h to m/s - } else if (windspeedFormat == "kn") { - offset /= 1.94384; // Convert kn to m/s - } else if (windspeedFormat == "bft") { - offset *= 2 + (offset / 2); // Convert Bft to m/s (approx) -> to be improved - } - - } else if (instance == "AWA" || instance == "COG" || instance == "TWA" || instance == "TWD" || instance == "HDM" || instance == "PRPOS" || instance == "RPOS") { - offset *= M_PI / 180; // Convert deg to rad - - } else if (instance == "DBT") { - if (lengthFormat == "m") { - // No conversion needed - } else if (lengthFormat == "ft") { - offset /= 3.28084; // Convert ft to m - } - - } else if (instance == "SOG" || instance == "STW") { - if (speedFormat == "m/s") { - // No conversion needed - } else if (speedFormat == "km/h") { - offset /= 3.6; // Convert km/h to m/s - } else if (speedFormat == "kn") { - offset /= 1.94384; // Convert kn to m/s - } - - } else if (instance == "WTemp") { - if (tempFormat == "K" || tempFormat == "C") { - // No conversion needed - } else if (tempFormat == "F") { - offset *= 9.0 / 5.0; // Convert °F to K - slope *= 9.0 / 5.0; // Convert °F to K - } - } - - // transform smoothing factor from {0.01..10} to {0.3..0.95} and invert for exponential smoothing formula - if (smooth <= 0) { - smooth = 0; - } else { - if (smooth > 10) { - smooth = 10; - } - smooth = 0.3 + ((smooth - 0.01) * (0.95 - 0.3) / (10 - 0.01)); - } - smooth = 1 - smooth; - - calibMap[instance].offset = offset; - calibMap[instance].slope = slope; - calibMap[instance].smooth = smooth; - calibMap[instance].isCalibrated = false; - LOG_DEBUG(GwLog::LOG, "calibration data: %s, offset: %f, slope: %f, smoothing: %f", instance.c_str(), - calibMap[instance].offset, calibMap[instance].slope, calibMap[instance].smooth); - } - LOG_DEBUG(GwLog::LOG, "all calibration data read"); -} - -void CalibrationDataList::calibrateInstance(GwApi::BoatValue* boatDataValue, GwLog* logger) -// Method to calibrate the boat data value -{ - std::string instance = boatDataValue->getName().c_str(); - double offset = 0; - double slope = 1.0; - double dataValue = 0; - std::string format = ""; - - if (calibMap.find(instance) == calibMap.end()) { - LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s not in calibration list", instance.c_str()); - return; - } else if (!boatDataValue->valid) { // no valid boat data value, so we don't want to apply calibration data - calibMap[instance].isCalibrated = false; - return; - } else { - offset = calibMap[instance].offset; - slope = calibMap[instance].slope; - dataValue = boatDataValue->value; - format = boatDataValue->getFormat().c_str(); - LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s: value: %f, format: %s", instance.c_str(), dataValue, format.c_str()); - - if (format == "formatWind") { // instance is of type angle - dataValue = (dataValue * slope) + offset; - dataValue = fmod(dataValue, 2 * M_PI); - if (dataValue > (M_PI)) { - dataValue -= (2 * M_PI); - } else if (dataValue < (M_PI * -1)) { - dataValue += (2 * M_PI); - } - } else if (format == "formatCourse") { // instance is of type direction - dataValue = (dataValue * slope) + offset; - dataValue = fmod(dataValue, 2 * M_PI); - if (dataValue < 0) { - dataValue += (2 * M_PI); - } - } else if (format == "kelvinToC") { // instance is of type temperature - dataValue = ((dataValue - 273.15) * slope) + offset + 273.15; - } else { - - dataValue = (dataValue * slope) + offset; - } - - calibMap[instance].isCalibrated = true; - boatDataValue->value = dataValue; - - calibrationData.smoothInstance(boatDataValue, logger); // smooth the boat data value - calibMap[instance].value = boatDataValue->value; // store the calibrated + smoothed value in the list - - LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s: Offset: %f, Slope: %f, Result: %f", instance.c_str(), offset, slope, calibMap[instance].value); - } -} - -void CalibrationDataList::smoothInstance(GwApi::BoatValue* boatDataValue, GwLog* logger) -// Method to smoothen the boat data value -{ - static std::unordered_map lastValue; // array for last values of smoothed boat data values - - std::string instance = boatDataValue->getName().c_str(); - double oldValue = 0; - double dataValue = boatDataValue->value; - double smoothFactor = 0; - - if (!boatDataValue->valid) { // no valid boat data value, so we don't want to smoothen value - return; - } else if (calibMap.find(instance) == calibMap.end()) { - LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: smooth factor for %s not found in calibration list", instance.c_str()); - return; - } else { - smoothFactor = calibMap[instance].smooth; - - if (lastValue.find(instance) != lastValue.end()) { - oldValue = lastValue[instance]; - dataValue = oldValue + (smoothFactor * (dataValue - oldValue)); // exponential smoothing algorithm - } - lastValue[instance] = dataValue; // store the new value for next cycle; first time, store only the current value and return - boatDataValue->value = dataValue; // set the smoothed value to the boat data value - } -} - -#endif \ No newline at end of file diff --git a/lib/obp60task/BoatDataCalibration.h b/lib/obp60task/BoatDataCalibration.h deleted file mode 100644 index d906fa9..0000000 --- a/lib/obp60task/BoatDataCalibration.h +++ /dev/null @@ -1,34 +0,0 @@ -// Functions lib for data instance calibration - -#ifndef _BOATDATACALIBRATION_H -#define _BOATDATACALIBRATION_H - -// #include "Pagedata.h" -#include "GwApi.h" -#include -#include - -#define MAX_CALIBRATION_DATA 3 // maximum number of calibration data instances - -typedef struct { - double offset; // calibration offset - double slope; // calibration slope - double smooth; // smoothing factor - double value; // calibrated data value - bool isCalibrated; // is data instance value calibrated? -} TypeCalibData; - -class CalibrationDataList { -public: - static std::unordered_map calibMap; // list of calibration data instances - - void readConfig(GwConfigHandler* config, GwLog* logger); - void calibrateInstance(GwApi::BoatValue* boatDataValue, GwLog* logger); - void smoothInstance(GwApi::BoatValue* boatDataValue, GwLog* logger); - -private: -}; - -extern CalibrationDataList calibrationData; // this list holds all calibration data - -#endif \ No newline at end of file diff --git a/lib/obp60task/OBP60Formatter.cpp b/lib/obp60task/OBP60Formatter.cpp index ebb2142..9b42102 100644 --- a/lib/obp60task/OBP60Formatter.cpp +++ b/lib/obp60task/OBP60Formatter.cpp @@ -92,6 +92,8 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool const char* fmt_dec_1; const char* fmt_dec_10; const char* fmt_dec_100; + double limit_dec_10; + double limit_dec_100; if (precision == "1") { // //All values are displayed using a DSEG7* font. In this font, ' ' is a very short space, and '.' takes up no space at all. @@ -100,10 +102,14 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool fmt_dec_1 = "!%1.1f"; //insert a blank digit and then display a two-digit number fmt_dec_10 = "!%2.0f"; //insert a blank digit and then display a two-digit number fmt_dec_100 = "%3.0f"; //dispay a three digit number + limit_dec_10=9.95; // use fmt_dec_1 below this number to avoid formatting 9.96 as 10.0 instead of 10 + limit_dec_100=99.5; } else { fmt_dec_1 = "%3.2f"; fmt_dec_10 = "%3.1f"; fmt_dec_100 = "%3.0f"; + limit_dec_10=9.995; + limit_dec_100=99.95; } // LOG_DEBUG(GwLog::DEBUG,"formatValue init: getFormat: %s date->value: %f time->value: %f", value->getFormat(), commondata.date->value, commondata.time->value); @@ -243,10 +249,10 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool speed = speed; // Unit conversion form m/s to m/s result.unit = "m/s"; } - if(speed < 10) { + if(speed < limit_dec_10) { snprintf(buffer, bsize, fmt_dec_1, speed); } - else if (speed < 100) { + else if (speed < limit_dec_100) { snprintf(buffer, bsize, fmt_dec_10, speed); } else { @@ -323,11 +329,10 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool snprintf(buffer, bsize, "%2.0f", speed); } else{ - speed = std::round(speed * 100) / 100; // in rare cases, speed could be 9.9999 kn instead of 10.0 kn - if (speed < 10.0){ + if (speed < limit_dec_10){ snprintf(buffer, bsize, fmt_dec_1, speed); } - else if (speed < 100.0){ + else if (speed < limit_dec_100){ snprintf(buffer, bsize, fmt_dec_10, speed); } else { @@ -378,10 +383,10 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool if (dop > 99.9){ dop = 99.9; } - if (dop < 10){ + if (dop < limit_dec_10){ snprintf(buffer, bsize, fmt_dec_1, dop); } - else if(dop < 100){ + else if(dop < limit_dec_100){ snprintf(buffer, bsize, fmt_dec_10, dop); } else { @@ -457,10 +462,10 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool else{ result.unit = "m"; } - if (depth < 10) { + if (depth < limit_dec_10) { snprintf(buffer, bsize, fmt_dec_1, depth); } - else if (depth < 100){ + else if (depth < limit_dec_100){ snprintf(buffer, bsize, fmt_dec_10, depth); } else { @@ -523,10 +528,10 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool else{ result.unit = "K"; } - if(temp < 10) { + if(temp < limit_dec_10) { snprintf(buffer, bsize, fmt_dec_1, temp); } - else if (temp < 100) { + else if (temp < limit_dec_100) { snprintf(buffer, bsize, fmt_dec_10, temp); } else { @@ -556,10 +561,10 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool else { result.unit = "m"; } - if (distance < 10){ + if (distance < limit_dec_10){ snprintf(buffer, bsize, fmt_dec_1, distance); } - else if (distance < 100){ + else if (distance < limit_dec_100){ snprintf(buffer, bsize, fmt_dec_10, distance); } else { @@ -613,7 +618,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool rawvalue = 12 + float(random(0, 30)) / 10.0; voltage = rawvalue; } - if (voltage < 10) { + if (voltage < limit_dec_10) { snprintf(buffer, bsize, fmt_dec_1, voltage); } else { @@ -633,10 +638,10 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool rawvalue = 8.2 + float(random(0, 50)) / 10.0; current = rawvalue; } - if (current < 10) { + if (current < limit_dec_10) { snprintf(buffer, bsize, fmt_dec_1, current); } - else if(current < 100) { + else if(current < limit_dec_100) { snprintf(buffer, bsize, fmt_dec_10, current); } else { @@ -656,10 +661,10 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool rawvalue = 21.8 + float(random(0, 50)) / 10.0; temperature = rawvalue; } - if (temperature < 10) { + if (temperature < limit_dec_10) { snprintf(buffer, bsize, fmt_dec_1, temperature); } - else if (temperature < 100) { + else if (temperature < limit_dec_100) { snprintf(buffer, bsize, fmt_dec_10, temperature); } else { @@ -679,10 +684,10 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool rawvalue = 21.8 + float(random(0, 50)) / 10.0; temperature = rawvalue; } - if (temperature < 10) { + if (temperature < limit_dec_10) { snprintf(buffer, bsize, fmt_dec_1, temperature); } - else if(temperature < 100) { + else if(temperature < limit_dec_100) { snprintf(buffer, bsize, fmt_dec_10, temperature); } else { @@ -702,10 +707,10 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool rawvalue = 41.3 + float(random(0, 50)) / 10.0; humidity = rawvalue; } - if (humidity < 10) { + if (humidity < limit_dec_10) { snprintf(buffer, bsize, fmt_dec_1, humidity); } - else if(humidity < 100) { + else if(humidity < limit_dec_100) { snprintf(buffer, bsize, fmt_dec_10, humidity); } else { @@ -725,13 +730,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool rawvalue = 85.8 + float(random(0, 50)) / 10.0; volume = rawvalue; } - if (volume < 10) { + if (volume < limit_dec_10) { snprintf(buffer, bsize, fmt_dec_1, volume); } - else if (volume < 100) { + else if (volume < limit_dec_100) { snprintf(buffer, bsize, fmt_dec_10, volume); } - else if (volume >= 100) { + else if (volume >= limit_dec_100) { snprintf(buffer, bsize, fmt_dec_100, volume); } result.unit = "%"; @@ -748,10 +753,10 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool rawvalue = 75.2 + float(random(0, 50)) / 10.0; volume = rawvalue; } - if (volume < 10) { + if (volume < limit_dec_10) { snprintf(buffer, bsize, fmt_dec_1, volume); } - else if (volume < 100) { + else if (volume < limit_dec_100) { snprintf(buffer, bsize, fmt_dec_10, volume); } else { @@ -771,10 +776,10 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool rawvalue = 7.5 + float(random(0, 20)) / 10.0; flow = rawvalue; } - if (flow < 10) { + if (flow < limit_dec_10) { snprintf(buffer, bsize, fmt_dec_1, flow); } - else if (flow < 100) { + else if (flow < limit_dec_100) { snprintf(buffer, bsize, fmt_dec_10, flow); } else { @@ -794,10 +799,10 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool rawvalue = 18.5 + float(random(0, 20)) / 10.0; generic = rawvalue; } - if (generic < 10) { + if (generic < limit_dec_10) { snprintf(buffer, bsize, fmt_dec_1, generic); } - else if (generic < 100) { + else if (generic < limit_dec_100) { snprintf(buffer, bsize, fmt_dec_10, generic); } else { @@ -817,10 +822,10 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool rawvalue = 55.3 + float(random(0, 20)) / 10.0; dplace = rawvalue; } - if (dplace < 10) { + if (dplace < limit_dec_10) { snprintf(buffer, bsize, fmt_dec_1, dplace); } - else if (dplace < 100) { + else if (dplace < limit_dec_100) { snprintf(buffer, bsize, fmt_dec_10, dplace); } else { @@ -861,10 +866,10 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool rawvalue = 2505 + random(0, 20); rpm = rawvalue; } - if (rpm < 10) { + if (rpm < limit_dec_10) { snprintf(buffer, bsize, fmt_dec_1, rpm); } - else if (rpm < 100) { + else if (rpm < limit_dec_100) { snprintf(buffer, bsize, fmt_dec_10, rpm); } else { @@ -877,10 +882,10 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool // Default format //######################################################## else { - if (value->value < 10) { + if (value->value < limit_dec_10) { snprintf(buffer, bsize, fmt_dec_1, value->value); } - else if (value->value < 100) { + else if (value->value < limit_dec_100) { snprintf(buffer, bsize, fmt_dec_10, value->value); } else { diff --git a/lib/obp60task/OBPDataOperations.cpp b/lib/obp60task/OBPDataOperations.cpp index aae0040..562b1f6 100644 --- a/lib/obp60task/OBPDataOperations.cpp +++ b/lib/obp60task/OBPDataOperations.cpp @@ -1,5 +1,221 @@ #include "OBPDataOperations.h" -#include "BoatDataCalibration.h" // Functions lib for data instance calibration +//#include "BoatDataCalibration.h" // Functions lib for data instance calibration + +// --- Class CalibrationData --------------- +CalibrationData::CalibrationData(GwLog* log) +{ + logger = log; +} + +void CalibrationData::readConfig(GwConfigHandler* config) +// Initial load of calibration data into internal list +// This method is called once at init phase of to read the configuration values +{ + std::string instance; + double offset; + double slope; + double smooth; + + String calInstance = ""; + String calOffset = ""; + String calSlope = ""; + String calSmooth = ""; + + // Load user format configuration values + String lengthFormat = config->getString(config->lengthFormat); // [m|ft] + String distanceFormat = config->getString(config->distanceFormat); // [m|km|nm] + String speedFormat = config->getString(config->speedFormat); // [m/s|km/h|kn] + String windspeedFormat = config->getString(config->windspeedFormat); // [m/s|km/h|kn|bft] + String tempFormat = config->getString(config->tempFormat); // [K|C|F] + + // Read calibration settings for data instances + for (int i = 0; i < MAX_CALIBRATION_DATA; i++) { + calInstance = "calInstance" + String(i + 1); + calOffset = "calOffset" + String(i + 1); + calSlope = "calSlope" + String(i + 1); + calSmooth = "calSmooth" + String(i + 1); + + instance = std::string(config->getString(calInstance, "---").c_str()); + if (instance == "---") { + LOG_DEBUG(GwLog::LOG, "No calibration data for instance no. %d", i + 1); + continue; + } + + calibrationMap[instance] = { 0.0f, 1.0f, 1.0f, 0.0f, false }; + offset = (config->getString(calOffset, "")).toDouble(); + slope = (config->getString(calSlope, "")).toDouble(); + smooth = (config->getString(calSmooth, "")).toInt(); // user input is int; further math is done with double + + if (slope == 0.0) { + slope = 1.0; // eliminate adjustment if user selected "0" -> that would set the calibrated value to "0" + } + + // Convert calibration values from user input format to internal standard SI format + if (instance == "AWS" || instance == "TWS") { + if (windspeedFormat == "m/s") { + // No conversion needed + } else if (windspeedFormat == "km/h") { + offset /= 3.6; // Convert km/h to m/s + } else if (windspeedFormat == "kn") { + offset /= 1.94384; // Convert kn to m/s + } else if (windspeedFormat == "bft") { + offset *= 2 + (offset / 2); // Convert Bft to m/s (approx) -> to be improved + } + + } else if (instance == "AWA" || instance == "COG" || instance == "HDM" || instance == "HDT" || instance == "PRPOS" || instance == "RPOS" || instance == "TWA" || instance == "TWD") { + offset *= DEG_TO_RAD; // Convert deg to rad + + } else if (instance == "DBS" || instance == "DBT") { + if (lengthFormat == "m") { + // No conversion needed + } else if (lengthFormat == "ft") { + offset /= 3.28084; // Convert ft to m + } + + } else if (instance == "SOG" || instance == "STW") { + if (speedFormat == "m/s") { + // No conversion needed + } else if (speedFormat == "km/h") { + offset /= 3.6; // Convert km/h to m/s + } else if (speedFormat == "kn") { + offset /= 1.94384; // Convert kn to m/s + } + + } else if (instance == "WTemp") { + if (tempFormat == "K" || tempFormat == "C") { + // No conversion needed + } else if (tempFormat == "F") { + offset *= 9.0 / 5.0; // Convert °F to K + slope *= 9.0 / 5.0; // Convert °F to K + } + } + + // transform smoothing factor from [0.01..10] to [0.3..0.95] and invert for exponential smoothing formula + if (smooth <= 0) { + smooth = 0; + } else { + if (smooth > 10) { + smooth = 10; + } + smooth = 0.3 + ((smooth - 0.01) * (0.95 - 0.3) / (10 - 0.01)); + } + smooth = 1 - smooth; + + calibrationMap[instance].offset = offset; + calibrationMap[instance].slope = slope; + calibrationMap[instance].smooth = smooth; + calibrationMap[instance].isCalibrated = false; + LOG_DEBUG(GwLog::LOG, "Calibration data type added: %s, offset: %f, slope: %f, smoothing: %f", instance.c_str(), + calibrationMap[instance].offset, calibrationMap[instance].slope, calibrationMap[instance].smooth); + } + // LOG_DEBUG(GwLog::LOG, "All calibration data read"); +} + +// Handle calibrationMap and calibrate all boat data values +void CalibrationData::handleCalibration(BoatValueList* boatValueList) +{ + GwApi::BoatValue* bValue; + + for (const auto& cMap : calibrationMap) { + std::string instance = cMap.first.c_str(); + bValue = boatValueList->findValueOrCreate(String(instance.c_str())); + + calibrateInstance(bValue); + smoothInstance(bValue); + } +} + +// Calibrate single boat data value +// Return calibrated boat value or DBL_MAX, if no calibration was performed +bool CalibrationData::calibrateInstance(GwApi::BoatValue* boatDataValue) +{ + std::string instance = boatDataValue->getName().c_str(); + double offset = 0; + double slope = 1.0; + double dataValue = 0; + std::string format = ""; + + // we test this earlier, but for safety reason ... + if (calibrationMap.find(instance) == calibrationMap.end()) { + LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s not in calibration list", instance.c_str()); + return false; + } + + calibrationMap[instance].isCalibrated = false; // reset calibration flag until properly calibrated + + if (!boatDataValue->valid) { // no valid boat data value, so we don't want to apply calibration data + return false; + } + + offset = calibrationMap[instance].offset; + slope = calibrationMap[instance].slope; + dataValue = boatDataValue->value; + format = boatDataValue->getFormat().c_str(); + LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s: value: %f, format: %s", instance.c_str(), dataValue, format.c_str()); + + if (format == "formatWind") { // instance is of type angle + dataValue = (dataValue * slope) + offset; + // dataValue = WindUtils::toPI(dataValue); + dataValue = WindUtils::to2PI(dataValue); // we should call for format of [-180..180], but pages cannot display negative values properly yet + + } else if (format == "formatCourse") { // instance is of type direction + dataValue = (dataValue * slope) + offset; + dataValue = WindUtils::to2PI(dataValue); + + } else if (format == "kelvinToC") { // instance is of type temperature + dataValue = ((dataValue - 273.15) * slope) + offset + 273.15; + + } else { + dataValue = (dataValue * slope) + offset; + } + + + boatDataValue->value = dataValue; // update boat data value with calibrated value + calibrationMap[instance].value = dataValue; // store the calibrated value in the list + calibrationMap[instance].isCalibrated = true; + + LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s: Offset: %f, Slope: %f, Result: %f", instance.c_str(), offset, slope, calibrationMap[instance].value); + return true; +} + +// Smooth single boat data value +// Return smoothed boat value or DBL_MAX, if no smoothing was performed +bool CalibrationData::smoothInstance(GwApi::BoatValue* boatDataValue) +{ + std::string instance = boatDataValue->getName().c_str(); + double oldValue = 0; + double dataValue = boatDataValue->value; + double smoothFactor = 0; + + // we test this earlier, but for safety reason ... + if (calibrationMap.find(instance) == calibrationMap.end()) { + LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s not in calibration list", instance.c_str()); + return false; + } + + calibrationMap[instance].isCalibrated = false; // reset calibration flag until properly calibrated + + if (!boatDataValue->valid) { // no valid boat data value, so we don't need to do anything + return false; + } + + smoothFactor = calibrationMap[instance].smooth; + + if (lastValue.find(instance) != lastValue.end()) { + oldValue = lastValue[instance]; + dataValue = oldValue + (smoothFactor * (dataValue - oldValue)); // exponential smoothing algorithm + } + lastValue[instance] = dataValue; // store the new value for next cycle; first time, store only the current value and return + + boatDataValue->value = dataValue; // update boat data value with smoothed value + calibrationMap[instance].value = dataValue; // store the smoothed value in the list + calibrationMap[instance].isCalibrated = true; + + LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s: smooth: %f, oldValue: %f, result: %f", instance.c_str(), smoothFactor, oldValue, calibrationMap[instance].value); + + return true; +} +// --- End Class CalibrationData --------------- // --- Class HstryBuf --------------- HstryBuf::HstryBuf(const String& name, int size, BoatValueList* boatValues, GwLog* log) @@ -43,12 +259,15 @@ void HstryBuf::handle(bool useSimuData, CommonData& common) if (boatValue->valid) { // Calibrate boat value before adding it to history buffer - calibrationData.calibrateInstance(tmpBVal.get(), logger); - add(tmpBVal->value); + //calibrationData.calibrateInstance(tmpBVal.get(), logger); + //add(tmpBVal->value); + add(boatValue->value); } else if (useSimuData) { // add simulated value to history buffer - double simValue = formatValue(tmpBVal.get(), common).value; // simulated value is generated at - add(simValue); + double simSIValue = formatValue(tmpBVal.get(), common).value; // simulated value is generated at ; here: retreive SI value + add(simSIValue); + } else { + // here we will add invalid (DBL_MAX) value; this will mark periods of missing data in buffer together with a timestamp } } // --- End Class HstryBuf --------------- @@ -299,7 +518,8 @@ bool WindUtils::addWinds() twsBVal->valid = true; } if (!twaBVal->valid) { - twaBVal->value = twa; + //twaBVal->value = twa; + twaBVal->value = to2PI(twa); // convert to [0..360], because pages cannot display negative values properly yet twaBVal->valid = true; } if (!awdBVal->valid) { diff --git a/lib/obp60task/OBPDataOperations.h b/lib/obp60task/OBPDataOperations.h index 0fb8647..9c5b783 100644 --- a/lib/obp60task/OBPDataOperations.h +++ b/lib/obp60task/OBPDataOperations.h @@ -1,9 +1,36 @@ -// Function lib for history buffer handling, true wind calculation, and other operations on boat data +// Function lib for boat data calibration, history buffer handling, true wind calculation, and other operations on boat data #pragma once #include "OBPRingBuffer.h" #include "Pagedata.h" #include "obp60task.h" #include +#include + +// Calibration of boat data values, when user setting available +// supported boat data types are: AWA, AWS, COG, DBS, DBT, HDM, HDT, PRPOS, RPOS, SOG, STW, TWA, TWS, TWD, WTemp +class CalibrationData { +private: + typedef struct { + double offset; // calibration offset + double slope; // calibration slope + double smooth; // smoothing factor + double value; // calibrated data value (for future use) + bool isCalibrated; // is data instance value calibrated? (for future use) + } tCalibrationData; + + std::unordered_map calibrationMap; // list of calibration data instances + std::unordered_map lastValue; // array for last smoothed values of boat data values + GwLog* logger; + + static constexpr int8_t MAX_CALIBRATION_DATA = 4; // maximum number of calibration data instances + +public: + CalibrationData(GwLog* log); + void readConfig(GwConfigHandler* config); + void handleCalibration(BoatValueList* boatValues); // Handle calibrationMap and calibrate all boat data values + bool calibrateInstance(GwApi::BoatValue* boatDataValue); // Calibrate single boat data value + bool smoothInstance(GwApi::BoatValue* boatDataValue); // Smooth single boat data value +}; class HstryBuf { private: diff --git a/lib/obp60task/PageFourValues.cpp b/lib/obp60task/PageFourValues.cpp index b7526c0..cb9de68 100644 --- a/lib/obp60task/PageFourValues.cpp +++ b/lib/obp60task/PageFourValues.cpp @@ -2,7 +2,6 @@ #include "Pagedata.h" #include "OBP60Extensions.h" -#include "BoatDataCalibration.h" class PageFourValues : public Page { @@ -46,7 +45,6 @@ class PageFourValues : public Page GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue) String name1 = xdrDelete(bvalue1->getName()); // Value name name1 = name1.substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated double value1 = bvalue1->value; // Value as double in SI unit bool valid1 = bvalue1->valid; // Valid information String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places @@ -56,7 +54,6 @@ class PageFourValues : public Page GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list String name2 = xdrDelete(bvalue2->getName()); // Value name name2 = name2.substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bvalue2, logger); // Check if boat data value is to be calibrated double value2 = bvalue2->value; // Value as double in SI unit bool valid2 = bvalue2->valid; // Valid information String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places @@ -66,7 +63,6 @@ class PageFourValues : public Page GwApi::BoatValue *bvalue3 = pageData.values[2]; // Third element in list String name3 = xdrDelete(bvalue3->getName()); // Value name name3 = name3.substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bvalue3, logger); // Check if boat data value is to be calibrated double value3 = bvalue3->value; // Value as double in SI unit bool valid3 = bvalue3->valid; // Valid information String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places @@ -76,7 +72,6 @@ class PageFourValues : public Page GwApi::BoatValue *bvalue4 = pageData.values[3]; // Fourth element in list String name4 = xdrDelete(bvalue4->getName()); // Value name name4 = name4.substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bvalue4, logger); // Check if boat data value is to be calibrated double value4 = bvalue4->value; // Value as double in SI unit bool valid4 = bvalue4->valid; // Valid information String svalue4 = formatValue(bvalue4, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places diff --git a/lib/obp60task/PageFourValues2.cpp b/lib/obp60task/PageFourValues2.cpp index e608409..730e14b 100644 --- a/lib/obp60task/PageFourValues2.cpp +++ b/lib/obp60task/PageFourValues2.cpp @@ -2,7 +2,6 @@ #include "Pagedata.h" #include "OBP60Extensions.h" -#include "BoatDataCalibration.h" class PageFourValues2 : public Page { @@ -46,7 +45,6 @@ class PageFourValues2 : public Page GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue) String name1 = xdrDelete(bvalue1->getName()); // Value name name1 = name1.substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated double value1 = bvalue1->value; // Value as double in SI unit bool valid1 = bvalue1->valid; // Valid information String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places @@ -56,7 +54,6 @@ class PageFourValues2 : public Page GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue) String name2 = xdrDelete(bvalue2->getName()); // Value name name2 = name2.substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bvalue2, logger); // Check if boat data value is to be calibrated double value2 = bvalue2->value; // Value as double in SI unit bool valid2 = bvalue2->valid; // Valid information String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places @@ -66,7 +63,6 @@ class PageFourValues2 : public Page GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue) String name3 = xdrDelete(bvalue3->getName()); // Value name name3 = name3.substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bvalue3, logger); // Check if boat data value is to be calibrated double value3 = bvalue3->value; // Value as double in SI unit bool valid3 = bvalue3->valid; // Valid information String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places @@ -76,7 +72,6 @@ class PageFourValues2 : public Page GwApi::BoatValue *bvalue4 = pageData.values[3]; // Second element in list (only one value by PageOneValue) String name4 = xdrDelete(bvalue4->getName()); // Value name name4 = name4.substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bvalue4, logger); // Check if boat data value is to be calibrated double value4 = bvalue4->value; // Value as double in SI unit bool valid4 = bvalue4->valid; // Valid information String svalue4 = formatValue(bvalue4, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places diff --git a/lib/obp60task/PageOneValue.cpp b/lib/obp60task/PageOneValue.cpp index 6349f29..a5c0f9c 100644 --- a/lib/obp60task/PageOneValue.cpp +++ b/lib/obp60task/PageOneValue.cpp @@ -2,7 +2,6 @@ #include "Pagedata.h" #include "OBP60Extensions.h" -#include "BoatDataCalibration.h" #include "OBPDataOperations.h" #include "OBPcharts.h" @@ -88,7 +87,6 @@ private: String name1 = xdrDelete(bValue1->getName()); // Value name name1 = name1.substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bValue1, logger); // Check if boat data value is to be calibrated double value1 = bValue1->value; // Value as double in SI unit bool valid1 = bValue1->valid; // Valid information String sValue1 = formatValue(bValue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places diff --git a/lib/obp60task/PageRudderPosition.cpp b/lib/obp60task/PageRudderPosition.cpp index 22b5f91..6a8695f 100644 --- a/lib/obp60task/PageRudderPosition.cpp +++ b/lib/obp60task/PageRudderPosition.cpp @@ -2,7 +2,6 @@ #include "Pagedata.h" #include "OBP60Extensions.h" -#include "BoatDataCalibration.h" class PageRudderPosition : public Page { @@ -41,7 +40,6 @@ public: GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list String name1 = bvalue1->getName().c_str(); // Value name name1 = name1.substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated value1 = bvalue1->value; // Raw value without unit convertion bool valid1 = bvalue1->valid; // Valid information String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places diff --git a/lib/obp60task/PageSixValues.cpp b/lib/obp60task/PageSixValues.cpp index af735f2..b75f307 100644 --- a/lib/obp60task/PageSixValues.cpp +++ b/lib/obp60task/PageSixValues.cpp @@ -2,7 +2,6 @@ #include "Pagedata.h" #include "OBP60Extensions.h" -#include "BoatDataCalibration.h" const int SixValues_x1 = 5; const int SixValues_DeltaX = 200; @@ -57,7 +56,6 @@ class PageSixValues : public Page bvalue = pageData.values[i]; DataName[i] = xdrDelete(bvalue->getName()); DataName[i] = DataName[i].substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bvalue, logger); // Check if boat data value is to be calibrated DataValue[i] = bvalue->value; // Value as double in SI unit DataValid[i] = bvalue->valid; DataText[i] = formatValue(bvalue, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places diff --git a/lib/obp60task/PageThreeValues.cpp b/lib/obp60task/PageThreeValues.cpp index 996e2bc..7c5324f 100644 --- a/lib/obp60task/PageThreeValues.cpp +++ b/lib/obp60task/PageThreeValues.cpp @@ -2,7 +2,6 @@ #include "Pagedata.h" #include "OBP60Extensions.h" -#include "BoatDataCalibration.h" class PageThreeValues : public Page { @@ -44,7 +43,6 @@ class PageThreeValues : public Page GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue) String name1 = xdrDelete(bvalue1->getName()); // Value name name1 = name1.substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated double value1 = bvalue1->value; // Value as double in SI unit bool valid1 = bvalue1->valid; // Valid information String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places @@ -54,7 +52,6 @@ class PageThreeValues : public Page GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list String name2 = xdrDelete(bvalue2->getName()); // Value name name2 = name2.substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bvalue2, logger); // Check if boat data value is to be calibrated double value2 = bvalue2->value; // Value as double in SI unit bool valid2 = bvalue2->valid; // Valid information String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places @@ -64,7 +61,6 @@ class PageThreeValues : public Page GwApi::BoatValue *bvalue3 = pageData.values[2]; // Third element in list String name3 = xdrDelete(bvalue3->getName()); // Value name name3 = name3.substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bvalue3, logger); // Check if boat data value is to be calibrated double value3 = bvalue3->value; // Value as double in SI unit bool valid3 = bvalue3->valid; // Valid information String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places diff --git a/lib/obp60task/PageTwoValues.cpp b/lib/obp60task/PageTwoValues.cpp index d4c0d98..323cbcb 100644 --- a/lib/obp60task/PageTwoValues.cpp +++ b/lib/obp60task/PageTwoValues.cpp @@ -2,7 +2,6 @@ #include "Pagedata.h" #include "OBP60Extensions.h" -#include "BoatDataCalibration.h" #include "OBPDataOperations.h" #include "OBPcharts.h" @@ -69,7 +68,6 @@ private: int yOffset = YOFFSET * i; String name = xdrDelete(bValue[i]->getName()); // Value name name = name.substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bValue[i], logger); // Check if boat data value is to be calibrated double value = bValue[i]->value; // Value as double in SI unit bool valid = bValue[i]->valid; // Valid information String sValue = formatValue(bValue[i], *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places diff --git a/lib/obp60task/PageWind.cpp b/lib/obp60task/PageWind.cpp index 226b430..242a365 100644 --- a/lib/obp60task/PageWind.cpp +++ b/lib/obp60task/PageWind.cpp @@ -3,7 +3,6 @@ #include "Pagedata.h" #include "OBP60Extensions.h" #include "N2kMessages.h" -#include "BoatDataCalibration.h" #define front_width 120 #define front_height 162 @@ -324,7 +323,6 @@ public: } String name1 = bvalue1->getName().c_str(); // Value name name1 = name1.substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated double value1 = bvalue1->value; // Value as double in SI unit // bool valid1 = bvalue1->valid; // Valid information String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places @@ -338,7 +336,6 @@ public: } String name2 = bvalue2->getName().c_str(); // Value name name2 = name2.substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bvalue2, logger); // Check if boat data value is to be calibrated double value2 = bvalue2->value; // Value as double in SI unit // bool valid2 = bvalue2->valid; // Valid information if (simulation) { diff --git a/lib/obp60task/PageWindRose.cpp b/lib/obp60task/PageWindRose.cpp index c4ab0e0..427e64b 100644 --- a/lib/obp60task/PageWindRose.cpp +++ b/lib/obp60task/PageWindRose.cpp @@ -2,7 +2,6 @@ #include "Pagedata.h" #include "OBP60Extensions.h" -#include "BoatDataCalibration.h" class PageWindRose : public Page { @@ -52,7 +51,6 @@ public: GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue) String name1 = xdrDelete(bvalue1->getName()); // Value name name1 = name1.substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated double value1 = bvalue1->value; // Value as double in SI unit bool valid1 = bvalue1->valid; // Valid information value1 = formatValue(bvalue1, *commonData).value;// Format only nesaccery for simulation data for pointer @@ -67,7 +65,6 @@ public: GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list String name2 = xdrDelete(bvalue2->getName()); // Value name name2 = name2.substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bvalue2, logger); // Check if boat data value is to be calibrated double value2 = bvalue2->value; // Value as double in SI unit bool valid2 = bvalue2->valid; // Valid information String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places @@ -81,7 +78,6 @@ public: GwApi::BoatValue *bvalue3 = pageData.values[2]; // Third element in list String name3 = xdrDelete(bvalue3->getName()); // Value name name3 = name3.substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bvalue3, logger); // Check if boat data value is to be calibrated double value3 = bvalue3->value; // Value as double in SI unit bool valid3 = bvalue3->valid; // Valid information String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places @@ -95,7 +91,6 @@ public: GwApi::BoatValue *bvalue4 = pageData.values[3]; // Fourth element in list String name4 = xdrDelete(bvalue4->getName()); // Value name name4 = name4.substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bvalue4, logger); // Check if boat data value is to be calibrated double value4 = bvalue4->value; // Value as double in SI unit bool valid4 = bvalue4->valid; // Valid information String svalue4 = formatValue(bvalue4, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places @@ -109,7 +104,6 @@ public: GwApi::BoatValue *bvalue5 = pageData.values[4]; // Fifth element in list String name5 = xdrDelete(bvalue5->getName()); // Value name name5 = name5.substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bvalue5, logger); // Check if boat data value is to be calibrated double value5 = bvalue5->value; // Value as double in SI unit bool valid5 = bvalue5->valid; // Valid information String svalue5 = formatValue(bvalue5, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places @@ -123,7 +117,6 @@ public: GwApi::BoatValue *bvalue6 = pageData.values[5]; // Sixth element in list String name6 = xdrDelete(bvalue6->getName()); // Value name name6 = name6.substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bvalue6, logger); // Check if boat data value is to be calibrated double value6 = bvalue6->value; // Value as double in SI unit bool valid6 = bvalue6->valid; // Valid information String svalue6 = formatValue(bvalue6, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places diff --git a/lib/obp60task/PageWindRoseFlex.cpp b/lib/obp60task/PageWindRoseFlex.cpp index 26efa28..d3526e0 100644 --- a/lib/obp60task/PageWindRoseFlex.cpp +++ b/lib/obp60task/PageWindRoseFlex.cpp @@ -2,7 +2,6 @@ #include "Pagedata.h" #include "OBP60Extensions.h" -#include "BoatDataCalibration.h" class PageWindRoseFlex : public Page { @@ -79,7 +78,6 @@ public: } String name1 = bvalue1->getName().c_str(); // Value name name1 = name1.substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated double value1 = bvalue1->value; // Value as double in SI unit bool valid1 = bvalue1->valid; // Valid information String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places @@ -97,7 +95,6 @@ public: } String name2 = bvalue2->getName().c_str(); // Value name name2 = name2.substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bvalue2, logger); // Check if boat data value is to be calibrated double value2 = bvalue2->value; // Value as double in SI unit bool valid2 = bvalue2->valid; // Valid information if (simulation) { @@ -122,7 +119,6 @@ public: else{ name3font=Ubuntu_Bold12pt8b; } - calibrationData.calibrateInstance(bvalue3, logger); // Check if boat data value is to be calibrated double value3 = bvalue3->value; // Value as double in SI unit bool valid3 = bvalue3->valid; // Valid information String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places @@ -142,7 +138,6 @@ public: else{ name4font=Ubuntu_Bold12pt8b; } - calibrationData.calibrateInstance(bvalue4, logger); // Check if boat data value is to be calibrated double value4 = bvalue4->value; // Value as double in SI unit bool valid4 = bvalue4->valid; // Valid information String svalue4 = formatValue(bvalue4, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places @@ -162,7 +157,6 @@ public: else{ name5font=Ubuntu_Bold12pt8b; } - calibrationData.calibrateInstance(bvalue5, logger); // Check if boat data value is to be calibrated double value5 = bvalue5->value; // Value as double in SI unit bool valid5 = bvalue5->valid; // Valid information String svalue5 = formatValue(bvalue5, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places @@ -182,7 +176,6 @@ public: else{ name6font=Ubuntu_Bold8pt8b; } - calibrationData.calibrateInstance(bvalue6, logger); // Check if boat data value is to be calibrated double value6 = bvalue6->value; // Value as double in SI unit bool valid6 = bvalue6->valid; // Valid information String svalue6 = formatValue(bvalue6, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places diff --git a/lib/obp60task/config.json b/lib/obp60task/config.json index 307f9f4..2aa21fa 100644 --- a/lib/obp60task/config.json +++ b/lib/obp60task/config.json @@ -763,8 +763,10 @@ "AWA", "AWS", "COG", + "DBS", "DBT", "HDM", + "HDT", "PRPOS", "RPOS", "SOG", @@ -790,7 +792,7 @@ "obp60":"true" }, "condition": [ - { "calInstance1": ["AWA", "AWS", "COG", "DBT", "HDM", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } + { "calInstance1": ["AWA", "AWS", "COG", "DBS", "DBT", "HDM", "HDT", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } ] }, { @@ -798,13 +800,13 @@ "label": "Data Instance 1 Calibration Slope", "type": "number", "default": "1.00", - "description": "Slope for data instance 1", + "description": "Slope for data instance 1; Default: 1(!)", "category": "OBP60 Calibrations", "capabilities": { "obp60":"true" }, "condition": [ - { "calInstance1": ["AWA", "AWS", "COG", "DBT", "HDM", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } + { "calInstance1": ["AWA", "AWS", "COG", "DBS", "DBT", "HDM", "HDT", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } ] }, { @@ -821,7 +823,7 @@ "obp60":"true" }, "condition": [ - { "calInstance1": ["AWA", "AWS", "COG", "DBT", "HDM", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } + { "calInstance1": ["AWA", "AWS", "COG", "DBS", "DBT", "HDM", "HDT", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } ] }, { @@ -835,8 +837,10 @@ "AWA", "AWS", "COG", + "DBS", "DBT", "HDM", + "HDT", "PRPOS", "RPOS", "SOG", @@ -862,7 +866,7 @@ "obp60":"true" }, "condition": [ - { "calInstance2": ["AWA", "AWS", "COG", "DBT", "HDM", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } + { "calInstance2": ["AWA", "AWS", "COG", "DBS", "DBT", "HDM", "HDT", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } ] }, { @@ -870,13 +874,13 @@ "label": "Data Instance 2 Calibration Slope", "type": "number", "default": "1.00", - "description": "Slope for data instance 2", + "description": "Slope for data instance 2; Default: 1(!)", "category": "OBP60 Calibrations", "capabilities": { "obp60":"true" }, "condition": [ - { "calInstance2": ["AWA", "AWS", "COG", "DBT", "HDM", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } + { "calInstance2": ["AWA", "AWS", "COG", "DBS", "DBT", "HDM", "HDT", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } ] }, { @@ -893,7 +897,7 @@ "obp60":"true" }, "condition": [ - { "calInstance2": ["AWA", "AWS", "COG", "DBT", "HDM", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } + { "calInstance2": ["AWA", "AWS", "COG", "DBS", "DBT", "HDM", "HDT", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } ] }, { @@ -907,8 +911,10 @@ "AWA", "AWS", "COG", + "DBS", "DBT", "HDM", + "HDT", "PRPOS", "RPOS", "SOG", @@ -934,7 +940,7 @@ "obp60":"true" }, "condition": [ - { "calInstance3": ["AWA", "AWS", "COG", "DBT", "HDM", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } + { "calInstance3": ["AWA", "AWS", "COG", "DBS", "DBT", "HDM", "HDT", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } ] }, { @@ -942,13 +948,13 @@ "label": "Data Instance 3 Calibration Slope", "type": "number", "default": "1.00", - "description": "Slope for data instance 3", + "description": "Slope for data instance 3; Default: 1(!)", "category": "OBP60 Calibrations", "capabilities": { "obp60":"true" }, "condition": [ - { "calInstance3": ["AWA", "AWS", "COG", "DBT", "HDM", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } + { "calInstance3": ["AWA", "AWS", "COG", "DBS", "DBT", "HDM", "HDT", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } ] }, { @@ -965,7 +971,81 @@ "obp60":"true" }, "condition": [ - { "calInstance3": ["AWA", "AWS", "COG", "DBT", "HDM", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } + { "calInstance3": ["AWA", "AWS", "COG", "DBS", "DBT", "HDM", "HDT", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } + ] + }, + { + "name": "calInstance4", + "label": "Calibration Data Instance 4", + "type": "list", + "default": "---", + "description": "Data instance for calibration", + "list": [ + "---", + "AWA", + "AWS", + "COG", + "DBS", + "DBT", + "HDM", + "HDT", + "PRPOS", + "RPOS", + "SOG", + "STW", + "TWA", + "TWS", + "TWD", + "WTemp" + ], + "category": "OBP60 Calibrations", + "capabilities": { + "obp60":"true" + } + }, + { + "name": "calOffset4", + "label": "Data Instance 4 Calibration Offset", + "type": "number", + "default": "0.00", + "description": "Offset for data instance 4", + "category": "OBP60 Calibrations", + "capabilities": { + "obp60":"true" + }, + "condition": [ + { "calInstance4": ["AWA", "AWS", "COG", "DBS", "DBT", "HDM", "HDT", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } + ] + }, + { + "name": "calSlope4", + "label": "Data Instance 4 Calibration Slope", + "type": "number", + "default": "1.00", + "description": "Slope for data instance 3; Default: 1(!)", + "category": "OBP60 Calibrations", + "capabilities": { + "obp60":"true" + }, + "condition": [ + { "calInstance4": ["AWA", "AWS", "COG", "DBS", "DBT", "HDM", "HDT", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } + ] + }, + { + "name": "calSmooth4", + "label": "Data Instance 4 Smoothing", + "type": "number", + "default": "0", + "check": "checkMinMax", + "min": 0, + "max": 10, + "description": "Smoothing factor [0..10]; 0 = no smoothing", + "category": "OBP60 Calibrations", + "capabilities": { + "obp60":"true" + }, + "condition": [ + { "calInstance4": ["AWA", "AWS", "COG", "DBS", "DBT", "HDM", "HDT", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } ] }, { diff --git a/lib/obp60task/config_obp40.json b/lib/obp60task/config_obp40.json index 9889b04..54a5409 100644 --- a/lib/obp60task/config_obp40.json +++ b/lib/obp60task/config_obp40.json @@ -774,8 +774,10 @@ "AWA", "AWS", "COG", + "DBS", "DBT", "HDM", + "HDT", "PRPOS", "RPOS", "SOG", @@ -801,7 +803,7 @@ "obp40":"true" }, "condition": [ - { "calInstance1": ["AWA", "AWS", "COG", "DBT", "HDM", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } + { "calInstance1": ["AWA", "AWS", "COG", "DBS", "DBT", "HDM", "HDT", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } ] }, { @@ -809,13 +811,13 @@ "label": "Data Instance 1 Calibration Slope", "type": "number", "default": "1.00", - "description": "Slope for data instance 1", + "description": "Slope for data instance 1, Default: 1(!)", "category": "OBP40 Calibrations", "capabilities": { "obp40":"true" }, "condition": [ - { "calInstance1": ["AWA", "AWS", "COG", "DBT", "HDM", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } + { "calInstance1": ["AWA", "AWS", "COG", "DBS", "DBT", "HDM", "HDT", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } ] }, { @@ -832,7 +834,7 @@ "obp40":"true" }, "condition": [ - { "calInstance1": ["AWA", "AWS", "COG", "DBT", "HDM", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } + { "calInstance1": ["AWA", "AWS", "COG", "DBS", "DBT", "HDM", "HDT", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } ] }, { @@ -846,8 +848,10 @@ "AWA", "AWS", "COG", + "DBS", "DBT", "HDM", + "HDT", "PRPOS", "RPOS", "SOG", @@ -873,7 +877,7 @@ "obp40":"true" }, "condition": [ - { "calInstance2": ["AWA", "AWS", "COG", "DBT", "HDM", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } + { "calInstance2": ["AWA", "AWS", "COG", "DBS", "DBT", "HDM", "HDT", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } ] }, { @@ -881,13 +885,13 @@ "label": "Data Instance 2 Calibration Slope", "type": "number", "default": "1.00", - "description": "Slope for data instance 2", + "description": "Slope for data instance 2; Default: 1(!)", "category": "OBP40 Calibrations", "capabilities": { "obp40":"true" }, "condition": [ - { "calInstance2": ["AWA", "AWS", "COG", "DBT", "HDM", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } + { "calInstance2": ["AWA", "AWS", "COG", "DBS", "DBT", "HDM", "HDT", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } ] }, { @@ -904,7 +908,7 @@ "obp40":"true" }, "condition": [ - { "calInstance2": ["AWA", "AWS", "COG", "DBT", "HDM", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } + { "calInstance2": ["AWA", "AWS", "COG", "DBS", "DBT", "HDM", "HDT", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } ] }, { @@ -918,8 +922,10 @@ "AWA", "AWS", "COG", + "DBS", "DBT", "HDM", + "HDT", "PRPOS", "RPOS", "SOG", @@ -945,7 +951,7 @@ "obp40":"true" }, "condition": [ - { "calInstance3": ["AWA", "AWS", "COG", "DBT", "HDM", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } + { "calInstance3": ["AWA", "AWS", "COG", "DBS", "DBT", "HDM", "HDT", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } ] }, { @@ -953,13 +959,13 @@ "label": "Data Instance 3 Calibration Slope", "type": "number", "default": "1.00", - "description": "Slope for data instance 3", + "description": "Slope for data instance 3, Default: 1(!)", "category": "OBP40 Calibrations", "capabilities": { "obp40":"true" }, "condition": [ - { "calInstance3": ["AWA", "AWS", "COG", "DBT", "HDM", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } + { "calInstance3": ["AWA", "AWS", "COG", "DBS", "DBT", "HDM", "HDT", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } ] }, { @@ -976,7 +982,81 @@ "obp40":"true" }, "condition": [ - { "calInstance3": ["AWA", "AWS", "COG", "DBT", "HDM", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } + { "calInstance3": ["AWA", "AWS", "COG", "DBS", "DBT", "HDM", "HDT", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } + ] + }, + { + "name": "calInstance4", + "label": "Calibration Data Instance 4", + "type": "list", + "default": "---", + "description": "Data instance for calibration", + "list": [ + "---", + "AWA", + "AWS", + "COG", + "DBS", + "DBT", + "HDM", + "HDT", + "PRPOS", + "RPOS", + "SOG", + "STW", + "TWA", + "TWS", + "TWD", + "WTemp" + ], + "category": "OBP40 Calibrations", + "capabilities": { + "obp40": "true" + } + }, + { + "name": "calOffset4", + "label": "Data Instance 4 Calibration Offset", + "type": "number", + "default": "0.00", + "description": "Offset for data instance 4", + "category": "OBP40 Calibrations", + "capabilities": { + "obp40":"true" + }, + "condition": [ + { "calInstance4": ["AWA", "AWS", "COG", "DBS", "DBT", "HDM", "HDT", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } + ] + }, + { + "name": "calSlope4", + "label": "Data Instance 4 Calibration Slope", + "type": "number", + "default": "1.00", + "description": "Slope for data instance 4, Default: 1(!)", + "category": "OBP40 Calibrations", + "capabilities": { + "obp40":"true" + }, + "condition": [ + { "calInstance4": ["AWA", "AWS", "COG", "DBS", "DBT", "HDM", "HDT", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } + ] + }, + { + "name": "calSmooth4", + "label": "Data Instance 4 Smoothing", + "type": "number", + "default": "0", + "check": "checkMinMax", + "min": 0, + "max": 10, + "description": "Smoothing factor [0..10]; 0 = no smoothing", + "category": "OBP40 Calibrations", + "capabilities": { + "obp40":"true" + }, + "condition": [ + { "calInstance4": ["AWA", "AWS", "COG", "DBS", "DBT", "HDM", "HDT", "PRPOS", "RPOS", "SOG", "STW", "TWA", "TWS", "TWD", "WTemp" ] } ] }, { diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp index e206204..cc825fa 100644 --- a/lib/obp60task/obp60task.cpp +++ b/lib/obp60task/obp60task.cpp @@ -12,7 +12,6 @@ #include // GxEPD2 lib for b/w E-Ink displays #include "OBP60Extensions.h" // Functions lib for extension board #include "OBP60Keypad.h" // Functions for keypad -#include "BoatDataCalibration.h" // Functions lib for data instance calibration #include "OBPDataOperations.h" // Functions lib for data operations such as true wind calculation #ifdef BOARD_OBP40S3 @@ -147,7 +146,6 @@ void keyboardTask(void *param){ vTaskDelete(NULL); } -// Scorgan: moved class declaration to header file to make class available to other functions // --- Class BoatValueList -------------- bool BoatValueList::addValueToList(GwApi::BoatValue *v){ for (int i=0;igetString(xxx); - //add all necessary data to common data + CalibrationData calibrationDataList(logger); // all boat data types which are supposed to be calibrated //fill the page data from config numPages=config->getInt(config->visiblePages,1); @@ -482,26 +479,25 @@ void OBP60Task(GwApi *api){ pages[i].parameters.values.push_back(value); } - // Read the specified boat data type of relevant pages and create a history buffer for each type + // Read the specified boat data types of relevant pages and create a history buffer for each type if (pages[i].parameters.pageName == "OneValue" || pages[i].parameters.pageName == "TwoValues" || pages[i].parameters.pageName == "WindPlot") { for (auto pVal : pages[i].parameters.values) { - hstryBufList.addBuffer(pVal->getName()); + hstryBufferList.addBuffer(pVal->getName()); } } // Add list of history buffers to page parameters - pages[i].parameters.hstryBuffers = &hstryBufList; + pages[i].parameters.hstryBuffers = &hstryBufferList; } // add out of band system page (always available) Page *syspage = allPages.pages[0]->creator(commonData); - // Check user settings for true wind calculation + // Read user settings from config file bool calcTrueWnds = api->getConfig()->getBool(api->getConfig()->calcTrueWnds, false); bool useSimuData = api->getConfig()->getBool(api->getConfig()->useSimuData, false); - - // Read all calibration data settings from config - calibrationData.readConfig(config, logger); + // Read user calibration data settings from config file + calibrationDataList.readConfig(config); // Display screenshot handler for HTTP request // http://192.168.15.1/api/user/OBP60Task/screenshot @@ -816,10 +812,10 @@ void OBP60Task(GwApi *api){ api->getStatus(commonData.status); if (calcTrueWnds) { - trueWind.addWinds(); + trueWind.addWinds(); // calculate true wind data from apparent wind values } - // Handle history buffers for certain boat data for windplot page and other usage - hstryBufList.handleHstryBufs(useSimuData, commonData); + calibrationDataList.handleCalibration(&boatValues); // Process calibration for all boat data in + hstryBufferList.handleHstryBufs(useSimuData, commonData); // Handle history buffers for certain boat data for windplot page and other usage // Clear display // getdisplay().fillRect(0, 0, getdisplay().width(), getdisplay().height(), commonData.bgcolor);