DEV Community

曾小旭
曾小旭

Posted on

The battery sizing formula is right about 80% of the time — and wrong in ways that matter

true description: "Why most LiFePO4 sizing calculators give you a number you can't ship, and the three corrections that fix it." tags: energy, solar, batteries, opensource, sustainability cover_image: https://jackzx71.github.io/bess-sizing-toolkit/demo/
Every battery sizing guide gives you the same formula:

kWh = load (kW) × hours ÷ efficiency ÷ depth of discharge
That math is not wrong. It's just incomplete in three specific ways, and each gap ends up costing you money — either in undersized systems or in quotes that can't be delivered.

Correction 1 — Depth of discharge depends on chemistry, not on optimism
LFP can be sized at 80% depth of discharge. Lead-acid should stay at 50%.

Running lead-acid at 80% doesn't just reduce usable capacity, it roughly halves cycle life. The battery still meets its spec sheet on day one. You find out in year three.

Same nameplate, same 26 kWh, 1.6× difference in usable energy depending on chemistry.

Correction 2 — Capacity moves away from rated temperature
Below roughly 10 °C, usable capacity falls. Below −20 °C it falls hard. Below about 35 °C, LFP capacity falls too — which matters more in the Middle East than cold climate derating does in northern Europe.

If a sizing calculation doesn't have a temperature step in it, it's incomplete. An "8-hour backup battery" at 25 °C is not an 8-hour battery at −20 °C.

Correction 3 — The answer needs to be a buildable size
Worked example: 5 kW load, 4 hours backup, 95% efficiency, 80% DoD.

5 × 4 ÷ 0.95 ÷ 0.80 = 26.32 kWh
26.32 kWh is a calculation. The next size you can actually ship might be 30 kWh. The inverter at 1.2× continuous load is 6 kW.

Quoting 26.32 kWh in a proposal means the installer has to round it themselves — and they usually round down, or they have to order a custom configuration that costs three weeks.

What I built
I put these three corrections into a small dependency-free library, mostly because I kept re-deriving them in spreadsheets:

bash
复制
npm install bess-sizing-toolkit
js
复制
const BESS = require("bess-sizing-toolkit");

BESS.sizeBatteryCapacity({
loadKw: 5,
backupHours: 4,
efficiency: 0.95,
dod: 0.8,
temperatureFactor: 0.85 // cold site
});
// {
// nominalKwh: 26.32,
// deratedKwh: 30.96, // after the cold derate
// buildableKwh: 35, // rounded to a real module size
// inverterKw: 6,
// steps: [...], // every intermediate value + the formula
// warnings: [...] // chemistry / derate / rounding sanity checks
// }
The part I'd point at first is steps. Most calculators return a single number, which makes it impossible for an engineer or a customer to check your arithmetic. This one returns every intermediate value with the formula used, so the number can be defended — or refuted — in a meeting.

It also covers solar yield (performance ratio, degradation, self-consumption value), C&I storage payback from a peak-valley tariff spread, and a small rule of thumb for deciding whether storage is even warranted: if daytime load ÷ annual PV generation is above 60%, batteries rarely pay for themselves.

16 tests, zero dependencies, runs in Node and the browser (MIT).

Live demo: https://jackzx71.github.io/bess-sizing-toolkit/demo/
Source and tests: https://github.com/jackzx71/bess-sizing-toolkit
npm: https://www.npmjs.com/package/bess-sizing-toolkit
The part I'm least sure about
The 0.85 temperature factor I used as a default is conservative and generic. Real derating depends on cell chemistry, enclosure, thermal management and how long the battery sits cold before discharge. If you have field measurements for a specific cell type and climate, that's the number I'd most like to replace.

Happy to be told the physics is wrong.

Top comments (0)