From c30b9c0ed06a5feae4f4df4db77c63023470f65f Mon Sep 17 00:00:00 2001 From: Jared Miller Date: Tue, 16 Dec 2025 17:37:51 -0500 Subject: [PATCH] Add a doc on hysteria --- docs/hysteria.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 docs/hysteria.md diff --git a/docs/hysteria.md b/docs/hysteria.md new file mode 100644 index 0000000..0b438c1 --- /dev/null +++ b/docs/hysteria.md @@ -0,0 +1,31 @@ +# hysteresis in lofivor + +## the problem without it + +say your target is 8.33ms. your frame times naturally jitter: 8.2, 8.4, 8.3, 8.5, 8.2... + +without hysteresis, every time it crosses 8.33ms you'd log "crossed threshold!" - potentially dozens of times per second. the log becomes useless noise. + +## how the code works + +from `sandbox_main.zig` lines 74-89: + +``` +was_above=false → need frame_ms > 10.33 (target + 2.0 margin) to flip to true +was_above=true → need frame_ms < 8.33 (target) to flip back to false +``` + +this creates a "dead zone" between 8.33 and 10.33ms where no state change happens. + +## the magnet analogy + +the `was_above_target` boolean is like the magnet's current polarity. the frame time "pushing" past thresholds is like the magnetic field. the key insight: **the threshold you need to cross depends on which side you're currently on.** + +if you're in "good" state, you need a significant spike (>10.33ms) before you flip to "bad". if you're in "bad" state, you only need to drop below 8.33ms to recover. this asymmetry is the hysteresis. + +## real-world examples + +- thermostat: heat on at 68°F, off at 72°F (prevents rapid on/off cycling) +- schmitt trigger in electronics: same concept, prevents noise from causing oscillation + +the `THRESHOLD_MARGIN` of 2.0ms is the "width" of the hysteresis band - bigger = more stable but less responsive.