mirror of https://codeberg.org/topola/topola.git
feat(autorouter/multilayer_reconfigurator): Add tracking of SMA of rate
SMA = Simple Moving Average
This commit is contained in:
parent
0f3f96d4af
commit
eff58d99e3
|
|
@ -4,7 +4,10 @@
|
|||
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use topola::{interactor::activity::ActivityStepperWithStatus, stepper::EstimateLinearProgress};
|
||||
use topola::{
|
||||
interactor::activity::ActivityStepperWithStatus,
|
||||
stepper::{EstimateProgress, GetMaybeReconfigurationTriggerProgress},
|
||||
};
|
||||
|
||||
use crate::{translator::Translator, viewport::Viewport};
|
||||
|
||||
|
|
@ -40,21 +43,32 @@ impl StatusBar {
|
|||
));
|
||||
|
||||
if let Some(activity) = maybe_activity {
|
||||
let linear_progress = activity.estimate_linear_progress();
|
||||
let value = linear_progress.value();
|
||||
let maximum = linear_progress.maximum();
|
||||
let progress = activity.estimate_progress();
|
||||
let value = progress.value();
|
||||
let maximum = progress.reference();
|
||||
let ratio = *value as f32 / *maximum as f32;
|
||||
|
||||
ui.add(egui::ProgressBar::new(ratio).text(format!(
|
||||
"{:.1}% ({:.1}/{:.1})",
|
||||
ratio * 100.0,
|
||||
value,
|
||||
maximum
|
||||
)));
|
||||
if let Some(trigger_progress) = activity.reconfiguration_trigger_progress() {
|
||||
ui.add(egui::ProgressBar::new(ratio).text(format!(
|
||||
"{:.1}% ({:.1}/{:.1}) (sma: {:.1}, min: {:.1}))",
|
||||
ratio * 100.0,
|
||||
value,
|
||||
maximum,
|
||||
trigger_progress.value(),
|
||||
trigger_progress.reference(),
|
||||
)));
|
||||
} else {
|
||||
ui.add(egui::ProgressBar::new(ratio).text(format!(
|
||||
"{:.1}% ({:.1}/{:.1})",
|
||||
ratio * 100.0,
|
||||
value,
|
||||
maximum
|
||||
)));
|
||||
}
|
||||
|
||||
let linear_subprogress = linear_progress.subscale();
|
||||
let linear_subprogress = progress.subscale();
|
||||
let value = linear_subprogress.value();
|
||||
let maximum = linear_subprogress.maximum();
|
||||
let maximum = linear_subprogress.reference();
|
||||
let ratio = *value as f32 / *maximum as f32;
|
||||
|
||||
ui.add(egui::ProgressBar::new(ratio).text(format!(
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ pub struct Workspace {
|
|||
Receiver<std::io::Result<Result<History, serde_json::Error>>>,
|
||||
),
|
||||
|
||||
update_counter: f32,
|
||||
dt_accumulator: f32,
|
||||
}
|
||||
|
||||
impl Workspace {
|
||||
|
|
@ -65,7 +65,7 @@ impl Workspace {
|
|||
)
|
||||
})?,
|
||||
history_channel: channel(),
|
||||
update_counter: 0.0,
|
||||
dt_accumulator: 0.0,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -82,12 +82,12 @@ impl Workspace {
|
|||
let instant = Instant::now();
|
||||
|
||||
if maybe_step_rate.is_some() {
|
||||
self.update_counter += interactive_input.dt;
|
||||
self.dt_accumulator += interactive_input.dt;
|
||||
}
|
||||
|
||||
while maybe_step_rate.is_none_or(|step_rate| self.update_counter >= 1.0 / step_rate) {
|
||||
while maybe_step_rate.is_none_or(|step_rate| self.dt_accumulator >= 1.0 / step_rate) {
|
||||
if let Some(step_rate) = maybe_step_rate {
|
||||
self.update_counter -= 1.0 / step_rate;
|
||||
self.dt_accumulator -= 1.0 / step_rate;
|
||||
}
|
||||
|
||||
if let ControlFlow::Break(()) = self.update_state(tr, error_dialog, interactive_input) {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use crate::{
|
|||
board::{edit::BoardEdit, AccessMesadata},
|
||||
layout::via::ViaWeight,
|
||||
router::ng,
|
||||
stepper::{Abort, EstimateLinearProgress, LinearScale, Step},
|
||||
stepper::{Abort, EstimateProgress, GetMaybeReconfigurationTriggerProgress, LinearScale, Step},
|
||||
};
|
||||
|
||||
use super::{
|
||||
|
|
@ -173,16 +173,14 @@ impl<M: AccessMesadata + Clone> Abort<Invoker<M>> for ExecutionStepper<M> {
|
|||
|
||||
// Since enum_dispatch does not really support generics, we implement this the
|
||||
// long way by using `match`.
|
||||
impl<M> EstimateLinearProgress for ExecutionStepper<M> {
|
||||
impl<M> EstimateProgress for ExecutionStepper<M> {
|
||||
type Value = usize;
|
||||
type Subscale = LinearScale<f64>;
|
||||
|
||||
fn estimate_linear_progress(&self) -> LinearScale<usize, LinearScale<f64>> {
|
||||
fn estimate_progress(&self) -> LinearScale<usize, LinearScale<f64>> {
|
||||
match self {
|
||||
ExecutionStepper::MultilayerAutoroute(autoroute) => {
|
||||
autoroute.estimate_linear_progress()
|
||||
}
|
||||
ExecutionStepper::PlanarAutoroute(autoroute) => autoroute.estimate_linear_progress(),
|
||||
ExecutionStepper::MultilayerAutoroute(autoroute) => autoroute.estimate_progress(),
|
||||
ExecutionStepper::PlanarAutoroute(autoroute) => autoroute.estimate_progress(),
|
||||
ExecutionStepper::TopoAutoroute(..) => {
|
||||
LinearScale::new(0, 0, LinearScale::new(0.0, 0.0, ()))
|
||||
}
|
||||
|
|
@ -198,3 +196,22 @@ impl<M> EstimateLinearProgress for ExecutionStepper<M> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Since enum_dispatch does not really support generics, we implement this the
|
||||
// long way by using `match`.
|
||||
impl<M> GetMaybeReconfigurationTriggerProgress for ExecutionStepper<M> {
|
||||
type Subscale = ();
|
||||
|
||||
fn reconfiguration_trigger_progress(&self) -> Option<LinearScale<f64>> {
|
||||
match self {
|
||||
ExecutionStepper::MultilayerAutoroute(autoroute) => {
|
||||
autoroute.reconfiguration_trigger_progress()
|
||||
}
|
||||
ExecutionStepper::PlanarAutoroute(autoroute) => None,
|
||||
ExecutionStepper::TopoAutoroute(..) => None,
|
||||
ExecutionStepper::PlaceVia(..) => None,
|
||||
ExecutionStepper::RemoveBands(..) => None,
|
||||
ExecutionStepper::MeasureLength(..) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,9 +21,7 @@ use crate::{
|
|||
drawing::graph::PrimitiveIndex,
|
||||
geometry::{edit::Edit, primitive::PrimitiveShape},
|
||||
router::{navcord::Navcord, navmesh::Navmesh, thetastar::ThetastarStepper},
|
||||
stepper::{
|
||||
Abort, EstimateLinearProgress, LinearScale, ReconfiguratorStatus, Reconfigure, Step,
|
||||
},
|
||||
stepper::{Abort, EstimateProgress, LinearScale, ReconfiguratorStatus, Reconfigure, Step},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
@ -119,12 +117,12 @@ impl<M: AccessMesadata> Reconfigure<Autorouter<M>> for MultilayerAutorouteExecut
|
|||
}
|
||||
}
|
||||
|
||||
impl EstimateLinearProgress for MultilayerAutorouteExecutionStepper {
|
||||
impl EstimateProgress for MultilayerAutorouteExecutionStepper {
|
||||
type Value = usize;
|
||||
type Subscale = LinearScale<f64>;
|
||||
|
||||
fn estimate_linear_progress(&self) -> LinearScale<usize, LinearScale<f64>> {
|
||||
self.planar.estimate_linear_progress()
|
||||
fn estimate_progress(&self) -> LinearScale<usize, LinearScale<f64>> {
|
||||
self.planar.estimate_progress()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@ use crate::{
|
|||
geometry::primitive::PrimitiveShape,
|
||||
router::{navcord::Navcord, navmesh::Navmesh, thetastar::ThetastarStepper},
|
||||
stepper::{
|
||||
Abort, EstimateLinearProgress, LinearScale, ReconfiguratorStatus, Reconfigure, Step,
|
||||
Abort, EstimateProgress, GetMaybeReconfigurationTriggerProgress, LinearScale,
|
||||
ReconfiguratorStatus, Reconfigure, SmaRateReconfigurationTrigger, Step,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -39,6 +40,7 @@ pub type MultilayerReconfiguratorStatus =
|
|||
|
||||
pub struct MultilayerAutorouteReconfigurator {
|
||||
stepper: MultilayerAutorouteExecutionStepper,
|
||||
reconfiguration_trigger: SmaRateReconfigurationTrigger,
|
||||
reconfigurer: MultilayerAutorouteReconfigurer,
|
||||
options: MultilayerAutorouteOptions,
|
||||
}
|
||||
|
|
@ -72,6 +74,7 @@ impl MultilayerAutorouteReconfigurator {
|
|||
preconfiguration,
|
||||
options,
|
||||
)?,
|
||||
reconfiguration_trigger: SmaRateReconfigurationTrigger::new(10, 0.5, 0.5),
|
||||
reconfigurer,
|
||||
options,
|
||||
})
|
||||
|
|
@ -83,6 +86,9 @@ impl MultilayerAutorouteReconfigurator {
|
|||
planar_result: Result<PlanarAutorouteConfigurationStatus, AutorouterError>,
|
||||
) -> Result<ControlFlow<Option<BoardEdit>, MultilayerReconfiguratorStatus>, AutorouterError>
|
||||
{
|
||||
// Reset the reconfiguration trigger.
|
||||
self.reconfiguration_trigger = SmaRateReconfigurationTrigger::new(4, 0.5, 0.5);
|
||||
|
||||
loop {
|
||||
let configuration = match self
|
||||
.reconfigurer
|
||||
|
|
@ -120,6 +126,9 @@ impl<M: AccessMesadata> Step<Autorouter<M>, Option<BoardEdit>, MultilayerReconfi
|
|||
autorouter: &mut Autorouter<M>,
|
||||
) -> Result<ControlFlow<Option<BoardEdit>, MultilayerReconfiguratorStatus>, AutorouterError>
|
||||
{
|
||||
self.reconfiguration_trigger
|
||||
.update(*self.estimate_progress().value() as f64);
|
||||
|
||||
match self.stepper.step(autorouter) {
|
||||
Ok(ControlFlow::Break(maybe_edit)) => Ok(ControlFlow::Break(maybe_edit)),
|
||||
Ok(ControlFlow::Continue(ReconfiguratorStatus::Running(status))) => {
|
||||
|
|
@ -141,12 +150,24 @@ impl<M: AccessMesadata> Abort<Autorouter<M>> for MultilayerAutorouteReconfigurat
|
|||
}
|
||||
}
|
||||
|
||||
impl EstimateLinearProgress for MultilayerAutorouteReconfigurator {
|
||||
impl EstimateProgress for MultilayerAutorouteReconfigurator {
|
||||
type Value = usize;
|
||||
type Subscale = LinearScale<f64>;
|
||||
|
||||
fn estimate_linear_progress(&self) -> LinearScale<usize, LinearScale<f64>> {
|
||||
self.stepper.estimate_linear_progress()
|
||||
fn estimate_progress(&self) -> LinearScale<usize, LinearScale<f64>> {
|
||||
self.stepper.estimate_progress()
|
||||
}
|
||||
}
|
||||
|
||||
impl GetMaybeReconfigurationTriggerProgress for MultilayerAutorouteReconfigurator {
|
||||
type Subscale = ();
|
||||
|
||||
fn reconfiguration_trigger_progress(&self) -> Option<LinearScale<f64>> {
|
||||
Some(LinearScale::new(
|
||||
(*self.reconfiguration_trigger.maybe_sma_rate_per_sec())?,
|
||||
*self.reconfiguration_trigger.min_sma_rate_per_sec(),
|
||||
(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ use crate::{
|
|||
router::{
|
||||
navcord::Navcord, navmesh::Navmesh, thetastar::ThetastarStepper, RouteStepper, Router,
|
||||
},
|
||||
stepper::{Abort, EstimateLinearProgress, LinearScale, Reconfigure, Step},
|
||||
stepper::{Abort, EstimateProgress, LinearScale, Reconfigure, Step},
|
||||
};
|
||||
|
||||
use super::{
|
||||
|
|
@ -303,21 +303,21 @@ impl<M: AccessMesadata> Reconfigure<Autorouter<M>> for PlanarAutorouteExecutionS
|
|||
}
|
||||
}
|
||||
|
||||
impl EstimateLinearProgress for PlanarAutorouteExecutionStepper {
|
||||
impl EstimateProgress for PlanarAutorouteExecutionStepper {
|
||||
type Value = usize;
|
||||
type Subscale = LinearScale<f64>;
|
||||
|
||||
fn estimate_linear_progress(&self) -> LinearScale<usize, LinearScale<f64>> {
|
||||
fn estimate_progress(&self) -> LinearScale<usize, LinearScale<f64>> {
|
||||
LinearScale::new(
|
||||
self.curr_ratline_index,
|
||||
self.configuration().ratlines.len(),
|
||||
LinearScale::new(
|
||||
self.route
|
||||
.as_ref()
|
||||
.map_or(0.0, |route| *route.estimate_linear_progress().value()),
|
||||
.map_or(0.0, |route| *route.estimate_progress().value()),
|
||||
self.route
|
||||
.as_ref()
|
||||
.map_or(0.0, |route| *route.estimate_linear_progress().maximum()),
|
||||
.map_or(0.0, |route| *route.estimate_progress().reference()),
|
||||
(),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -24,9 +24,7 @@ use crate::{
|
|||
drawing::graph::PrimitiveIndex,
|
||||
geometry::primitive::PrimitiveShape,
|
||||
router::{navcord::Navcord, navmesh::Navmesh, thetastar::ThetastarStepper},
|
||||
stepper::{
|
||||
Abort, EstimateLinearProgress, LinearScale, ReconfiguratorStatus, Reconfigure, Step,
|
||||
},
|
||||
stepper::{Abort, EstimateProgress, LinearScale, ReconfiguratorStatus, Reconfigure, Step},
|
||||
};
|
||||
|
||||
pub type PlanarAutorouteReconfiguratorStatus =
|
||||
|
|
@ -120,12 +118,12 @@ impl<M: AccessMesadata> Abort<Autorouter<M>> for PlanarAutorouteReconfigurator {
|
|||
}
|
||||
}
|
||||
|
||||
impl EstimateLinearProgress for PlanarAutorouteReconfigurator {
|
||||
impl EstimateProgress for PlanarAutorouteReconfigurator {
|
||||
type Value = usize;
|
||||
type Subscale = LinearScale<f64>;
|
||||
|
||||
fn estimate_linear_progress(&self) -> LinearScale<usize, LinearScale<f64>> {
|
||||
self.stepper.estimate_linear_progress()
|
||||
fn estimate_progress(&self) -> LinearScale<usize, LinearScale<f64>> {
|
||||
self.stepper.estimate_progress()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,9 @@ use crate::{
|
|||
ng,
|
||||
thetastar::ThetastarStepper,
|
||||
},
|
||||
stepper::{Abort, EstimateLinearProgress, LinearScale, OnEvent, Step},
|
||||
stepper::{
|
||||
Abort, EstimateProgress, GetMaybeReconfigurationTriggerProgress, LinearScale, OnEvent, Step,
|
||||
},
|
||||
};
|
||||
|
||||
/// Stores the interactive input data from the user.
|
||||
|
|
@ -99,17 +101,30 @@ impl<M: AccessMesadata + Clone> Abort<Invoker<M>> for ActivityStepper<M> {
|
|||
}
|
||||
|
||||
// Since enum_dispatch does not really support generics, we implement this the
|
||||
// long way.
|
||||
impl<M> EstimateLinearProgress for ActivityStepper<M> {
|
||||
// long way by using `match`.
|
||||
impl<M> EstimateProgress for ActivityStepper<M> {
|
||||
type Value = usize;
|
||||
type Subscale = LinearScale<f64>;
|
||||
|
||||
fn estimate_linear_progress(&self) -> LinearScale<usize, LinearScale<f64>> {
|
||||
fn estimate_progress(&self) -> LinearScale<usize, LinearScale<f64>> {
|
||||
match self {
|
||||
ActivityStepper::Interaction(..) => {
|
||||
LinearScale::new(0, 0, LinearScale::new(0.0, 0.0, ()))
|
||||
}
|
||||
ActivityStepper::Execution(execution) => execution.estimate_linear_progress(),
|
||||
ActivityStepper::Execution(execution) => execution.estimate_progress(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Since enum_dispatch does not really support generics, we implement this the
|
||||
// long way by using `match`.
|
||||
impl<M> GetMaybeReconfigurationTriggerProgress for ActivityStepper<M> {
|
||||
type Subscale = ();
|
||||
|
||||
fn reconfiguration_trigger_progress(&self) -> Option<LinearScale<f64>> {
|
||||
match self {
|
||||
ActivityStepper::Interaction(..) => None,
|
||||
ActivityStepper::Execution(execution) => execution.reconfiguration_trigger_progress(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -195,12 +210,20 @@ impl<M: AccessMesadata + Clone> OnEvent<ActivityContext<'_, M>, InteractiveEvent
|
|||
}
|
||||
}
|
||||
|
||||
impl<M> EstimateLinearProgress for ActivityStepperWithStatus<M> {
|
||||
impl<M> EstimateProgress for ActivityStepperWithStatus<M> {
|
||||
type Value = usize;
|
||||
type Subscale = LinearScale<f64>;
|
||||
|
||||
fn estimate_linear_progress(&self) -> LinearScale<usize, LinearScale<f64>> {
|
||||
self.activity.estimate_linear_progress()
|
||||
fn estimate_progress(&self) -> LinearScale<usize, LinearScale<f64>> {
|
||||
self.activity.estimate_progress()
|
||||
}
|
||||
}
|
||||
|
||||
impl<M> GetMaybeReconfigurationTriggerProgress for ActivityStepperWithStatus<M> {
|
||||
type Subscale = ();
|
||||
|
||||
fn reconfiguration_trigger_progress(&self) -> Option<LinearScale<f64>> {
|
||||
self.activity.reconfiguration_trigger_progress()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use crate::{
|
|||
geometry::primitive::PrimitiveShape,
|
||||
graph::GenericIndex,
|
||||
layout::{poly::PolyWeight, Layout},
|
||||
stepper::{Abort, EstimateLinearProgress},
|
||||
stepper::{Abort, EstimateProgress},
|
||||
};
|
||||
|
||||
use super::{
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use crate::{
|
|||
thetastar::{ThetastarError, ThetastarStepper},
|
||||
Router, RouterThetastarStrategy,
|
||||
},
|
||||
stepper::{EstimateLinearProgress, LinearScale, Step},
|
||||
stepper::{EstimateProgress, LinearScale, Step},
|
||||
};
|
||||
|
||||
#[derive(Getters, Dissolve)]
|
||||
|
|
@ -99,11 +99,11 @@ impl<R: AccessRules> Step<Router<'_, R>, BandTermsegIndex> for RouteStepper {
|
|||
}
|
||||
}
|
||||
|
||||
impl EstimateLinearProgress for RouteStepper {
|
||||
impl EstimateProgress for RouteStepper {
|
||||
type Value = f64;
|
||||
type Subscale = ();
|
||||
|
||||
fn estimate_linear_progress(&self) -> LinearScale<f64> {
|
||||
self.thetastar.estimate_linear_progress()
|
||||
fn estimate_progress(&self) -> LinearScale<f64> {
|
||||
self.thetastar.estimate_progress()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ use thiserror::Error;
|
|||
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use crate::stepper::{EstimateLinearProgress, LinearScale, Step};
|
||||
use crate::stepper::{EstimateProgress, LinearScale, Step};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct MinScored<K, T>(pub K, pub T);
|
||||
|
|
@ -443,7 +443,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<G, K> EstimateLinearProgress for ThetastarStepper<G, K>
|
||||
impl<G, K> EstimateProgress for ThetastarStepper<G, K>
|
||||
where
|
||||
G: GraphBase,
|
||||
G::NodeId: Eq + Ord,
|
||||
|
|
@ -453,7 +453,7 @@ where
|
|||
type Value = K;
|
||||
type Subscale = ();
|
||||
|
||||
fn estimate_linear_progress(&self) -> LinearScale<Self::Value> {
|
||||
fn estimate_progress(&self) -> LinearScale<Self::Value> {
|
||||
LinearScale::new(
|
||||
self.progress_estimate_value,
|
||||
self.progress_estimate_maximum,
|
||||
|
|
|
|||
101
src/stepper.rs
101
src/stepper.rs
|
|
@ -3,6 +3,7 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use core::ops::ControlFlow;
|
||||
use std::{collections::VecDeque, time::Instant};
|
||||
|
||||
use derive_getters::Getters;
|
||||
|
||||
|
|
@ -86,34 +87,104 @@ pub trait OnEvent<Ctx, Event> {
|
|||
#[derive(Clone, Copy, Debug, Getters)]
|
||||
pub struct LinearScale<V, S = ()> {
|
||||
value: V,
|
||||
maximum: V,
|
||||
reference: V,
|
||||
subscale: S,
|
||||
}
|
||||
|
||||
impl<V, S> LinearScale<V, S> {
|
||||
pub fn new(value: V, maximum: V, subscale: S) -> Self {
|
||||
pub fn new(value: V, reference: V, subscale: S) -> Self {
|
||||
Self {
|
||||
value,
|
||||
maximum,
|
||||
reference,
|
||||
subscale,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: Default> Default for LinearScale<V> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
value: V::default(),
|
||||
maximum: V::default(),
|
||||
subscale: (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Some steppers report estimates of how far they are from completion.
|
||||
pub trait EstimateLinearProgress {
|
||||
pub trait EstimateProgress {
|
||||
type Value;
|
||||
type Subscale;
|
||||
|
||||
fn estimate_linear_progress(&self) -> LinearScale<Self::Value, Self::Subscale>;
|
||||
fn estimate_progress(&self) -> LinearScale<Self::Value, Self::Subscale>;
|
||||
}
|
||||
|
||||
pub trait GetMaybeReconfigurationTriggerProgress {
|
||||
type Subscale;
|
||||
|
||||
fn reconfiguration_trigger_progress(&self) -> Option<LinearScale<f64, Self::Subscale>>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Getters)]
|
||||
pub struct SmaRateReconfigurationTrigger {
|
||||
#[getter(skip)]
|
||||
sample_buffer: VecDeque<f64>,
|
||||
#[getter(skip)]
|
||||
last_instant: Instant,
|
||||
#[getter(skip)]
|
||||
last_value: f64,
|
||||
maybe_sma_rate_per_sec: Option<f64>,
|
||||
#[getter(skip)]
|
||||
sample_buffer_size: usize,
|
||||
#[getter(skip)]
|
||||
sampling_interval_secs: f64,
|
||||
min_sma_rate_per_sec: f64,
|
||||
}
|
||||
|
||||
impl SmaRateReconfigurationTrigger {
|
||||
pub fn new(
|
||||
sample_buffer_size: usize,
|
||||
sampling_interval_secs: f64,
|
||||
min_sma_rate_per_sec: f64,
|
||||
) -> Self {
|
||||
Self {
|
||||
sample_buffer: VecDeque::new(),
|
||||
last_instant: Instant::now(),
|
||||
last_value: 0.0,
|
||||
maybe_sma_rate_per_sec: None,
|
||||
sample_buffer_size,
|
||||
sampling_interval_secs,
|
||||
min_sma_rate_per_sec,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, value: f64) -> bool {
|
||||
let elapsed = self.last_instant.elapsed();
|
||||
let delta = value - self.last_value;
|
||||
|
||||
if elapsed.as_secs_f64() >= self.sampling_interval_secs {
|
||||
let count = (elapsed.as_secs_f64() / self.sampling_interval_secs) as usize;
|
||||
let mut total_pushed = 0.0;
|
||||
let mut total_popped = 0.0;
|
||||
|
||||
for _ in 0..count {
|
||||
let pushed = delta.max(0.0) / count as f64;
|
||||
self.sample_buffer.push_back(delta.max(0.0) / count as f64);
|
||||
total_pushed += pushed;
|
||||
|
||||
if self.sample_buffer.len() > self.sample_buffer_size {
|
||||
total_popped += self.sample_buffer.pop_front().unwrap_or_default();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(sma_rate_per_sec) = self.maybe_sma_rate_per_sec {
|
||||
self.maybe_sma_rate_per_sec = Some(
|
||||
sma_rate_per_sec
|
||||
+ (total_pushed - total_popped) / self.sample_buffer_size as f64,
|
||||
)
|
||||
} else if self.sample_buffer.len() >= self.sample_buffer_size {
|
||||
self.maybe_sma_rate_per_sec =
|
||||
Some(self.sample_buffer.iter().sum::<f64>() / self.sample_buffer_size as f64)
|
||||
}
|
||||
|
||||
self.last_instant = Instant::now();
|
||||
self.last_value = value;
|
||||
}
|
||||
|
||||
if let Some(sma_rate_per_sec) = self.maybe_sma_rate_per_sec {
|
||||
sma_rate_per_sec >= self.min_sma_rate_per_sec
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue