# --------------------------------------------------------------------------- # 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"