Skip to main content

dsfb_semiconductor/
config.rs

1#[cfg(feature = "std")]
2use crate::precursor::DsaConfig;
3use serde::{Deserialize, Serialize};
4#[cfg(not(feature = "std"))]
5use alloc::string::String;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct PipelineConfig {
9    pub healthy_pass_runs: usize,
10    pub drift_window: usize,
11    pub envelope_sigma: f64,
12    pub boundary_fraction_of_rho: f64,
13    pub state_confirmation_steps: usize,
14    pub persistent_state_steps: usize,
15    pub density_window: usize,
16    pub ewma_alpha: f64,
17    pub ewma_sigma_multiplier: f64,
18    pub cusum_kappa_sigma_multiplier: f64,
19    pub cusum_alarm_sigma_multiplier: f64,
20    pub run_energy_sigma_multiplier: f64,
21    pub pca_variance_explained: f64,
22    pub pca_t2_sigma_multiplier: f64,
23    pub pca_spe_sigma_multiplier: f64,
24    pub drift_sigma_multiplier: f64,
25    pub slew_sigma_multiplier: f64,
26    pub grazing_window: usize,
27    pub grazing_min_hits: usize,
28    pub pre_failure_lookback_runs: usize,
29    pub minimum_healthy_observations: usize,
30    pub epsilon: f64,
31    #[cfg(feature = "std")]
32    pub dsa: DsaConfig,
33}
34
35impl Default for PipelineConfig {
36    fn default() -> Self {
37        Self {
38            healthy_pass_runs: 100,
39            drift_window: 5,
40            envelope_sigma: 3.0,
41            boundary_fraction_of_rho: 0.5,
42            state_confirmation_steps: 2,
43            persistent_state_steps: 2,
44            density_window: 10,
45            ewma_alpha: 0.2,
46            ewma_sigma_multiplier: 3.0,
47            cusum_kappa_sigma_multiplier: 0.5,
48            cusum_alarm_sigma_multiplier: 5.0,
49            run_energy_sigma_multiplier: 3.0,
50            pca_variance_explained: 0.95,
51            pca_t2_sigma_multiplier: 3.0,
52            pca_spe_sigma_multiplier: 3.0,
53            drift_sigma_multiplier: 3.0,
54            slew_sigma_multiplier: 3.0,
55            grazing_window: 10,
56            grazing_min_hits: 3,
57            pre_failure_lookback_runs: 20,
58            minimum_healthy_observations: 2,
59            epsilon: 1.0e-9,
60            #[cfg(feature = "std")]
61            dsa: DsaConfig::default(),
62        }
63    }
64}
65
66impl PipelineConfig {
67    pub fn validate(&self) -> Result<(), String> {
68        if self.healthy_pass_runs < 2 {
69            return Err("healthy_pass_runs must be at least 2".into());
70        }
71        if self.drift_window == 0 {
72            return Err("drift_window must be positive".into());
73        }
74        if self.envelope_sigma <= 0.0 {
75            return Err("envelope_sigma must be positive".into());
76        }
77        if !(0.0..=1.0).contains(&self.boundary_fraction_of_rho) {
78            return Err("boundary_fraction_of_rho must be in [0, 1]".into());
79        }
80        if self.state_confirmation_steps == 0 {
81            return Err("state_confirmation_steps must be positive".into());
82        }
83        if self.persistent_state_steps == 0 {
84            return Err("persistent_state_steps must be positive".into());
85        }
86        if self.density_window == 0 {
87            return Err("density_window must be positive".into());
88        }
89        if !(0.0..=1.0).contains(&self.ewma_alpha) || self.ewma_alpha == 0.0 {
90            return Err("ewma_alpha must be in (0, 1]".into());
91        }
92        if self.ewma_sigma_multiplier <= 0.0 {
93            return Err("ewma_sigma_multiplier must be positive".into());
94        }
95        if self.cusum_kappa_sigma_multiplier <= 0.0 {
96            return Err("cusum_kappa_sigma_multiplier must be positive".into());
97        }
98        if self.cusum_alarm_sigma_multiplier <= 0.0 {
99            return Err("cusum_alarm_sigma_multiplier must be positive".into());
100        }
101        if self.run_energy_sigma_multiplier <= 0.0 {
102            return Err("run_energy_sigma_multiplier must be positive".into());
103        }
104        if !(0.0..=1.0).contains(&self.pca_variance_explained) || self.pca_variance_explained == 0.0
105        {
106            return Err("pca_variance_explained must be in (0, 1]".into());
107        }
108        if self.pca_t2_sigma_multiplier <= 0.0 {
109            return Err("pca_t2_sigma_multiplier must be positive".into());
110        }
111        if self.pca_spe_sigma_multiplier <= 0.0 {
112            return Err("pca_spe_sigma_multiplier must be positive".into());
113        }
114        if self.minimum_healthy_observations < 2 {
115            return Err("minimum_healthy_observations must be at least 2".into());
116        }
117        #[cfg(feature = "std")]
118        self.dsa.validate().map_err(|err| err.to_string())?;
119        Ok(())
120    }
121}
122
123#[cfg(feature = "std")]
124#[derive(Debug, Clone, Serialize, Deserialize)]
125pub struct RunConfiguration {
126    pub dataset: String,
127    pub config: PipelineConfig,
128    pub data_root: String,
129    pub output_root: String,
130    pub secom_fetch_if_missing: bool,
131}