Enhance buzzer detection logic to group intermittent matches with a 500 ms quiet tail, updating relevant configurations and documentation.
This commit is contained in:
+49
-17
@@ -1,39 +1,71 @@
|
||||
#include <string.h>
|
||||
#include "detector.h"
|
||||
#include "feature_params.h"
|
||||
|
||||
void detector_init(detector_t *d) { memset(d, 0, sizeof(*d)); d->state = DET_IDLE; }
|
||||
void detector_reset(detector_t *d) { d->state = DET_IDLE; d->hist = 0; }
|
||||
void detector_reset(detector_t *d)
|
||||
{
|
||||
d->state = DET_IDLE;
|
||||
d->hist = 0;
|
||||
d->frame_index = 0;
|
||||
}
|
||||
|
||||
bool detector_is_match(float rms, float score, float min_rms, float threshold)
|
||||
{
|
||||
return rms >= min_rms && score >= threshold;
|
||||
}
|
||||
|
||||
bool detector_update(detector_t *d, bool match, uint32_t now_ms, const detector_cfg_t *cfg)
|
||||
static void update_idle(detector_t *d, bool match, uint32_t now_ms,
|
||||
uint32_t n, uint32_t m)
|
||||
{
|
||||
uint32_t slot = d->frame_index % 32;
|
||||
d->match_time_ms[slot] = now_ms;
|
||||
d->hist = (d->hist << 1) | (match ? 1u : 0u);
|
||||
|
||||
uint32_t mask = (n == 32) ? 0xFFFFFFFFu : ((1u << n) - 1u);
|
||||
if ((uint32_t)__builtin_popcount(d->hist & mask) >= m) {
|
||||
uint32_t matches_seen = 0;
|
||||
for (uint32_t offset = 0; offset < n; offset++) {
|
||||
if ((d->hist & (1u << offset)) && ++matches_seen == m) {
|
||||
uint32_t first_slot = (d->frame_index - offset) % 32;
|
||||
d->buzz_start_ms = d->match_time_ms[first_slot];
|
||||
break;
|
||||
}
|
||||
}
|
||||
d->last_match_ms = now_ms;
|
||||
d->state = DET_TRIGGERED;
|
||||
d->triggers++;
|
||||
}
|
||||
d->frame_index++;
|
||||
}
|
||||
|
||||
bool detector_update(detector_t *d, bool match, uint32_t now_ms, const detector_cfg_t *cfg,
|
||||
uint32_t *buzz_duration_ms)
|
||||
{
|
||||
uint32_t n = cfg->win_n < 1 ? 1 : (cfg->win_n > 32 ? 32 : cfg->win_n);
|
||||
uint32_t m = cfg->win_m < 1 ? 1 : (cfg->win_m > n ? n : cfg->win_m);
|
||||
|
||||
switch (d->state) {
|
||||
case DET_IDLE: {
|
||||
d->hist = (d->hist << 1) | (match ? 1u : 0u);
|
||||
uint32_t mask = (n == 32) ? 0xFFFFFFFFu : ((1u << n) - 1u);
|
||||
if ((uint32_t)__builtin_popcount(d->hist & mask) >= m) {
|
||||
d->state = DET_TRIGGERED;
|
||||
d->triggers++;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DET_IDLE:
|
||||
update_idle(d, match, now_ms, n, m);
|
||||
return false;
|
||||
case DET_TRIGGERED:
|
||||
d->state = DET_COOLDOWN;
|
||||
d->cooldown_start_ms = now_ms;
|
||||
d->hist = 0;
|
||||
break;
|
||||
case DET_COOLDOWN:
|
||||
if ((uint32_t)(now_ms - d->cooldown_start_ms) >= cfg->cooldown_ms) {
|
||||
if (match && (uint32_t)(now_ms - d->last_match_ms) < cfg->cooldown_ms) {
|
||||
d->last_match_ms = now_ms;
|
||||
d->state = DET_COOLDOWN;
|
||||
} else {
|
||||
d->state = DET_COOLDOWN;
|
||||
if ((uint32_t)(now_ms - d->last_match_ms) < cfg->cooldown_ms) break;
|
||||
d->last_completed_start_ms = d->buzz_start_ms;
|
||||
if (buzz_duration_ms) {
|
||||
*buzz_duration_ms = (uint32_t)(d->last_match_ms - d->buzz_start_ms) +
|
||||
(1000u * HOP_LEN / FS_HZ);
|
||||
}
|
||||
d->state = DET_IDLE;
|
||||
d->hist = 0;
|
||||
if (match) update_idle(d, true, now_ms, n, m);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user