Battery Pack Optimizer Project Report
A practical Python GUI for grouping 18650 cells into balanced series/parallel packs using capacity, DCIR, and voltage safety checks.
Executive Summary
The application helps build safer and better balanced battery packs by assigning cells into series groups with parallel slots. It validates spreadsheet data, selects the best cells when extras are available, optimizes group balance, checks parallel voltage spread, visualizes the final layout, and exports a formatted workbook.
- Similar group capacity
- Similar parallel DCIR
- Safe voltage spread inside each parallel group
- Good: ≤ 0.02 V
- Acceptable: ≤ 0.05 V
- Warning: > 0.05 V
- Unsafe: > 0.10 V
- Pack summary
- Visual layout
- Grouped cells table
- Excel export with safety colors
Inputs
The app expects an Excel sheet with measured cell data. Voltage is now part of the expected input because it matters before cells are physically connected in parallel.
Cell IDModelCapacity (mAh)DCIR (mΩ)Voltage (V)
- Pack configuration, such as
10S4P - Nominal and full cell voltage
- Capacity, DCIR, and voltage weights
- Max allowed parallel voltage spread
- Unsafe voltage spread threshold
How the Optimizer Works
The optimizer starts from a reasonable first layout, then repeatedly swaps cells between groups to reduce the pack score.
Parallel cell capacities are summed within each series group. The optimizer tries to make those group totals similar.
group_capacity = sum(cell capacities) capacity_score = std(group_capacities) / mean(group_capacities)Cells in parallel behave like resistors in parallel, so group DCIR is calculated using reciprocal resistance.
group_DCIR = 1 / sum(1 / cell_DCIR) dcir_score = std(group_DCIRs) / mean(group_DCIRs)Voltage is treated differently from capacity and DCIR. Capacity/DCIR are balanced between series groups. Voltage spread is checked inside each parallel group, because cells connected in parallel must be close in voltage before connection.
group_voltage_spread = max(group voltages) minus min(group voltages)How the Score Is Calculated
The score is a single number that tells the optimizer how good a proposed pack layout is. A lower score is better. Each possible layout is judged by how evenly it distributes capacity, how evenly it distributes internal resistance, and whether any parallel group has a risky voltage spread.
First, the app adds the cell capacities inside each series group. It then compares those group totals. If one group has much less capacity than the others, that group will limit the whole pack, so the score goes up.
capacity_score = standard deviation of group capacities divided by average group capacityDCIR is calculated as parallel resistance inside each group. Groups with higher resistance sag more under load and heat more, so the optimizer tries to keep group resistance values close together.
dcir_score = standard deviation of group DCIR values divided by average group DCIRVoltage is handled as a safety check inside each parallel group. Small spreads are allowed, but larger spreads add a penalty because cells at different voltages can drive equalization current into each other when connected.
- Up to 0.02 V adds no penalty
- 0.02 to 0.05 V adds a small penalty
- Above 0.05 V adds a strong penalty
- Above 0.10 V is treated as unsafe and flagged clearly
The final score combines the three parts using user selected weights. This lets the builder decide what matters most for a given pack, while still keeping voltage safety visible.
total_score = capacity_weight times capacity_score plus dcir_weight times dcir_score plus voltage_weight times voltage_penaltyThe score is mainly useful for comparing layouts from the same cell set and same settings. It is not a universal battery quality number. If the optimizer finds a lower score, it has found a layout with better balance or fewer voltage concerns under the chosen weights.
Voltage Safety Logic
The most important safety rule is not average voltage. It is the spread inside each parallel group. A high voltage cell connected directly in parallel with a lower voltage cell can push equalization current between cells, causing heat, sparks, cell stress, or damage.
≤ 0.02 V
≤ 0.05 V
> 0.05 V
> 0.10 V
The voltage logic was refined so safe voltage matching does not overpower the whole optimizer.
- ≤ 0.02 V: no voltage penalty
- 0.02 to 0.05 V: small nudge penalty
- > 0.05 V: strong penalty or rejection
- > 0.10 V: unsafe warning
Before physical assembly, cells should be balanced to approximately the same voltage, ideally within 0.02 to 0.05 V.
Outputs
- Pack summary with voltage safety recommendation
- Visual pack layout by series group and parallel slot
- Grouped cells table
- Group summary table
- Capacity, DCIR, and voltage spread charts
- Grouped Cells
- Group Summary
- Pack Summary
- Unused Cells
- Conditional formatting for voltage safety status
Challenges Faced During Development
The first version was functional but looked like a default desktop tool. The layout was redesigned with a clearer sidebar, better summary cards, stronger buttons, and cleaner charts.
The first visual pass was too tall for smaller screens. The sidebar was changed so settings scroll independently, while the Optimize button, status log, and progress bar remain pinned at the bottom.
The app originally optimized capacity and DCIR only. Voltage was added because cells connected in parallel need close voltages before assembly to reduce equalization current risk.
The first voltage scoring method penalized every tiny voltage spread. This caused the optimizer to lock onto the voltage sorted starting layout. The scoring was changed so ideal spreads have no penalty and voltage acts mainly as a safety guardrail.
Detailed optimizer diagnostics helped debug the algorithm, but they were too noisy for the status panel. The status panel now focuses on progress and final score, while detailed information remains in the summary/export path.