mirror of
https://github.com/jomjol/AI-on-the-edge-device.git
synced 2025-12-06 19:46:54 +03:00
Implemented late analog / digital transition (#2778)
* Implemented late transition Complete rewrite of analog / digital transition Two tests is still failing, which need to be discussed. * Allow wider range of transition values to support late transition * Added documentation
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <cassert>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
@@ -725,6 +726,130 @@ string ClassFlowPostProcessing::ShiftDecimal(string in, int _decShift){
|
||||
return zw;
|
||||
}
|
||||
|
||||
|
||||
float wrapAround(float val)
|
||||
{
|
||||
return fmod(val, 10.);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks whether val is in the range [min, max]
|
||||
*
|
||||
* Note, this function also handles the wrap around case,
|
||||
* in which min could be larger than max in case of
|
||||
* a circular range
|
||||
*
|
||||
* @param val The value to be checked
|
||||
* @param min Minimal bound of the range
|
||||
* @param max Maximum bound of the range
|
||||
* @return True, if val is in the range
|
||||
*/
|
||||
bool inRange(float val, float min, float max)
|
||||
{
|
||||
assert(min >= 0. && min < 10.0);
|
||||
assert(max >= 0. && max <= 10.0);
|
||||
assert(val >= 0. && val < 10.0);
|
||||
|
||||
if (min <= max)
|
||||
{
|
||||
return min <= val && val <= max;
|
||||
}
|
||||
else
|
||||
{
|
||||
// e.g. between 8 and 2 (of the next round)
|
||||
return (min <= val && val < 10.) || (0. <= val && val <= max);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Synchronizes a potential misalignment between analog and digital part
|
||||
*
|
||||
* @param The current value assembled from digits (pre comma) and analogs (post comma)
|
||||
* @param digitalPrecision The post-comma value of the last digit ([0...9])
|
||||
* @param analogDigitalShift The value of the 0.1 analog, when the digital precision == 5 in [0, 9.9]
|
||||
*
|
||||
* We define 3 phases:
|
||||
* - Pre transition: analog post comma < analogDigitalShift && not in transition
|
||||
* - Transition: Digital Precision in range 1...9
|
||||
* - Post transition: analog post comma > analogDigitalShift && not in transition
|
||||
*
|
||||
* @return The synchronized values as a string
|
||||
*/
|
||||
std::string syncDigitalAnalog(const std::string& value, const std::string& digitalPrecision,
|
||||
double analogDigitalShift)
|
||||
{
|
||||
if (digitalPrecision.empty())
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
const auto pos = value.find('.');
|
||||
if (pos == std::string::npos)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
// disassemble value into pre and post comma part
|
||||
const auto preComma = value.substr(0, pos);
|
||||
|
||||
// memorize, to be able to assemble right numbers of leading zeros
|
||||
const size_t nPreComma = preComma.size();
|
||||
const auto postComma = value.substr(pos+1);
|
||||
|
||||
const float digitalPostComma = std::atof(digitalPrecision.c_str());
|
||||
int digitalPreComma = std::atoi(preComma.c_str());
|
||||
const float analogPostComma = std::atof(("0." + postComma).c_str());
|
||||
|
||||
// Determine phase
|
||||
const bool inTransition = digitalPostComma > 0. && digitalPostComma < 10.;
|
||||
const bool postTransition = !inTransition && inRange(analogPostComma*10., analogDigitalShift, wrapAround(analogDigitalShift + 5.));
|
||||
const bool preTransition = !inTransition && inRange(analogPostComma*10., 0, analogDigitalShift);
|
||||
|
||||
|
||||
if (inRange(analogDigitalShift, 0.5, 5.))
|
||||
{
|
||||
// late transition, last digit starts transition, when analog is between [0.5, 5)
|
||||
if (inTransition || preTransition)
|
||||
{
|
||||
ESP_LOGD("syncDigitalAnalog", "Late digital transition. Increase digital value by 1.");
|
||||
digitalPreComma += 1;
|
||||
}
|
||||
}
|
||||
else if (inRange(analogDigitalShift, 5., 9.5))
|
||||
{
|
||||
// early transition
|
||||
if (postTransition && analogPostComma*10 > analogDigitalShift)
|
||||
{
|
||||
ESP_LOGD("syncDigitalAnalog", "Early digital transition. Decrease digital value by 1.");
|
||||
digitalPreComma -= 1;
|
||||
}
|
||||
|
||||
// transition has not finished, but we are already at the new cycle
|
||||
// this also should handle hanging digits
|
||||
if (inTransition && analogPostComma < 0.5) {
|
||||
digitalPreComma += 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
// assemble result into string again, pad with zeros
|
||||
auto preCommaNew = std::to_string(digitalPreComma);
|
||||
for (size_t i = preCommaNew.size(); i < nPreComma; ++i)
|
||||
preCommaNew = "0" + preCommaNew;
|
||||
|
||||
const std::string result = preCommaNew + "." + postComma;
|
||||
|
||||
#if debugSync
|
||||
ESP_LOGD("syncDigitalAnalog", "result: %s", result.c_str());
|
||||
#endif
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
bool ClassFlowPostProcessing::doFlow(string zwtime)
|
||||
{
|
||||
string result = "";
|
||||
@@ -768,6 +893,8 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
|
||||
|
||||
int previous_value = -1;
|
||||
|
||||
// ------------------- start processing analog values --------------------------//
|
||||
|
||||
if (NUMBERS[j]->analog_roi)
|
||||
{
|
||||
NUMBERS[j]->ReturnRawValue = flowAnalog->getReadout(j, NUMBERS[j]->isExtendedResolution);
|
||||
@@ -781,19 +908,38 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
|
||||
#ifdef SERIAL_DEBUG
|
||||
ESP_LOGD(TAG, "After analog->getReadout: ReturnRaw %s", NUMBERS[j]->ReturnRawValue.c_str());
|
||||
#endif
|
||||
if (NUMBERS[j]->digit_roi && NUMBERS[j]->analog_roi)
|
||||
NUMBERS[j]->ReturnRawValue = "." + NUMBERS[j]->ReturnRawValue;
|
||||
|
||||
if (NUMBERS[j]->digit_roi)
|
||||
// ----------------- start processing digital values --------------------------//
|
||||
|
||||
// we need the precision of the digital values to determine transition phase
|
||||
std::string digitalPrecision = {"0"};
|
||||
if (NUMBERS[j]->digit_roi && NUMBERS[j]->analog_roi) {
|
||||
// we have nachkommad and vorkomman part!
|
||||
|
||||
std::string analogValues = NUMBERS[j]->ReturnRawValue;
|
||||
std::string digitValues = flowDigit->getReadout(j, true, previous_value, NUMBERS[j]->analog_roi->ROI[0]->result_float, 0.);
|
||||
|
||||
if (flowDigit->getCNNType() != Digital)
|
||||
{
|
||||
// The digital type does not provide an extended resolution, so we cannot extract it
|
||||
digitalPrecision = digitValues.substr(digitValues.size() - 1);
|
||||
digitValues = digitValues.substr(0, digitValues.size() - 1);
|
||||
}
|
||||
|
||||
NUMBERS[j]->ReturnRawValue = digitValues + "." + analogValues;
|
||||
}
|
||||
|
||||
|
||||
if (NUMBERS[j]->digit_roi && !NUMBERS[j]->analog_roi)
|
||||
{
|
||||
if (NUMBERS[j]->analog_roi)
|
||||
NUMBERS[j]->ReturnRawValue = flowDigit->getReadout(j, false, previous_value, NUMBERS[j]->analog_roi->ROI[0]->result_float, NUMBERS[j]->AnalogDigitalTransitionStart) + NUMBERS[j]->ReturnRawValue;
|
||||
else
|
||||
NUMBERS[j]->ReturnRawValue = flowDigit->getReadout(j, NUMBERS[j]->isExtendedResolution, previous_value); // Extended Resolution only if there are no analogue digits
|
||||
NUMBERS[j]->ReturnRawValue = flowDigit->getReadout(j, NUMBERS[j]->isExtendedResolution, previous_value); // Extended Resolution only if there are no analogue digits
|
||||
}
|
||||
#ifdef SERIAL_DEBUG
|
||||
ESP_LOGD(TAG, "After digital->getReadout: ReturnRaw %s", NUMBERS[j]->ReturnRawValue.c_str());
|
||||
#endif
|
||||
|
||||
// ------------------ start corrections --------------------------//
|
||||
|
||||
NUMBERS[j]->ReturnRawValue = ShiftDecimal(NUMBERS[j]->ReturnRawValue, NUMBERS[j]->DecimalShift);
|
||||
|
||||
#ifdef SERIAL_DEBUG
|
||||
@@ -826,6 +972,13 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
|
||||
continue; // there is no number because there is still an N.
|
||||
}
|
||||
}
|
||||
|
||||
if (NUMBERS[j]->digit_roi && NUMBERS[j]->analog_roi)
|
||||
{
|
||||
// Synchronize potential misalignment between analog and digital part
|
||||
NUMBERS[j]->ReturnValue = syncDigitalAnalog(NUMBERS[j]->ReturnValue, digitalPrecision, NUMBERS[j]->AnalogDigitalTransitionStart);
|
||||
}
|
||||
|
||||
#ifdef SERIAL_DEBUG
|
||||
ESP_LOGD(TAG, "After findDelimiterPos: ReturnValue %s", NUMBERS[j]->ReturnRawValue.c_str());
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "test_flow_postrocess_helper.h"
|
||||
|
||||
|
||||
|
||||
#include <memory>
|
||||
|
||||
/**
|
||||
* ACHTUNG! Die Test laufen aktuell nur mit ausgeschaltetem Debug in ClassFlowCNNGeneral
|
||||
@@ -542,4 +541,64 @@ void test_doFlowPP4() {
|
||||
|
||||
}
|
||||
|
||||
std::string postProcess(std::vector<float> digits,
|
||||
std::vector<float> analogs,
|
||||
float analog2DigitalTransition=0.0)
|
||||
{
|
||||
std::unique_ptr<UnderTestPost> undertestPost(init_do_flow(std::move(analogs),
|
||||
std::move(digits),
|
||||
Digital100,
|
||||
false, false));
|
||||
|
||||
setAnalogdigitTransistionStart(undertestPost.get(), analog2DigitalTransition);
|
||||
return process_doFlow(undertestPost.get());
|
||||
}
|
||||
|
||||
void test_doFlowLateTransition()
|
||||
{
|
||||
// in these test cases, the last digit before comma turns 3.6 too late
|
||||
float a2dt = 3.6;
|
||||
|
||||
// meter shows 011.0210 but it already needs to be 012.0210, before transition
|
||||
TEST_ASSERT_EQUAL_STRING("12.0210", postProcess({0.0, 1.0, 1.0}, {0.2, 2.2, 1.0, 0.0}, a2dt).c_str());
|
||||
|
||||
// meter shows 011.3210 but it already needs to be 012.3210, just before transition
|
||||
TEST_ASSERT_EQUAL_STRING("12.3210", postProcess({0.0, 1.0, 1.2}, {3.3, 2.2, 1.0, 0.0}, a2dt).c_str());
|
||||
|
||||
// meter shows 012.4210 , this is after transition
|
||||
TEST_ASSERT_EQUAL_STRING("12.4210", postProcess({0.0, 1.0, 2.0}, {4.3, 2.2, 1.0, 0.0}, a2dt).c_str());
|
||||
|
||||
// meter shows 012.987
|
||||
TEST_ASSERT_EQUAL_STRING("12.9870", postProcess({0.0, 1.0, 2.0}, {9.8, 8.7, 7.0, 0.0}, a2dt).c_str());
|
||||
|
||||
// meter shows 0012.003
|
||||
TEST_ASSERT_EQUAL_STRING("13.003", postProcess({0.0, 0.0, 1.0, 2.0}, {0.1, 0.3, 3.1}, a2dt).c_str());
|
||||
|
||||
// meter shows 0012.351
|
||||
TEST_ASSERT_EQUAL_STRING("13.351", postProcess({0.0, 0.0, 1.0, 2.8}, {3.5, 5.2, 1.1}, a2dt).c_str());
|
||||
|
||||
// meter shows 0013.421
|
||||
TEST_ASSERT_EQUAL_STRING("13.421", postProcess({0.0, 0.0, 1.0, 3.0}, {4.1, 2.2, 1.1}, a2dt).c_str());
|
||||
}
|
||||
|
||||
void test_doFlowEarlyTransition()
|
||||
{
|
||||
// in these test cases, the last digit before comma turns at around 7.5
|
||||
// start transition 7.0 end transition 8.0
|
||||
float a2dt = 7.5;
|
||||
|
||||
// meter shows 011.0210 but it already needs to be 012.0210, before transition
|
||||
TEST_ASSERT_EQUAL_STRING("12.6789", postProcess({0.0, 1.0, 2.0}, {6.7, 7.8, 8.9, 9.0}, a2dt).c_str());
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING("12.7234", postProcess({0.0, 1.0, 2.4}, {7.2, 2.3, 3.4, 4.0}, a2dt).c_str());
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING("12.7789", postProcess({0.0, 1.0, 2.7}, {7.7, 7.8, 8.9, 9.0}, a2dt).c_str());
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING("12.8123", postProcess({0.0, 1.0, 3.0}, {8.1, 1.2, 2.3, 3.0}, a2dt).c_str());
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING("13.1234", postProcess({0.0, 1.0, 3.0}, {1.2, 2.3, 3.4, 4.0}, a2dt).c_str());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -164,6 +164,8 @@ extern "C" void app_main()
|
||||
RUN_TEST(test_doFlowPP2);
|
||||
RUN_TEST(test_doFlowPP3);
|
||||
RUN_TEST(test_doFlowPP4);
|
||||
RUN_TEST(test_doFlowLateTransition);
|
||||
RUN_TEST(test_doFlowEarlyTransition);
|
||||
|
||||
// getReadoutRawString test
|
||||
RUN_TEST(test_getReadoutRawString);
|
||||
|
||||
@@ -628,8 +628,8 @@
|
||||
<label for=PostProcessing_AnalogDigitalTransitionStart_enabled><class id="PostProcessing_AnalogDigitalTransitionStart_text" style="color:black;">Analog/Digital Transition Start</class></label>
|
||||
</td>
|
||||
<td>
|
||||
<input required type="number" id="PostProcessing_AnalogDigitalTransitionStart_value1" step="0.1" min="6.0" max="9.9" value="9.2"
|
||||
oninput="(!validity.rangeUnderflow||(value=6.0)) && (!validity.rangeOverflow||(value=9.9)) &&
|
||||
<input required type="number" id="PostProcessing_AnalogDigitalTransitionStart_value1" step="0.1" min="0.1" max="9.9" value="9.2"
|
||||
oninput="(!validity.rangeUnderflow||(value=0.1)) && (!validity.rangeOverflow||(value=9.9)) &&
|
||||
(!validity.stepMismatch||(value=parseInt(this.value)));">
|
||||
</td>
|
||||
<td>$TOOLTIP_PostProcessing_NUMBER.AnalogDigitalTransitionStart</td>
|
||||
|
||||
Reference in New Issue
Block a user