dsfb-semiconductor 0.1.0

Deterministic DSFB semiconductor benchmark companion for SECOM and PHM-style dataset adapters
Documentation
#[cfg(feature = "std")]
use crate::precursor::DsaConfig;
use serde::{Deserialize, Serialize};
#[cfg(not(feature = "std"))]
use alloc::string::String;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PipelineConfig {
    pub healthy_pass_runs: usize,
    pub drift_window: usize,
    pub envelope_sigma: f64,
    pub boundary_fraction_of_rho: f64,
    pub state_confirmation_steps: usize,
    pub persistent_state_steps: usize,
    pub density_window: usize,
    pub ewma_alpha: f64,
    pub ewma_sigma_multiplier: f64,
    pub cusum_kappa_sigma_multiplier: f64,
    pub cusum_alarm_sigma_multiplier: f64,
    pub run_energy_sigma_multiplier: f64,
    pub pca_variance_explained: f64,
    pub pca_t2_sigma_multiplier: f64,
    pub pca_spe_sigma_multiplier: f64,
    pub drift_sigma_multiplier: f64,
    pub slew_sigma_multiplier: f64,
    pub grazing_window: usize,
    pub grazing_min_hits: usize,
    pub pre_failure_lookback_runs: usize,
    pub minimum_healthy_observations: usize,
    pub epsilon: f64,
    #[cfg(feature = "std")]
    pub dsa: DsaConfig,
}

impl Default for PipelineConfig {
    fn default() -> Self {
        Self {
            healthy_pass_runs: 100,
            drift_window: 5,
            envelope_sigma: 3.0,
            boundary_fraction_of_rho: 0.5,
            state_confirmation_steps: 2,
            persistent_state_steps: 2,
            density_window: 10,
            ewma_alpha: 0.2,
            ewma_sigma_multiplier: 3.0,
            cusum_kappa_sigma_multiplier: 0.5,
            cusum_alarm_sigma_multiplier: 5.0,
            run_energy_sigma_multiplier: 3.0,
            pca_variance_explained: 0.95,
            pca_t2_sigma_multiplier: 3.0,
            pca_spe_sigma_multiplier: 3.0,
            drift_sigma_multiplier: 3.0,
            slew_sigma_multiplier: 3.0,
            grazing_window: 10,
            grazing_min_hits: 3,
            pre_failure_lookback_runs: 20,
            minimum_healthy_observations: 2,
            epsilon: 1.0e-9,
            #[cfg(feature = "std")]
            dsa: DsaConfig::default(),
        }
    }
}

impl PipelineConfig {
    pub fn validate(&self) -> Result<(), String> {
        if self.healthy_pass_runs < 2 {
            return Err("healthy_pass_runs must be at least 2".into());
        }
        if self.drift_window == 0 {
            return Err("drift_window must be positive".into());
        }
        if self.envelope_sigma <= 0.0 {
            return Err("envelope_sigma must be positive".into());
        }
        if !(0.0..=1.0).contains(&self.boundary_fraction_of_rho) {
            return Err("boundary_fraction_of_rho must be in [0, 1]".into());
        }
        if self.state_confirmation_steps == 0 {
            return Err("state_confirmation_steps must be positive".into());
        }
        if self.persistent_state_steps == 0 {
            return Err("persistent_state_steps must be positive".into());
        }
        if self.density_window == 0 {
            return Err("density_window must be positive".into());
        }
        if !(0.0..=1.0).contains(&self.ewma_alpha) || self.ewma_alpha == 0.0 {
            return Err("ewma_alpha must be in (0, 1]".into());
        }
        if self.ewma_sigma_multiplier <= 0.0 {
            return Err("ewma_sigma_multiplier must be positive".into());
        }
        if self.cusum_kappa_sigma_multiplier <= 0.0 {
            return Err("cusum_kappa_sigma_multiplier must be positive".into());
        }
        if self.cusum_alarm_sigma_multiplier <= 0.0 {
            return Err("cusum_alarm_sigma_multiplier must be positive".into());
        }
        if self.run_energy_sigma_multiplier <= 0.0 {
            return Err("run_energy_sigma_multiplier must be positive".into());
        }
        if !(0.0..=1.0).contains(&self.pca_variance_explained) || self.pca_variance_explained == 0.0
        {
            return Err("pca_variance_explained must be in (0, 1]".into());
        }
        if self.pca_t2_sigma_multiplier <= 0.0 {
            return Err("pca_t2_sigma_multiplier must be positive".into());
        }
        if self.pca_spe_sigma_multiplier <= 0.0 {
            return Err("pca_spe_sigma_multiplier must be positive".into());
        }
        if self.minimum_healthy_observations < 2 {
            return Err("minimum_healthy_observations must be at least 2".into());
        }
        #[cfg(feature = "std")]
        self.dsa.validate().map_err(|err| err.to_string())?;
        Ok(())
    }
}

#[cfg(feature = "std")]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RunConfiguration {
    pub dataset: String,
    pub config: PipelineConfig,
    pub data_root: String,
    pub output_root: String,
    pub secom_fetch_if_missing: bool,
}