# --------------------------------------------------------------------------- # Product tiers for end-of-line grade assignment. # # Boundaries follow the binary split used in the source literature (550 cycles, # Severson et al. 2019) plus an upper automotive-qualification tier. # # RECOMPUTE the realised class balance from data and log it; do not assume. # Phase 3 must annotate the observed A/B/C counts on the cycle-life # distribution figure. If a tier turns out to be nearly empty, the boundary is # a modelling liability (a classifier cannot learn a class with five examples) # and must be revisited here rather than worked around downstream. # --------------------------------------------------------------------------- grades: A: {min_cycles: 1200, tier: "automotive traction pack"} B: {min_cycles: 550, tier: "stationary ESS / second tier"} C: {min_cycles: 0, tier: "scrap or non-critical"} # Minimum cycle life for any shipped application. A cell below this is not # saleable into either tier, so this coincides with the A/B/C floor at the # B boundary by construction. warranty_target_cycles: 550 # Ordering is load-bearing: it defines which off-diagonal cells of the cost # matrix are escapes (assigned tier more demanding than true grade) and which # are overkill. Listed most-demanding first. grade_order: [A, B, C] # Grades that constitute "shipped" product. Escape rate is defined over these # only: a cell scrapped as C cannot escape into the field by definition. shipped_grades: [A, B] labelling: # Cycle life is defined as the cycle at which discharge capacity first falls # below eol_capacity_fraction * nominal (see configs/data.yaml). Grades are # assigned by thresholding that observed value. # # Boundary handling: a cell with cycle life exactly equal to a boundary is # assigned to the HIGHER tier (>= comparison). Stated explicitly because an # off-by-one at the boundary silently moves cells between classes and would # make the class balance irreproducible. boundary_inclusive: true