breos.polysun_degradation#

Polysun-style battery degradation model.

Implements the Wöhler curve + Miner’s linear damage accumulation methodology used by Polysun (Vela Solaris) for battery lifetime estimation. This serves as a comparison baseline against BREOS’s Naumann-based continuous degradation.

Polysun methodology:
  1. Cycle counting: 20 DOD histogram bins (equal width)

  2. Cycle life: Wöhler curve N(DOD) = a * DOD^(-b)

  3. Damage: Miner’s rule D = sum(n_i / N_i)

  4. Calendar life: Fixed (20 years for Li-ion)

  5. Total life: min(calendar_life, 1/D_annual)

  6. No temperature effects, no continuous SOH tracking

References

  • Polysun User Manual, Section “Battery Lifetime” (Vela Solaris AG)

  • Weniger et al., “Performance Model for PV-Battery Systems (PerMod)”, HTW Berlin, 2023

  • Palmgren-Miner linear damage hypothesis (Miner, 1945)

Functions

compute_dod_histogram(soc_series[, n_bins, ...])

Count cycles per DOD range from an SOC timeseries using peak detection.

compute_miner_damage(cycle_counts, ...)

Compute cumulative damage using Miner's linear damage rule.

predict_polysun_lifetime(annual_damage, ...)

Predict battery lifetime following Polysun methodology.

simulate_polysun_degradation(soc_series, config)

Run Polysun-style degradation over multiple years.

woehler_cycles_to_failure(dod, a, b)

Cycles to failure from Wöhler curve: N(DOD) = a * DOD^(-b).

Classes

PolysunDegradationConfig([woehler_a, ...])

Configuration for Polysun-style degradation model.

class breos.polysun_degradation.PolysunDegradationConfig(woehler_a=5000.0, woehler_b=1.6, calendar_life_years=20.0, n_bins=20, min_doc=0.01, deep_cycle_threshold=0.5)[source]#

Bases: object

Configuration for Polysun-style degradation model.

Parameters:
woehler_a#

Scale parameter for Wöhler curve N(DOD) = a * DOD^(-b). Equals cycles to failure at 100% DOD.

woehler_b#

Shape parameter for Wöhler curve. Higher b means deeper cycles are disproportionately more damaging.

calendar_life_years#

Fixed calendar lifetime in years.

n_bins#

Number of DOD histogram bins (Polysun uses 20).

min_doc#

Minimum DOD to count as a cycle (fraction, 0-1).

deep_cycle_threshold#

DOD above which a cycle is classified as “deep”.

breos.polysun_degradation.compute_dod_histogram(soc_series, n_bins=20, min_doc=0.01)[source]#

Count cycles per DOD range from an SOC timeseries using peak detection.

Uses simple local-extrema-based half-cycle detection to match Polysun’s approach (not rainflow counting). Half-cycles are paired and binned by DOD.

Parameters:
  • soc_series (ndarray) – SOC timeseries (0-1 range), typically one year of data.

  • n_bins (int) – Number of equal-width DOD bins (Polysun uses 20).

  • min_doc (float) – Minimum DOD to include a cycle (fraction, 0-1).

Returns:

bin_centers: DOD value at center of each bin (length n_bins). cycle_counts: Number of full cycles in each bin (length n_bins). total_cycles: Total number of cycles detected. deep_cycles: Number of deep cycles (DOD > deep_cycle_threshold).

Return type:

Tuple[ndarray, ndarray, int, int]

breos.polysun_degradation.compute_miner_damage(cycle_counts, bin_centers, woehler_a, woehler_b)[source]#

Compute cumulative damage using Miner’s linear damage rule.

D = sum(n_i / N_i) where n_i is the number of cycles at DOD_i and N_i = a * DOD_i^(-b) is the cycles to failure at that DOD.

Parameters:
  • cycle_counts (ndarray) – Number of cycles per DOD bin.

  • bin_centers (ndarray) – DOD value at center of each bin.

  • woehler_a (float) – Wöhler curve scale parameter.

  • woehler_b (float) – Wöhler curve shape exponent.

Return type:

float

Returns:

Cumulative damage fraction. D >= 1 means end of cycle life.

breos.polysun_degradation.predict_polysun_lifetime(annual_damage, calendar_life_years)[source]#

Predict battery lifetime following Polysun methodology.

Total life = min(calendar_life, cycle_life) where cycle_life = 1 / annual_damage.

Parameters:
  • annual_damage (float) – Miner’s damage per year (D_annual).

  • calendar_life_years (float) – Fixed calendar lifetime in years.

Return type:

Tuple[float, float, float]

Returns:

Tuple of (total_life, cycle_life, calendar_life) in years.

breos.polysun_degradation.simulate_polysun_degradation(soc_series, config, n_years=20)[source]#

Run Polysun-style degradation over multiple years.

Polysun assumes constant annual usage (same SOC profile each year) and does not feed degradation back into the energy balance. Damage accumulates linearly; when cumulative damage >= 1, the battery is replaced.

Parameters:
  • soc_series (ndarray) – One year of SOC data (0-1 range). Reused each year.

  • config (PolysunDegradationConfig) – Polysun degradation configuration.

  • n_years (int) – Number of years to simulate.

Returns:

Year, Damage_Annual, Damage_Cumulative, Cycle_Life_Years, Total_Life_Years, Replacement, SOH_Equivalent, Total_Cycles, Deep_Cycles.

Return type:

DataFrame

breos.polysun_degradation.woehler_cycles_to_failure(dod, a, b)[source]#

Cycles to failure from Wöhler curve: N(DOD) = a * DOD^(-b).

Parameters:
  • dod (float) – Depth of discharge (fraction, 0-1). Must be > 0.

  • a (float) – Scale parameter (cycles to failure at DOD=1.0).

  • b (float) – Shape exponent (steepness of DOD sensitivity).

Return type:

float

Returns:

Number of cycles to failure at the given DOD.