diff --git a/devices/sensor/ld2420_radar.cpp b/devices/sensor/ld2420_radar.cpp index 44ea14c..bbfc140 100644 --- a/devices/sensor/ld2420_radar.cpp +++ b/devices/sensor/ld2420_radar.cpp @@ -1,5 +1,15 @@ #include "ld2420_radar.h" +static uint8_t clamp_score_0_10(int value) { + if (value < 0) { + return 0; + } + if (value > 10) { + return 10; + } + return static_cast(value); +} + Ld2420Radar::Ld2420Radar() { uart = nullptr; reset_runtime_state(); @@ -56,10 +66,10 @@ json += (state.presence ? "true" : "false"); json += ",\"activity_score\":"; - json += String(state.activity_score); + json += String(clamp_score_0_10(state.activity_score)); json += ",\"activity_score_current\":"; - json += String(state.activity_score_current); + json += String(clamp_score_0_10(state.activity_score_current)); json += ",\"activity_score_dynamics\":\""; json += activity_dynamics_to_string(state.activity_score_dynamics); @@ -373,10 +383,7 @@ int score = 1 + static_cast(normalized * 9.0f + 0.5f); - if (score < 1) score = 1; - if (score > 10) score = 10; - - return static_cast(score); + return clamp_score_0_10(score); } void Ld2420Radar::update_activity_history() { @@ -408,9 +415,8 @@ uint8_t average_score = 0; if (activity_bucket_accum_count > 0) { - average_score = static_cast( - activity_bucket_accum_sum / activity_bucket_accum_count - ); + uint32_t avg = activity_bucket_accum_sum / activity_bucket_accum_count; + average_score = clamp_score_0_10(static_cast(avg)); } activity_buckets[activity_bucket_index] = average_score; @@ -428,36 +434,59 @@ void Ld2420Radar::update_activity_outputs() { /* - activity_score = средняя активность за последнюю минуту. - Так как бакет = 10 секунд, берём последние 6 бакетов. + activity_score_current уже считается отдельно в update_activity_history(). + Здесь считаем усреднённую активность за последнюю минуту. + + Берём: + - текущий незавершённый бакет + - до 5 последних завершённых бакетов + И усредняем всё в диапазоне 0..10. */ - uint8_t minute_bucket_count = 6; + uint32_t sum = 0; uint8_t count = 0; - for (uint8_t i = 0; i < minute_bucket_count; i++) { + /* + Текущий частичный бакет. + */ + if (activity_bucket_accum_count > 0) { + uint8_t current_bucket_avg = clamp_score_0_10( + static_cast(activity_bucket_accum_sum / activity_bucket_accum_count) + ); + + sum += current_bucket_avg; + count++; + } + + /* + Последние завершённые бакеты. + Всего хотим получить окно примерно в 1 минуту: + 1 текущий + 5 завершённых = до 6 бакетов по 10 секунд. + */ + uint8_t completed_to_take = 5; + uint8_t taken = 0; + + for (uint8_t i = 0; i < completed_to_take; i++) { int index = static_cast(activity_bucket_index) - 1 - i; if (index < 0) { index += activity_bucket_count; } - /* - Если история ещё не заполнена, не читаем незаписанные хвосты. - */ if (!activity_history_filled) { - if (index >= static_cast(activity_bucket_index)) { + if (index < 0 || index >= activity_bucket_index) { continue; } } - sum += activity_buckets[index]; + sum += clamp_score_0_10(activity_buckets[index]); count++; + taken++; } if (count > 0) { - state.activity_score = static_cast(sum / count); + state.activity_score = clamp_score_0_10(static_cast(sum / count)); } else { - state.activity_score = state.activity_score_current; + state.activity_score = clamp_score_0_10(state.activity_score_current); } state.activity_score_dynamics = calculate_activity_dynamics();