Browse Source

Data validator: Better vibration level estimation, better failover

sbg
Lorenz Meier 10 years ago
parent
commit
e8ce2234f3
  1. 42
      src/lib/ecl/validation/data_validator.h
  2. 93
      src/lib/ecl/validation/data_validator_group.h

42
src/lib/ecl/validation/data_validator.h

@ -73,11 +73,17 @@ public: @@ -73,11 +73,17 @@ public:
uint64_t error_count() { return _error_count; }
/**
* Get the value of this validator
* Get the values of this validator
* @return the stored value
*/
float* value() { return _value; }
/**
* Get the RMS values of this validator
* @return the stored RMS
*/
float* rms() { return _rms; }
/**
* Print the validator value
*
@ -95,8 +101,10 @@ private: @@ -95,8 +101,10 @@ private:
float _M2[3]; /**< RMS component value */
float _rms[3]; /**< root mean square error */
float _value[3]; /**< last value */
float _value_equal_count; /**< equal values in a row */
DataValidator *_sibling; /**< sibling in the group */
const unsigned _noreturn_errcount = 1000; /**< if the error count reaches this value, return sensor as invalid */
const unsigned NORETURN_ERRCOUNT = 1000; /**< if the error count reaches this value, return sensor as invalid */
const unsigned VALUE_EQUAL_COUNT_MAX = 100; /**< if the sensor value is the same (accumulated also between axes) this many times, flag it */
/* we don't want this class to be copied */
DataValidator(const DataValidator&);
@ -113,6 +121,7 @@ DataValidator::DataValidator(DataValidator *prev_sibling) : @@ -113,6 +121,7 @@ DataValidator::DataValidator(DataValidator *prev_sibling) :
_M2{0.0f},
_rms{0.0f},
_value{0.0f},
_value_equal_count(0),
_sibling(prev_sibling)
{
@ -131,7 +140,7 @@ DataValidator::put(uint64_t timestamp, float val[3], uint64_t error_count_in) @@ -131,7 +140,7 @@ DataValidator::put(uint64_t timestamp, float val[3], uint64_t error_count_in)
for (unsigned i = 0; i < _dimensions; i++) {
if (_time_last == 0) {
_mean[i] = val[i];
_mean[i] = 0;
_lp[i] = val[i];
_M2[i] = 0;
} else {
@ -141,10 +150,16 @@ DataValidator::put(uint64_t timestamp, float val[3], uint64_t error_count_in) @@ -141,10 +150,16 @@ DataValidator::put(uint64_t timestamp, float val[3], uint64_t error_count_in)
_mean[i] += delta_val / _event_count;
_M2[i] += delta_val * (lp_val - _mean[i]);
_rms[i] = sqrtf(_M2[i] / (_event_count - 1));
if (fabsf(_value[i] - val[i]) < 0.000001f) {
_value_equal_count++;
} else {
_value_equal_count = 0;
}
}
// XXX replace with better filter, make it auto-tune to update rate
_lp[i] = _lp[i] * 0.95f + val[i] * 0.05f;
_lp[i] = _lp[i] * 0.5f + val[i] * 0.5f;
_value[i] = val[i];
}
@ -161,7 +176,12 @@ DataValidator::confidence(uint64_t timestamp) @@ -161,7 +176,12 @@ DataValidator::confidence(uint64_t timestamp)
}
/* check error count limit */
if (_error_count > _noreturn_errcount) {
if (_error_count > NORETURN_ERRCOUNT) {
return 0.0f;
}
/* we got the exact same sensor value N times in a row */
if (_value_equal_count > VALUE_EQUAL_COUNT_MAX) {
return 0.0f;
}
@ -170,17 +190,19 @@ DataValidator::confidence(uint64_t timestamp) @@ -170,17 +190,19 @@ DataValidator::confidence(uint64_t timestamp)
return 0.0f;
}
// XXX work out scaling between confidence and RMS
//return _rms / _mean;
return 1.0f;
}
void
DataValidator::print()
{
if (_time_last == 0) {
printf("\tno data\n");
return;
}
for (unsigned i = 0; i < _dimensions; i++) {
printf("\tmean: %8.4f lp: %8.4f RMS: %8.4f\n",
(double)(_lp[i] + _mean[i]), (double)_lp[i], (double)_rms[i]);
printf("\tval: %8.4f, lp: %8.4f mean dev: %8.4f RMS: %8.4f\n",
(double) _value[i], (double)_lp[i], (double)_mean[i], (double)_rms[i]);
}
}

93
src/lib/ecl/validation/data_validator_group.h

@ -65,6 +65,20 @@ public: @@ -65,6 +65,20 @@ public:
*/
float* get_best(uint64_t timestamp, int *index);
/**
* Get the RMS / vibration factor
*
* @return float value representing the RMS, which a valid indicator for vibration
*/
float get_vibration_factor(uint64_t timestamp);
/**
* Get the number of failover events
*
* @return the number of failovers
*/
unsigned failover_count();
/**
* Print the validator value
*
@ -73,6 +87,10 @@ public: @@ -73,6 +87,10 @@ public:
private:
DataValidator *_first; /**< sibling in the group */
int _curr_best; /**< currently best index */
int _prev_best; /**< the previous best index */
uint64_t _first_failover_time; /**< timestamp where the first failover occured or zero if none occured */
unsigned _toggle_count; /**< number of back and forth switches between two sensors */
/* we don't want this class to be copied */
DataValidatorGroup(const DataValidatorGroup&);
@ -80,13 +98,19 @@ private: @@ -80,13 +98,19 @@ private:
};
DataValidatorGroup::DataValidatorGroup(unsigned siblings) :
_first(nullptr)
_first(nullptr),
_curr_best(-1),
_prev_best(-1),
_first_failover_time(0),
_toggle_count(0)
{
DataValidator *next = _first;
for (unsigned i = 0; i < siblings; i++) {
next = new DataValidator(next);
}
_first = next;
}
DataValidatorGroup::~DataValidatorGroup()
@ -116,6 +140,7 @@ DataValidatorGroup::get_best(uint64_t timestamp, int *index) @@ -116,6 +140,7 @@ DataValidatorGroup::get_best(uint64_t timestamp, int *index)
DataValidator *next = _first;
// XXX This should eventually also include voting
int pre_check_best = _curr_best;
float max_confidence = 0.0f;
int max_index = -1;
uint64_t min_error_count = 30000;
@ -125,28 +150,90 @@ DataValidatorGroup::get_best(uint64_t timestamp, int *index) @@ -125,28 +150,90 @@ DataValidatorGroup::get_best(uint64_t timestamp, int *index)
while (next != nullptr) {
float confidence = next->confidence(timestamp);
if (confidence > max_confidence &&
next->error_count() < min_error_count) {
if (confidence > max_confidence ||
(fabsf(confidence - max_confidence) < 0.01f && next->error_count() < min_error_count)) {
max_index = i;
max_confidence = confidence;
min_error_count = next->error_count();
best = next;
}
next = next->sibling();
i++;
}
/* the current best sensor is not matching the previous best sensor */
if (max_index != _curr_best) {
/* if we're no initialized, initialize the bookkeeping but do not count a failsafe */
if (_curr_best < 0) {
_prev_best = max_index;
} else {
/* we were initialized before, this is a real failsafe */
_prev_best = pre_check_best;
_toggle_count++;
/* if this is the first time, log when we failed */
if (_first_failover_time == 0) {
_first_failover_time = timestamp;
}
}
/* for all cases we want to keep a record of the best index */
_curr_best = max_index;
}
*index = max_index;
return (best) ? best->value() : nullptr;
}
float
DataValidatorGroup::get_vibration_factor(uint64_t timestamp)
{
DataValidator *next = _first;
float vibe = 0.0f;
/* find the best RMS value of a non-timed out sensor */
while (next != nullptr) {
if (next->confidence(timestamp) > 0.5f) {
float* rms = next->rms();
for (unsigned j = 0; j < 3; j++) {
if (rms[j] > vibe) {
vibe = rms[j];
}
}
}
next = next->sibling();
}
return vibe;
}
void
DataValidatorGroup::print()
{
/* print the group's state */
warnx("validator: best: %d, prev best: %d, failsafe: %s (# %u)",
_curr_best, _prev_best, (_toggle_count > 0) ? "YES" : "NO",
_toggle_count);
DataValidator *next = _first;
unsigned i = 0;
while (next != nullptr) {
printf("sensor #%u:\n", i);
next->print();
next = next->sibling();
i++;
}
}
unsigned
DataValidatorGroup::failover_count()
{
return _toggle_count;
}

Loading…
Cancel
Save