69 lines
3.6 KiB
C
69 lines
3.6 KiB
C
// PC test of the REAL fingerprint.c and detector.c.
|
|
// gcc -I stubs -iquote ../../main host_test.c ../../main/fingerprint.c ../../main/detector.c -lm -o host_test
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include "fingerprint.h"
|
|
#include "detector.h"
|
|
#include "test_vector.h"
|
|
|
|
static int fails;
|
|
#define CHECK(c, ...) do { if (!(c)) { printf("FAIL: " __VA_ARGS__); printf("\n"); fails++; } } while (0)
|
|
|
|
int main(void)
|
|
{
|
|
CHECK(features_init() == ESP_OK, "features_init");
|
|
#if TEST_VECTOR_VALID
|
|
static features_ctx_t ctx; float fp[NUM_BANDS], rms;
|
|
bool ok = features_compute(&ctx, TEST_VECTOR_PCM, fp, &rms);
|
|
float me = 0; for (int b = 0; b < NUM_BANDS; b++) { float e = fabsf(fp[b] - TEST_VECTOR_FP[b]); if (e > me) me = e; }
|
|
printf("parity: ok=%d max|fp err|=%.2e rms C=%.4f py=%.4f\n", ok, me, rms, TEST_VECTOR_RMS);
|
|
CHECK(ok && me < 1e-3f, "fingerprint parity");
|
|
#endif
|
|
// degenerate inputs must not produce NaN
|
|
static int16_t z[FRAME_LEN]; static features_ctx_t c2; float f2[NUM_BANDS], r2;
|
|
CHECK(!features_compute(&c2, z, f2, &r2) && r2 == 0.0f, "silence -> invalid, rms 0");
|
|
for (int b = 0; b < NUM_BANDS; b++) CHECK(f2[b] == 0.0f, "silence fp zero");
|
|
|
|
// Detector starts after N-of-M matches, groups matches within 500 ms,
|
|
// includes intermittent gaps, and excludes the final quiet tail.
|
|
detector_t d; detector_init(&d);
|
|
detector_cfg_t cfg = { 1, 1, 500 };
|
|
uint32_t duration = 0;
|
|
CHECK(!detector_update(&d, true, 0, &cfg, &duration), "event remains open after first match");
|
|
CHECK(d.state == DET_TRIGGERED && d.triggers == 1, "event starts on match");
|
|
CHECK(!detector_update(&d, false, 100, &cfg, &duration), "intermittent gap remains in event");
|
|
CHECK(!detector_update(&d, true, 400, &cfg, &duration), "match within quiet tail extends event");
|
|
CHECK(!detector_update(&d, false, 600, &cfg, &duration), "event remains open before tail expires");
|
|
CHECK(detector_update(&d, false, 900, &cfg, &duration), "event closes at 500 ms after last match");
|
|
CHECK(duration == 432, "duration includes gap, excludes final quiet tail (got %lu ms)",
|
|
(unsigned long)duration);
|
|
CHECK(d.state == DET_IDLE, "returns to idle after event closes");
|
|
CHECK(!detector_update(&d, true, 932, &cfg, &duration), "next event starts after prior event closes");
|
|
CHECK(detector_update(&d, false, 1432, &cfg, &duration), "single-frame event closes");
|
|
CHECK(duration == (1000u * HOP_LEN / FS_HZ), "single-frame duration is one hop (got %lu ms)",
|
|
(unsigned long)duration);
|
|
|
|
detector_reset(&d);
|
|
cfg = (detector_cfg_t){ 5, 3, 500 };
|
|
CHECK(!detector_update(&d, true, 0, &cfg, &duration), "first of three matches");
|
|
CHECK(!detector_update(&d, false, 32, &cfg, &duration), "intervening non-match");
|
|
CHECK(!detector_update(&d, true, 64, &cfg, &duration), "second match");
|
|
CHECK(!detector_update(&d, true, 96, &cfg, &duration), "third match starts event");
|
|
CHECK(d.buzz_start_ms == 0, "event start is the earliest qualifying match");
|
|
CHECK(detector_update(&d, false, 608, &cfg, &duration), "N-of-M event ends after quiet tail");
|
|
CHECK(duration == 128, "N-of-M duration includes one-hop extent (got %lu ms)",
|
|
(unsigned long)duration);
|
|
|
|
// Sparse matches must not satisfy 10-of-15.
|
|
cfg = (detector_cfg_t){ 15, 10, 500 };
|
|
int n = 0;
|
|
detector_reset(&d);
|
|
uint32_t t = 0;
|
|
for (int i = 0; i < 300; i++, t += 32) {
|
|
n += detector_update(&d, i % 3 == 0, t, &cfg, &duration);
|
|
}
|
|
CHECK(n == 0, "1-in-3 matches must not trigger 10/15");
|
|
printf(fails ? "HOST TEST FAILED\n" : "HOST TEST PASSED\n");
|
|
return fails != 0;
|
|
}
|