From 4f83e41c0cff957c9fca53742b1b557fdefd7ba7 Mon Sep 17 00:00:00 2001 From: Huamonarch Date: Wed, 13 May 2026 15:15:14 +0800 Subject: [PATCH] feat: add ValvePairModel with jitter/flash/over-delay --- TestProject/RNG/model/ValvePairModel.h | 78 ++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 TestProject/RNG/model/ValvePairModel.h diff --git a/TestProject/RNG/model/ValvePairModel.h b/TestProject/RNG/model/ValvePairModel.h new file mode 100644 index 0000000..c8963c1 --- /dev/null +++ b/TestProject/RNG/model/ValvePairModel.h @@ -0,0 +1,78 @@ +#pragma once +#include +#include +#include +#include +#include +using json = nlohmann::json; + +struct ValvePairModel : IModel { + IModel* action = nullptr; + std::string actionModelName; + + int on_delay_ticks; + int off_delay_ticks; + int delay_jitter_ticks; + float flash_prob; + float delay_over_prob; + int delay_over_ticks; + + enum State { IDLE_LOW, WAITING_RISE, HIGH, WAITING_FALL }; + State state = IDLE_LOW; + int delay_counter = 0; + bool prev_action = false; + + ValvePairModel(const json& params, float) + : on_delay_ticks(params.value("on_delay_ms", 200) / 20) + , off_delay_ticks(params.value("off_delay_ms", 150) / 20) + , delay_jitter_ticks(params.value("delay_jitter_ms", 0) / 20) + , flash_prob(params.value("flash_prob", 0.0f)) + , delay_over_prob(params.value("delay_over_prob", 0.0f)) + , delay_over_ticks(params.value("delay_over_ms", 0) / 20) {} + + void linkPeers(ModelRegistry& reg) override; + + bool evaluateBool(size_t t) override { + if (!action) return false; + bool action_now = action->evaluateBool(t); + + bool rising_edge = !prev_action && action_now; + bool falling_edge = prev_action && !action_now; + prev_action = action_now; + + switch (state) { + case IDLE_LOW: + if (rising_edge) { + bool over = ((double)rand() / RAND_MAX) < delay_over_prob; + int base = over ? delay_over_ticks : on_delay_ticks; + delay_counter = base + (delay_jitter_ticks ? rand() % (delay_jitter_ticks + 1) : 0); + state = WAITING_RISE; + } + break; + case WAITING_RISE: + if (delay_counter > 0) { delay_counter--; } + else { state = HIGH; } + break; + case HIGH: + if (falling_edge) { + bool over = ((double)rand() / RAND_MAX) < delay_over_prob; + int base = over ? delay_over_ticks : off_delay_ticks; + delay_counter = base + (delay_jitter_ticks ? rand() % (delay_jitter_ticks + 1) : 0); + state = WAITING_FALL; + } else if (((double)rand() / RAND_MAX) < flash_prob) { + return false; + } + break; + case WAITING_FALL: + if (delay_counter > 0) { delay_counter--; } + else { state = IDLE_LOW; } + break; + } + return state == HIGH || state == WAITING_FALL; + } + + void reset() override { state = IDLE_LOW; prev_action = false; } +}; + +// linkPeers is defined in ModelRegistry.cc to avoid circular include +// (ValvePairModel needs ModelRegistry, ModelRegistry includes ValvePairModel)