Causal Inference for Multi-Fault Satellite Failures
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Update README

+41 -334
+6 -2
README.md
··· 4 4 ![License](https://img.shields.io/badge/license-MIT-green) 5 5 ![Status](https://img.shields.io/badge/status-active-success) 6 6 7 - **Topics**: `satellite`, `causal-inference`, `bayesian`, `fault-detection`, `python` 7 + 8 8 9 9 Framework for inferring root causes in satellite systems experiencing multiple simultaneous degradations. 10 10 ··· 30 30 │ └──────────────────────────┘ └──────────────────────────┘ │ 31 31 └────────────────────┬───────────────────────────────────────────┘ 32 32 │ Detect Anomalies (>15% deviation) 33 - 33 + v 34 34 ┌────────────────────────────────────────────────────────────────┐ 35 35 │ CAUSAL GRAPH (DAG) │ 36 36 │ │ ··· 108 108 109 109 **4. Deviation Analysis** - Quantified deviations at each timepoint 110 110 ![Deviation Analysis](docs/images/gsat6a_deviation_analysis.png) 111 + 112 + **5. Benchmarks** - Benchmark Results against LSTM and Threshold (OOL) *Note*: Its buggy and is being worked on. 113 + ![Benchmark](docs/benchmark_results.png) 114 + 111 115 112 116 ### Key Results 113 117
causal_graph/__pycache__/root_cause_ranking.cpython-314.pyc

This is a binary file and will not be displayed.

+3 -3
causal_graph/root_cause_ranking.py
··· 244 244 deg_values = getattr(degraded, name) 245 245 nom_values = getattr(nominal, name) 246 246 247 - # --- 1. Sensor Fault Detection (3+ consecutive zeros or NaNs) --- 247 + # Sensor Fault Detection (3+ consecutive zeros or NaNs) 248 248 latest_val = deg_values[-1] if len(deg_values) > 0 else np.nan 249 249 if np.isnan(latest_val) or latest_val == 0.0: 250 250 self._sensor_dead_counts[name] = self._sensor_dead_counts.get(name, 0) + 1 ··· 254 254 if self._sensor_dead_counts[name] >= 3: 255 255 continue 256 256 257 - # --- 2. Eclipse Awareness --- 257 + # Eclipse Awareness 258 258 if is_eclipse and name in ["solar_input", "solar_panel_temp"]: 259 259 continue 260 260 261 - # --- 3. Direction-Aware Deviation --- 261 + # Direction-Aware Deviation 262 262 deg_mean = np.nanmean(deg_values) 263 263 nom_mean = np.nanmean(nom_values) 264 264 residual = deg_mean - nom_mean
+1 -5
causal_graph/stateful_ranking.py
··· 238 238 hypotheses.sort(key=lambda h: h.probability, reverse=True) 239 239 return hypotheses 240 240 241 - # ────────────────────────────────────────────────────────────────── 242 241 # Override base _compute_confidence so analyze() also works correctly 243 - # ────────────────────────────────────────────────────────────────── 244 242 245 243 def _compute_confidence( 246 244 self, ··· 265 263 streak = self._streak.get(cause_name, 0), 266 264 ) 267 265 268 - # ────────────────────────────────────────────────────────────────── 269 266 # Temporally-aware confidence (returns 0–100 PERCENTAGE) 270 - # ────────────────────────────────────────────────────────────────── 271 - 267 + 272 268 def _compute_stateful_confidence( 273 269 self, 274 270 cause_name: str,
-204
docs/benchmark_results.txt
··· 1 - BENCHMARK: Stochastic 100-Scenario Pipeline 2 - [ 1] solar_degradation cat=A | Causal:HIT Baseline:HIT Threshold:HIT 3 - [ 2] battery_aging cat=A | Causal:RANK4 Baseline:HIT Threshold:RANK2 4 - [ 3] solar_degradation cat=A | Causal:HIT Baseline:HIT Threshold:HIT 5 - [ 4] solar_degradation cat=A | Causal:HIT Baseline:HIT Threshold:HIT 6 - [ 5] solar_degradation cat=A | Causal:HIT Baseline:RANK2 Threshold:HIT 7 - [ 6] panel_insulation_degradation cat=A | Causal:HIT Baseline:HIT Threshold:HIT 8 - [ 7] solar_degradation cat=A | Causal:HIT Baseline:HIT Threshold:HIT 9 - [ 8] panel_insulation_degradation cat=A | Causal:HIT Baseline:HIT Threshold:HIT 10 - [ 9] battery_heatsink_failure cat=A | Causal:HIT Baseline:HIT Threshold:HIT 11 - [ 10] battery_heatsink_failure cat=A | Causal:HIT Baseline:HIT Threshold:HIT 12 - [ 11] solar_degradation cat=A | Causal:HIT Baseline:HIT Threshold:HIT 13 - [ 12] panel_insulation_degradation cat=A | Causal:HIT Baseline:HIT Threshold:HIT 14 - [ 13] battery_heatsink_failure cat=A | Causal:HIT Baseline:HIT Threshold:HIT 15 - [ 14] solar_degradation cat=A | Causal:HIT Baseline:RANK2 Threshold:HIT 16 - [ 15] solar_degradation cat=A | Causal:HIT Baseline:HIT Threshold:HIT 17 - [ 16] panel_insulation_degradation cat=A | Causal:HIT Baseline:HIT Threshold:HIT 18 - [ 17] battery_heatsink_failure cat=A | Causal:HIT Baseline:HIT Threshold:HIT 19 - [ 18] battery_heatsink_failure cat=A | Causal:HIT Baseline:HIT Threshold:HIT 20 - [ 19] solar_degradation cat=A | Causal:HIT Baseline:HIT Threshold:HIT 21 - [ 20] battery_aging cat=A | Causal:RANK4 Baseline:HIT Threshold:RANK2 22 - [ 21] battery_aging cat=A | Causal:RANK4 Baseline:HIT Threshold:RANK2 23 - [ 22] solar_degradation cat=A | Causal:HIT Baseline:HIT Threshold:HIT 24 - [ 23] battery_heatsink_failure cat=A | Causal:HIT Baseline:HIT Threshold:HIT 25 - [ 24] battery_heatsink_failure cat=A | Causal:HIT Baseline:HIT Threshold:HIT 26 - [ 25] panel_insulation_degradation cat=A | Causal:HIT Baseline:HIT Threshold:HIT 27 - [ 26] battery_heatsink_failure cat=A | Causal:HIT Baseline:HIT Threshold:HIT 28 - [ 27] panel_insulation_degradation cat=A | Causal:HIT Baseline:HIT Threshold:HIT 29 - [ 28] battery_aging cat=A | Causal:RANK4 Baseline:HIT Threshold:RANK2 30 - [ 29] solar_degradation cat=A | Causal:HIT Baseline:HIT Threshold:HIT 31 - [ 30] battery_aging cat=A | Causal:RANK4 Baseline:HIT Threshold:RANK2 32 - [ 31] solar_degradation cat=A | Causal:HIT Baseline:HIT Threshold:HIT 33 - [ 32] panel_insulation_degradation cat=A | Causal:HIT Baseline:HIT Threshold:HIT 34 - [ 33] solar_degradation cat=A | Causal:HIT Baseline:HIT Threshold:HIT 35 - [ 34] battery_heatsink_failure cat=A | Causal:HIT Baseline:HIT Threshold:HIT 36 - [ 35] battery_heatsink_failure cat=A | Causal:HIT Baseline:HIT Threshold:HIT 37 - [ 36] battery_heatsink_failure cat=A | Causal:HIT Baseline:HIT Threshold:HIT 38 - [ 37] solar_degradation cat=A | Causal:HIT Baseline:HIT Threshold:HIT 39 - [ 38] battery_aging cat=A | Causal:RANK4 Baseline:HIT Threshold:RANK2 40 - [ 39] solar_degradation cat=A | Causal:HIT Baseline:HIT Threshold:HIT 41 - [ 40] solar_degradation cat=A | Causal:HIT Baseline:HIT Threshold:HIT 42 - [ 41] battery_heatsink_failure cat=B | Causal:RANK3 Baseline:HIT Threshold:RANK2 43 - [ 42] solar_degradation cat=B | Causal:HIT Baseline:RANK2 Threshold:HIT 44 - [ 43] battery_aging cat=B | Causal:RANK4 Baseline:RANK2 Threshold:RANK3 45 - [ 44] panel_insulation_degradation cat=B | Causal:RANK6 Baseline:RANK2 Threshold:RANK3 46 - [ 45] battery_heatsink_failure cat=B | Causal:RANK2 Baseline:HIT Threshold:HIT 47 - [ 46] panel_insulation_degradation cat=B | Causal:RANK6 Baseline:RANK3 Threshold:RANK2 48 - [ 47] battery_aging cat=B | Causal:RANK4 Baseline:RANK2 Threshold:RANK2 49 - [ 48] battery_aging cat=B | Causal:RANK4 Baseline:RANK2 Threshold:RANK3 50 - [ 49] battery_aging cat=B | Causal:RANK4 Baseline:HIT Threshold:RANK2 51 - [ 50] panel_insulation_degradation cat=B | Causal:RANK6 Baseline:HIT Threshold:RANK3 52 - [ 51] solar_degradation cat=B | Causal:HIT Baseline:RANK2 Threshold:HIT 53 - [ 52] solar_degradation cat=B | Causal:HIT Baseline:HIT Threshold:HIT 54 - [ 53] battery_heatsink_failure cat=B | Causal:RANK3 Baseline:HIT Threshold:RANK2 55 - [ 54] panel_insulation_degradation cat=B | Causal:RANK6 Baseline:RANK4 Threshold:RANK2 56 - [ 55] panel_insulation_degradation cat=B | Causal:RANK3 Baseline:RANK2 Threshold:RANK2 57 - [ 56] solar_degradation cat=B | Causal:HIT Baseline:RANK2 Threshold:HIT 58 - [ 57] panel_insulation_degradation cat=B | Causal:RANK6 Baseline:RANK3 Threshold:RANK2 59 - [ 58] panel_insulation_degradation cat=B | Causal:RANK6 Baseline:RANK4 Threshold:RANK2 60 - [ 59] panel_insulation_degradation cat=B | Causal:RANK5 Baseline:RANK2 Threshold:RANK2 61 - [ 60] panel_insulation_degradation cat=B | Causal:RANK7 Baseline:RANK4 Threshold:RANK2 62 - [ 61] solar_degradation cat=B | Causal:HIT Baseline:RANK2 Threshold:HIT 63 - [ 62] battery_aging cat=B | Causal:RANK3 Baseline:RANK2 Threshold:RANK2 64 - [ 63] solar_degradation cat=B | Causal:HIT Baseline:RANK2 Threshold:HIT 65 - [ 64] battery_aging cat=B | Causal:RANK4 Baseline:RANK2 Threshold:RANK2 66 - [ 65] battery_heatsink_failure cat=B | Causal:RANK2 Baseline:RANK2 Threshold:HIT 67 - [ 66] battery_heatsink_failure cat=C | Causal:HIT Baseline:RANK3 Threshold:RANK2 68 - [ 67] solar_degradation cat=C | Causal:HIT Baseline:RANK2 Threshold:HIT 69 - [ 68] panel_insulation_degradation cat=C | Causal:HIT Baseline:RANK4 Threshold:RANK3 70 - [ 69] battery_heatsink_failure cat=C | Causal:HIT Baseline:HIT Threshold:HIT 71 - [ 70] panel_insulation_degradation cat=C | Causal:HIT Baseline:HIT Threshold:HIT 72 - [ 71] solar_degradation cat=C | Causal:HIT Baseline:RANK2 Threshold:HIT 73 - [ 72] battery_heatsink_failure cat=C | Causal:HIT Baseline:HIT Threshold:HIT 74 - [ 73] battery_heatsink_failure cat=C | Causal:HIT Baseline:HIT Threshold:HIT 75 - [ 74] panel_insulation_degradation cat=C | Causal:HIT Baseline:HIT Threshold:HIT 76 - [ 75] battery_heatsink_failure cat=C | Causal:HIT Baseline:HIT Threshold:HIT 77 - [ 76] solar_degradation cat=C | Causal:HIT Baseline:RANK2 Threshold:HIT 78 - [ 77] battery_heatsink_failure cat=C | Causal:HIT Baseline:HIT Threshold:HIT 79 - [ 78] solar_degradation cat=C | Causal:HIT Baseline:HIT Threshold:HIT 80 - [ 79] panel_insulation_degradation cat=C | Causal:HIT Baseline:RANK4 Threshold:RANK2 81 - [ 80] solar_degradation cat=C | Causal:HIT Baseline:HIT Threshold:HIT 82 - [ 81] battery_heatsink_failure cat=D | Causal:HIT Baseline:HIT Threshold:RANK2 83 - [ 82] battery_heatsink_failure cat=D | Causal:HIT Baseline:RANK2 Threshold:RANK3 84 - [ 83] battery_heatsink_failure cat=D | Causal:HIT Baseline:RANK2 Threshold:RANK2 85 - [ 84] battery_heatsink_failure cat=D | Causal:HIT Baseline:HIT Threshold:HIT 86 - [ 85] battery_heatsink_failure cat=D | Causal:HIT Baseline:HIT Threshold:HIT 87 - [ 86] battery_heatsink_failure cat=D | Causal:HIT Baseline:HIT Threshold:HIT 88 - [ 87] solar_degradation cat=D | Causal:HIT Baseline:RANK2 Threshold:HIT 89 - [ 88] solar_degradation cat=D | Causal:HIT Baseline:RANK2 Threshold:HIT 90 - [ 89] solar_degradation cat=D | Causal:HIT Baseline:RANK2 Threshold:HIT 91 - [ 90] battery_heatsink_failure cat=D | Causal:HIT Baseline:HIT Threshold:HIT 92 - [ 91] solar_degradation cat=E | Causal:RANK3 Baseline:HIT Threshold:HIT 93 - [ 92] solar_degradation cat=E | Causal:RANK2 Baseline:RANK3 Threshold:RANK2 94 - [ 93] solar_degradation cat=E | Causal:RANK3 Baseline:RANK3 Threshold:RANK2 95 - [ 94] solar_degradation cat=E | Causal:RANK3 Baseline:RANK3 Threshold:RANK2 96 - [ 95] solar_degradation cat=E | Causal:RANK3 Baseline:RANK3 Threshold:RANK2 97 - [ 96] solar_degradation cat=E | Causal:HIT Baseline:HIT Threshold:HIT 98 - [ 97] solar_degradation cat=E | Causal:RANK3 Baseline:RANK3 Threshold:RANK2 99 - [ 98] solar_degradation cat=E | Causal:HIT Baseline:HIT Threshold:HIT 100 - [ 99] solar_degradation cat=E | Causal:RANK3 Baseline:RANK3 Threshold:RANK2 101 - [100] solar_degradation cat=E | Causal:RANK3 Baseline:RANK3 Threshold:RANK2 102 - 103 - RESULTS SUMMARY 104 - 105 - Top-1 Accuracy: 106 - Causal: 67.0% 107 - Baseline: 61.0% 108 - Threshold: 64.0% 109 - Improvement (Causal vs Baseline): +6.0% 110 - 111 - Top-3 Accuracy: 112 - Causal: 81.0% 113 - Baseline: 95.0% 114 - Threshold: 100.0% 115 - Improvement (Causal vs Baseline): -14.0% 116 - 117 - Mean Rank (lower is better): 118 - Causal: 1.98 119 - Baseline: 1.59 120 - Threshold: 1.42 121 - Improvement (Causal vs Baseline): -0.39 122 - 123 - BREAKDOWN BY SCENARIO CATEGORY 124 - 125 - Single-fault (n=40): 126 - Causal top-1: 34/40 = 85% 127 - Baseline top-1: 38/40 = 95% 128 - Threshold top-1: 34/40 = 85% 129 - 130 - Two-fault (n=25): 131 - Causal top-1: 6/25 = 24% 132 - Baseline top-1: 6/25 = 24% 133 - Threshold top-1: 8/25 = 32% 134 - 135 - Triple-fault+noise (n=15): 136 - Causal top-1: 15/15 = 100% 137 - Baseline top-1: 9/15 = 60% 138 - Threshold top-1: 12/15 = 80% 139 - 140 - Sensor-dropout (n=10): 141 - Causal top-1: 10/10 = 100% 142 - Baseline top-1: 5/10 = 50% 143 - Threshold top-1: 7/10 = 70% 144 - 145 - Cascading-ambiguity (n=10): 146 - Causal top-1: 2/10 = 20% 147 - Baseline top-1: 3/10 = 30% 148 - Threshold top-1: 3/10 = 30% 149 - Professional comparison table saved to: docs/benchmark_results.png 150 - 151 - 152 - 153 - 154 - FAULT SEVERITY ANALYSIS: Solar Degradation 155 - 156 - Testing at 70% loss... 157 - 158 - Testing at 50% loss... 159 - 160 - Testing at 30% loss... 161 - 162 - Testing at 10% loss... 163 - 164 - Loss Causal Rank Correlation Rank Threshold Rank 165 - ------------------------------------------------------------ 166 - 70% 1.00 1.00 1.00 167 - 50% 1.00 1.00 1.00 168 - 30% 1.00 1.00 1.00 169 - 10% 1.00 1.00 1.00 170 - 171 - 172 - 173 - 174 - NOISE ROBUSTNESS ANALYSIS: Battery Heatsink Failure 175 - 176 - Testing with 0% noise... 177 - 178 - Testing with 5% noise... 179 - 180 - Testing with 10% noise... 181 - 182 - Testing with 20% noise... 183 - 184 - Noise Causal Rank Correlation Rank Threshold Rank 185 - ------------------------------------------------------------ 186 - 0.0% 1.00 1.00 1.00 187 - 5.0% 1.00 1.00 1.00 188 - 10.0% 1.00 1.00 1.00 189 - 20.0% 1.00 1.00 1.00 190 - 191 - 192 - 193 - 194 - CONFIDENCE CALIBRATION CURVE 195 - 196 - Confidence Bin Mean Conf Actual Acc Samples 197 - -------------------------------------------------- 198 - 0.0-0.2 N/A N/A 0 199 - 0.2-0.4 N/A N/A 0 200 - 0.4-0.6 N/A N/A 0 201 - 0.6-0.8 69.5% 67.7% 164 202 - 0.8-1.0 81.5% 100.0% 40 203 - 204 - Note: good calibration means Mean Conf ≈ Actual Acc in each bin.
-26
docs/leadtime_results.txt
··· 1 - Detection Lead-Time Benchmark 2 - Fault type: Solar degradation (15%–40%) 3 - Fault onset: T = 6h 4 - Scenarios: 50 | Seed: 42 5 - Aethelix confidence threshold: 40.0% 6 - OOL threshold: 15% deviation 7 - 8 - ============================================================ 9 - DETECTION LEAD-TIME RESULTS 10 - ============================================================ 11 - Scenarios run: 50 12 - Aethelix detected: 29 13 - Threshold fired: 50 14 - Threshold-only misses: 0 (severity too mild) 15 - 16 - Lead-time statistics (Aethelix vs OOL threshold): 17 - Mean lead time: +0.0 s 18 - Median lead time: +0.0 s 19 - 75th percentile: +0.0 s 20 - Scenarios Aethelix faster: 0/29 21 - 22 - Published comparisons: 23 - LSTM Telemanom lead time: ~+10 to +20 s (requires training) 24 - OOL threshold lead time: 0 s (baseline) 25 - Aethelix lead time: +0.0 s (zero training) 26 - ============================================================
-37
docs/nasa_benchmark_results.txt
··· 1 - NASA SMAP/MSL Benchmark — 82 channels 2 - Evaluation: sequence-level Precision / Recall / F1 3 - 4 - [ 0/82] P-1 — TP=3/3 FP_events=4 5 - [ 10/82] E-9 — TP=1/1 FP_events=2 6 - [ 20/82] D-3 — TP=1/1 FP_events=2 7 - [ 30/82] F-1 — TP=1/1 FP_events=2 8 - [ 40/82] D-11 — TP=1/1 FP_events=2 9 - [ 50/82] D-13 — TP=1/1 FP_events=1 10 - [ 60/82] T-4 — TP=0/1 FP_events=0 11 - [ 70/82] T-13 — TP=2/2 FP_events=3 12 - [ 80/82] M-7 — TP=1/1 FP_events=3 13 - 14 - ============================================================ 15 - FINAL NASA SMAP/MSL BENCHMARK RESULTS 16 - ============================================================ 17 - Total channels evaluated: 82 18 - Total labelled sequences: 105 19 - True Positives (seqs): 89 20 - False Negatives (seqs): 16 21 - False Positive events: 121 (1.5/channel) 22 - 23 - Metric Aethelix LSTM (trained) Threshold 24 - -------------------------------------------------------------------- 25 - Precision 42.4% 85.1% 28.0% 26 - Recall 84.8% 85.3% 53.0% 27 - F1 Score 56.5% 85.2% 37.0% 28 - FP events / channel 1.5 N/A (trained) ~High 29 - Training required None Days–weeks None 30 - Explainability Causal paths None Alert only 31 - ============================================================ 32 - 33 - NOTE: LSTM baseline (Telemanom) requires days of training data and 34 - produces no causal explanation. Aethelix is zero-shot. 35 - Aethelix's primary advantage is explainability + zero training, 36 - not raw F1 on this benchmark (which is LSTM's home turf). 37 - ============================================================
docs/subthreshold_results.txt

This is a binary file and will not be displayed.

-24
nasa_results.txt
··· 1 - --- Running NASA SMAP/MSL Benchmark (82 channels) --- 2 - Processed 0/82: P-1 (Detected 3/3) 3 - Processed 10/82: E-9 (Detected 1/1) 4 - Processed 20/82: D-3 (Detected 1/1) 5 - Processed 30/82: F-1 (Detected 1/1) 6 - Processed 40/82: D-11 (Detected 1/1) 7 - Processed 50/82: D-13 (Detected 1/1) 8 - Processed 60/82: T-4 (Detected 1/1) 9 - Processed 70/82: T-13 (Detected 2/2) 10 - Processed 80/82: M-7 (Detected 1/1) 11 - 12 - ================================================== 13 - FINAL NASA BENCHMARK RESULTS 14 - ================================================== 15 - Total Channels: 82 16 - Total Anomalies: 105 17 - Detected: 105 18 - Detection Rate: 100.0% 19 - False Positive Rate: 2103.3 per channel 20 - 21 - Comparison with NASA Telemanom LSTM baseline: 22 - - LSTM (Telemanom): ~85% (Requires Training) 23 - - Aethelix Causal: 100.0% (Zero-Shot / No Training) 24 - ==================================================
+22 -5
operational/anomaly_detector.py
··· 18 18 19 19 import numpy as np 20 20 from collections import deque 21 - from typing import Dict 22 - from scipy.stats import ks_2samp 21 + from typing import Dict, Tuple 23 22 23 + def fast_ks_2samp(data1: np.ndarray, data2: np.ndarray) -> Tuple[float, float]: 24 + """ 25 + Sub-millisecond Kolmogorov-Smirnov test algorithm. 26 + Optimized for anomaly detection streaming where arrays are small. 27 + """ 28 + data1 = np.sort(data1) 29 + data2 = np.sort(data2) 30 + n1 = len(data1) 31 + n2 = len(data2) 32 + data_all = np.concatenate([data1, data2]) 33 + cdf1 = np.searchsorted(data1, data_all, side='right') / n1 34 + cdf2 = np.searchsorted(data2, data_all, side='right') / n2 35 + d = np.max(np.abs(cdf1 - cdf2)) 36 + 37 + en = np.sqrt(n1 * n2 / (n1 + n2)) 38 + # Asymptotic approximation of the true KS p-value formula 39 + pval = 2 * np.exp(-2.0 * (en * d) ** 2) 40 + return d, min(float(pval), 1.0) 24 41 25 42 class SlidingWindowDetector: 26 43 """ ··· 123 140 cur_q = self.cur_windows[key] 124 141 ref_q = self.ref_windows[key] 125 142 126 - # --- Anomaly test --- 143 + # Anomaly test 127 144 if len(cur_q) >= self.window_size and len(ref_q) >= 20: 128 - # Primary: KS distribution-shift test 129 - _, pval = ks_2samp(list(ref_q), list(cur_q)) 145 + # Primary: Fast KS distribution-shift test 146 + _, pval = fast_ks_2samp(list(ref_q), list(cur_q)) 130 147 is_anomalous = pval < self.p_threshold 131 148 132 149 if not is_anomalous:
profile.txt

This is a binary file and will not be displayed.

+1 -1
scripts/benchmark.py
··· 619 619 620 620 print("\nNote: good calibration means Mean Conf ≈ Actual Acc in each bin.") 621 621 622 - # ── convenience: cause_to_kwargs (static alias for calibration) ──── 622 + # convenience: cause_to_kwargs (static alias for calibration) 623 623 @staticmethod 624 624 def _cause_to_kwargs(cause: str, severity: float) -> dict: 625 625 if cause == "solar_degradation":
+2 -3
scripts/nasa_benchmark.py
··· 7 7 Telemanom LSTM paper so results are directly comparable. 8 8 9 9 Evaluation Protocol (sequence-level, industry standard) 10 - -------------------------------------------------------- 10 + 11 11 - True Positive (TP): at least one alarm fires inside an anomaly window. 12 12 - False Positive (FP): an alarm fires with no overlap to any anomaly window. 13 13 Consecutive alarms in the same non-anomaly region count as ONE FP event. ··· 33 33 DATA_DIR = "smap&msl_dataset/data/data/test" 34 34 LABELS_PATH = "smap&msl_dataset/labeled_anomalies.csv" 35 35 36 - # ── Baselines from published literature ───────────────────────────────────── 36 + # Baselines from published literature 37 37 LSTM_PRECISION = 0.851 38 38 LSTM_RECALL = 0.853 39 39 LSTM_F1 = 0.852 ··· 119 119 print(f" [{idx:3d}/{len(labels_df)}] {chan_id} — " 120 120 f"TP={chan_tp}/{len(anomaly_seqs)} FP_events={chan_fp}") 121 121 122 - # ── Metrics ───────────────────────────────────────────────────────────── 123 122 precision = tp_seqs / (tp_seqs + fp_events) if (tp_seqs + fp_events) > 0 else 0.0 124 123 recall = tp_seqs / total_seqs if total_seqs > 0 else 0.0 125 124 f1 = (2 * precision * recall / (precision + recall)
+3 -5
scripts/streaming_benchmark.py
··· 5 5 fixed-threshold alarm system for solar degradation faults. 6 6 7 7 Lead-Time Definition 8 - -------------------- 8 + 9 9 Lead time = t_threshold_alarm – t_aethelix_detection 10 10 11 11 Where: ··· 19 19 (lead time = undefined / +∞ advantage). 20 20 21 21 Methodology 22 - ----------- 22 + 23 23 50 scenarios (seed=42), solar degradation 15–40% injected at T=6h. 24 24 Each sample is 10 seconds (0.1 Hz). Results in seconds. 25 25 """ ··· 100 100 if deviation > THRESHOLD_FRACTION: 101 101 t_threshold = t 102 102 103 - # Aethelix detection 104 103 if t_aethelix is None: 105 104 tick = { 106 105 "solar_input" : solar_val, ··· 127 126 aethelix_miss += 1 128 127 lead_s = None 129 128 elif t_threshold is None: 130 - # Threshold never fired — Aethelix-only detection (infinite advantage) 131 129 threshold_miss += 1 132 130 lead_s = None # handled separately 133 131 else: 134 132 lead_s = (t_threshold - t_aethelix) * dt_per_sample 135 133 lead_times_s.append(lead_s) 136 134 137 - # ── Summary ───────────────────────────────────────────────────────────── 135 + 138 136 if lead_times_s: 139 137 mean_lead = np.mean(lead_times_s) 140 138 median_lead = np.median(lead_times_s)
+3 -3
scripts/subthreshold_benchmark.py
··· 2 2 Sub-threshold fault detection benchmark. 3 3 4 4 Evaluates Aethelix's ability to detect faults below the operational 15% alarm 5 - threshold — the regime where traditional alarm systems fail by design. 5 + threshold - the regime where traditional alarm systems fail by design. 6 6 7 7 Fault Severity Range: 5–12% degradation of solar input power. 8 8 - Traditional threshold alarm: 0% detection (misses by design). ··· 10 10 - Aethelix causal: see measured result below. 11 11 12 12 Methodology 13 - ----------- 13 + 14 14 100 reproducible scenarios (seed=42) injected at T+6h with solar degradation 15 15 drawn from Uniform(0.05, 0.12). Detection is confirmed when Aethelix produces 16 16 a hypothesis with confidence ≥ 40% (meaningful, not trivial) for ··· 100 100 print(f" Scenario {i+1:3d}/{num_scenarios} | " 101 101 f"Detected so far: {detected_count}") 102 102 103 - # ── False-positive rate (clean data) ──────────────────────────────────── 103 + # False-positive rate (clean data) 104 104 fp_count = 0 105 105 for _ in range(30): 106 106 sim = PowerSimulator(duration_hours=24, sampling_rate_hz=0.1)
-16
subthreshold_results.txt
··· 1 - --- Running Sub-threshold Benchmark (50 scenarios) --- 2 - Operational Threshold: 15.0% 3 - Scenario 10/50 processed. 4 - Scenario 20/50 processed. 5 - Scenario 30/50 processed. 6 - Scenario 40/50 processed. 7 - Scenario 50/50 processed. 8 - 9 - ================================================== 10 - SUB-THRESHOLD BENCHMARK RESULTS 11 - ================================================== 12 - Fault Severity Range: 5.0% - 12.0% 13 - Fixed Threshold (15%): 0.0% Detection 14 - Aethelix Causal Logic: 100.0% Detection 15 - Gap (Headline Value): +100.0% 16 - ==================================================