CellTriage / configs /features.yaml
Sarvarbek13's picture
CellTriage QC operator console - inference only, CPU-bound classical ML
749bffa verified
Raw
History Blame Contribute Delete
6.85 kB
# ---------------------------------------------------------------------------
# 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"