Spaces:
Running on Zero
Running on Zero
| # --------------------------------------------------------------------------- | |
| # Feature engineering configuration (Phase 4 -- the scientific core). | |
| # | |
| # THE LEAKAGE RULE IS THE POINT OF THIS FILE. For budget N, features may use | |
| # ONLY cycles 1..N. src/features/builder.py slices the per-cell frame to | |
| # `cycle <= max_cycle` ONCE at the top and passes only that slice downstream; | |
| # no feature function ever receives the full frame. tests/test_leakage.py must | |
| # FAIL if shuffling cycles > N changes any feature value. | |
| # --------------------------------------------------------------------------- | |
| # Diagnostic budgets in cycles. Each is a distinct "how long do we hold the | |
| # cell in the chamber" operating point, and RQ1 is the trade-off curve across | |
| # them. | |
| budgets: [5, 10, 20, 50, 100] | |
| # The budget used for the Severson reproduction (Gate 2) and as the reference | |
| # operating point when a single budget must be quoted. | |
| reference_budget: 100 | |
| curve: | |
| # Common voltage grid for interpolating discharge capacity Q(V). | |
| # The discharge window is 3.5 V down to 2.0 V; interpolating onto a shared | |
| # grid is what makes Q(V) curves from different cycles subtractable. | |
| voltage_min_v: 2.0 | |
| voltage_max_v: 3.5 | |
| n_grid_points: 1000 | |
| # DeltaQ(V) = Q_late(V) - Q_early(V). The source result uses the (100, 10) | |
| # pair; for budgets below 100 the late cycle becomes the budget itself. | |
| baseline_cycle: 10 | |
| # For very small budgets the (late, early) pair must collapse to something | |
| # meaningful. Below this budget the baseline falls back to cycle 2. | |
| min_baseline_cycle: 2 | |
| interpolation: "linear" | |
| # --------------------------------------------------------------------------- | |
| # Feature groups. Each group is its own module with a documented rationale. | |
| # | |
| # `in_line_measurable` records whether a production line could actually obtain | |
| # this signal without extra equipment -- docs/02_feature_engineering.md must | |
| # group features by this flag, because a feature that is not measurable in-line | |
| # is not deployable in QC however predictive it is. | |
| # | |
| # `is_process_recipe` marks Group F. Results must be reported both WITH and | |
| # WITHOUT these for RQ4: a model that memorises recipe-to-lifetime mapping will | |
| # not generalise to a new recipe. | |
| # --------------------------------------------------------------------------- | |
| groups: | |
| A_curve: | |
| enabled: true | |
| module: "src.features.curve_features" | |
| in_line_measurable: true | |
| is_process_recipe: false | |
| rationale: >- | |
| DeltaQ(V) captures redistribution of accessible lithium inventory and | |
| active-material loss before bulk capacity fade is visible. Severson et al. | |
| showed log|var(DeltaQ)| alone explains most of the variance in log cycle | |
| life. | |
| B_degradation: | |
| enabled: true | |
| module: "src.features.degradation" | |
| in_line_measurable: true | |
| is_process_recipe: false | |
| rationale: "Early trajectory curvature reflects SEI growth rate." | |
| C_resistance: | |
| enabled: true | |
| module: "src.features.resistance" | |
| in_line_measurable: true | |
| is_process_recipe: false | |
| rationale: >- | |
| Low-SOC resistance is an established early-life diagnostic for lithium | |
| consumption during formation (Weng et al., 2022) and is measurable in-line | |
| without additional equipment, which matters for QC deployability. | |
| D_thermal: | |
| enabled: true | |
| module: "src.features.thermal" | |
| # Honest flag: per-cell temperature logging is standard in a research | |
| # cycler but is NOT universally instrumented per cell on a production line. | |
| # Treated as conditionally measurable and called out as such in docs/02. | |
| in_line_measurable: false | |
| is_process_recipe: false | |
| rationale: >- | |
| Arrhenius-accelerated side reactions; thermal exposure is a first-order | |
| driver of ageing. | |
| E_charge_dynamics: | |
| enabled: true | |
| module: "src.features.charge_dynamics" | |
| in_line_measurable: true | |
| is_process_recipe: false | |
| rationale: >- | |
| Rising charge time under a fixed protocol indicates growing polarization | |
| resistance. | |
| F_protocol: | |
| enabled: true | |
| module: "src.features.protocol" | |
| in_line_measurable: true | |
| is_process_recipe: true | |
| rationale: >- | |
| Parsed charging-policy parameters (step C-rates, switching SOC). In a | |
| factory these are KNOWN process settings, so using them is legitimate -- | |
| but every RQ4 result must be reported both with and without them. | |
| G_interactions: | |
| enabled: true | |
| module: "src.features.interactions" | |
| in_line_measurable: true | |
| is_process_recipe: false | |
| rationale: >- | |
| Products and ratios motivated by degradation physics (e.g. thermal | |
| exposure x resistance growth). Each interaction needs a one-line | |
| justification or it does not get built. | |
| # Ablation sets used throughout Phases 6-10. `no_recipe` is not optional | |
| # decoration: it is the RQ4 control. | |
| feature_sets: | |
| all: [A_curve, B_degradation, C_resistance, D_thermal, E_charge_dynamics, F_protocol, G_interactions] | |
| no_recipe: [A_curve, B_degradation, C_resistance, D_thermal, E_charge_dynamics, G_interactions] | |
| in_line_only: [A_curve, B_degradation, C_resistance, E_charge_dynamics, F_protocol, G_interactions] | |
| severson_reproduction: [A_curve, B_degradation, C_resistance] | |
| # --------------------------------------------------------------------------- | |
| # Feature selection. n is ~124-169 cells. Selecting on the full dataset is the | |
| # fastest way to manufacture a fake result, so selection is a STEP INSIDE an | |
| # sklearn Pipeline and is fitted within CV folds only. | |
| # --------------------------------------------------------------------------- | |
| selection: | |
| # Schema-enforced: src/utils/config.py rejects this config if the flag is | |
| # false. It exists so that turning selection into a full-data preprocessing | |
| # step requires deliberately defeating a validator. | |
| fit_inside_cv_only: true | |
| variance_threshold: 1.0e-8 | |
| # Drop one of any feature pair correlated above this. Curve features are | |
| # highly collinear by construction, which destabilises linear coefficients. | |
| correlation_threshold: 0.95 | |
| mutual_information: | |
| enabled: true | |
| n_neighbors: 3 | |
| stability_selection: | |
| enabled: true | |
| n_bootstrap: 100 | |
| sample_fraction: 0.75 | |
| # Retain a feature only if selected in at least this fraction of resamples. | |
| selection_frequency_threshold: 0.60 | |
| preprocessing: | |
| # Fitted inside folds only, same rule as selection. | |
| scaler: "standard" | |
| # Curve-derived quantities span orders of magnitude; log10|x| is applied | |
| # within the feature modules where the rationale is documented, not blindly. | |
| impute_strategy: "median" | |
| output: | |
| # One feature matrix per (budget, feature_set), written with the config hash | |
| # and package versions attached for provenance. | |
| directory: "data/processed" | |
| filename_template: "features_budget{budget:03d}.parquet" | |
| float_precision: "float64" | |