ESPectre SDK 2.8.0-280-gac7af68
Wi-Fi CSI motion sensing for ESP32 firmware
Loading...
Searching...
No Matches
high_accuracy_detector.h
Go to the documentation of this file.
1/*
2 * ESPectre - High-Accuracy Detector
3 *
4 * Neural network-based motion detection algorithm.
5 *
6 * Algorithm:
7 * 1. Calculate spatial turbulence per packet using CV normalization
8 * (`std/mean`)
9 * 2. Apply optional Hampel filtering to turbulence and L1-delta streams
10 * 3. Apply optional low-pass filter for noise reduction
11 * 4. Extract statistical features from turbulence buffer
12 * 5. Run MLP inference using exported architecture metadata
13 * 6. Compare probability to threshold for motion detection
14 *
15 * Author: Francesco Pace <francesco.pace@gmail.com>
16 * SPDX-License-Identifier: GPL-3.0-only
17 * Commercial licensing available under separate agreement; see LICENSING.md.
18 */
19#pragma once
20
21#include "base_detector.h"
22#include "csi_format.h"
23#include "csi_features.h"
25#include "l1_delta_tracker.h"
26#include "ml_feature_trackers.h"
27#include <cstdint>
28#include <cstddef>
29
30namespace espectre {
31
32/**
33 * Neural motion detector, using the MLP weights exported by training.
34 *
35 * Unlike `LightweightDetector` it does not calibrate to the room: it ships a fixed
36 * threshold learned at training time, so it performs best in environments the
37 * training corpus represents. Check the per-chip figures in
38 * `docs/performance/README.md` before choosing it over Lightweight.
39 *
40 * Same usage as `LightweightDetector` on the core-only path, and the same
41 * threading rules. `core/ml_weights.h` is generated by the training script and
42 * must not be edited by hand; retraining is documented in
43 * `docs/ML_TRAINING.md`.
44 */
46public:
47 /**
48 * Constructor
49 *
50 * @param window_size Feature extraction window size (10-200 packets)
51 * @param threshold Motion detection threshold (0.0-1.0 on the ML probability scale)
52 */
53 /**
54 * @param lag Profile-displacement distance in packets. Production uses the
55 * nominal-rate default. Alternate values are for replay experiments
56 * and require retraining before deployment.
57 */
59 float threshold = HIGH_ACCURACY_DEFAULT_THRESHOLD,
60 uint16_t lag = L1_DELTA_LAG);
61
63
64 // Move semantics inherited from BaseDetector
67
68 // Disable copy
71
72 // ========================================================================
73 // BaseDetector interface implementation
74 // ========================================================================
75
76 void process_packet(const int8_t* csi_data, size_t csi_len,
77 const uint8_t* selected_subcarriers = nullptr,
78 uint8_t num_subcarriers = 0,
79 int8_t rssi_dbm = INT8_MIN) override;
80 void advance_missing_slots(uint32_t count) override;
81 void update_state() override;
82 void clear_buffer() override;
83 bool is_ready() const override;
84 bool set_threshold(float threshold) override;
85 float get_threshold() const override { return threshold_; }
86 const char* get_name() const override { return "High Accuracy"; }
88 bool enabled,
89 uint8_t window_size = HAMPEL_TURBULENCE_WINDOW_DEFAULT,
90 float threshold = HAMPEL_TURBULENCE_THRESHOLD_DEFAULT) override;
92 bool enabled,
93 float cutoff_hz = LOWPASS_CUTOFF_DEFAULT) override;
94
95private:
96 /**
97 * Extract ML features from the turbulence buffer and tracker state
98 */
99 void extract_features(float* features_out);
100
101 /**
102 * L1-delta ring capacity for this window: window_size - lag (0 if window
103 * is not larger than the lag).
104 */
105 uint16_t l1_delta_capacity_() const;
106
107 /**
108 * Total size of the single feature-scratch block, in floats.
109 */
110 uint16_t feature_scratch_size_() const;
111
112 /**
113 * Sorted-series view onto the scratch block. Empty when allocation failed.
114 */
115 MLSeriesScratch series_scratch_() const;
116
117 void add_aggregated_turbulence_(float turbulence);
118 const float* ordered_aggregated_turbulence_(uint16_t& count) const;
119
120 /**
121 * Run MLP inference on features.
122 *
123 * The hidden-layer layout is defined by the auto-generated
124 * `ml_weights.h` metadata rather than hardcoded in this class.
125 *
126 * @param features Feature vector expected by the exported model
127 * @return Motion probability (0.0-1.0)
128 */
129 float predict(const float* features);
130
131 float threshold_;
132
133 // L1-delta profile-displacement state, maintained only when the exported
134 // model actually uses L1-delta features (checked against ML_FEATURE_IDS).
135 // Mirrors the shared L1-delta tracker rings; keep aligned with the Python
136 // lag ratio reference.
137 bool uses_l1_tracker_;
138 bool uses_shape_trajectory_tracker_;
139 bool uses_aggregated_turbulence_;
140 uint16_t lag_;
141 L1DeltaTracker l1_tracker_;
142 ChannelShapeTrajectoryTracker shape_trajectory_tracker_;
143
144 // Single heap block reused for packet amplitudes, chronological aggregate
145 // reconstruction, and sorted feature statistics, so these non-overlapping
146 // phases do not each reserve a window-sized buffer.
147 float* feature_scratch_;
148 float* aggregated_turbulence_buffer_;
149 FilteredTurbulenceRing aggregated_turbulence_;
150};
151
152} // namespace espectre
BaseDetector(uint16_t window_size=DETECTOR_DEFAULT_WINDOW_SIZE)
Constructor.
Fixed-capacity turbulence history with optional Hampel and low-pass filtering.
bool set_threshold(float threshold) override
Set detection threshold.
void configure_lowpass(bool enabled, float cutoff_hz=LOWPASS_CUTOFF_DEFAULT) override
Configure low-pass filter.
void configure_hampel(bool enabled, uint8_t window_size=HAMPEL_TURBULENCE_WINDOW_DEFAULT, float threshold=HAMPEL_TURBULENCE_THRESHOLD_DEFAULT) override
Configure Hampel filter.
bool is_ready() const override
Check if detector is ready (buffer filled).
void advance_missing_slots(uint32_t count) override
Advance packet-indexed feature rings for absent temporal slots.
const char * get_name() const override
Get detector name for logging.
void process_packet(const int8_t *csi_data, size_t csi_len, const uint8_t *selected_subcarriers=nullptr, uint8_t num_subcarriers=0, int8_t rssi_dbm=INT8_MIN) override
Process a CSI packet and update internal state.
HighAccuracyDetector & operator=(HighAccuracyDetector &&other) noexcept
HighAccuracyDetector & operator=(const HighAccuracyDetector &)=delete
HighAccuracyDetector(uint16_t window_size=DETECTOR_DEFAULT_WINDOW_SIZE, float threshold=HIGH_ACCURACY_DEFAULT_THRESHOLD, uint16_t lag=L1_DELTA_LAG)
Constructor.
HighAccuracyDetector(HighAccuracyDetector &&other) noexcept
float get_threshold() const override
Get current threshold.
HighAccuracyDetector(const HighAccuracyDetector &)=delete
void update_state() override
Update state machine (call at publish interval).
void clear_buffer() override
Clear turbulence buffer (cold restart).
constexpr uint8_t L1_DELTA_LAG
constexpr uint16_t DETECTOR_DEFAULT_WINDOW_SIZE
constexpr uint8_t HAMPEL_TURBULENCE_WINDOW_DEFAULT
constexpr float HIGH_ACCURACY_DEFAULT_THRESHOLD
constexpr float HAMPEL_TURBULENCE_THRESHOLD_DEFAULT
constexpr float LOWPASS_CUTOFF_DEFAULT