Skip to main content

Battery Life Estimation: From mAh to Real-World Runtime

11 min read
ElectricalBatteryIoTEngineeringReference

An ESP32 sensor node with a 2,000 mAh lithium cell should last 12.5 hours at 160 mA continuous draw. Simple division: 2,000 / 160 = 12.5. But flash the radio for 2 seconds every minute and sleep the rest, and that same battery stretches past two weeks. The difference between 12.5 hours and 15+ days comes down to duty cycle math that most datasheets never spell out.

Battery life estimation sounds trivial. Divide capacity by current, get hours. In practice, six factors conspire to make the naive answer wrong: duty cycle, depth of discharge, self-discharge, the Peukert effect, temperature, and battery aging. This guide walks through each one with numbers.

The Naive Formula

The starting point for any battery life calculation:

Runtime (hours) = Capacity (mAh) / Load current (mA)

A 3,000 mAh phone battery powering a 500 mA average load: 3,000 / 500 = 6 hours. That matches real-world experience for continuous screen-on use, which is why the formula feels right.

It breaks down the moment any of these assumptions fail:

  • The load is not constant (it almost never is)
  • The battery cannot be drained to 0% (chemistry-dependent cutoffs apply)
  • High current draws reduce effective capacity (Peukert effect)
  • Cold temperatures shrink available capacity
  • Self-discharge eats charge even with no load

The naive formula is the ceiling. Every real-world factor pushes runtime lower.

mAh vs Wh: The Comparison Trap

Milliamp-hours (mAh) measure electric charge. Watt-hours (Wh) measure energy. They are not interchangeable unless you specify the voltage.

Wh = mAh x V / 1000

A 3,000 mAh lithium cell at 3.7 V stores 11.1 Wh of energy. A 3,000 mAh NiMH AA cell at 1.2 V stores only 3.6 Wh. Same mAh, one-third the energy. Marketing departments love mAh because the number is bigger, but energy content is what determines runtime when comparing across voltages.

This matters most when comparing:

  • Lithium-ion (3.7 V) vs NiMH (1.2 V): A 2,000 mAh Li-ion pack replaces three series NiMH cells at 2,000 mAh. The Li-ion stores 7.4 Wh; the NiMH pack stores 7.2 Wh (3 x 1.2 V x 2,000 mAh / 1000). Roughly equivalent energy despite identical mAh ratings, but only because the NiMH cells are in series tripling the voltage.
  • Power banks: A "20,000 mAh" power bank at its internal 3.7 V cell voltage stores 74 Wh. Charging a phone at 5 V USB, the usable capacity drops to about 14,800 mAh (74 Wh / 5 V x 1000) before accounting for conversion losses. At ~90% converter efficiency, expect ~13,300 mAh at 5 V output.

The battery life calculator accepts both mAh and Wh inputs and converts between them using the nominal voltage you specify. Watt-hours are also the quantity used in the FAA passenger-battery rules, which is a useful independent check on the relationship Wh = V ร— Ah.

Duty Cycle: Where the Real Gains Live

Most battery-powered devices alternate between active and sleep states. The average current, not the peak current, determines battery life:

I_avg = (I_active x t_active + I_sleep x t_sleep) / (t_active + t_sleep)

Worked example: LoRa environmental sensor

An ESP32 with a BME280 sensor and LoRa radio. It wakes every 5 minutes, reads the sensor, transmits a packet, and goes back to deep sleep.

ModeCurrentDuration
Active (sensor read + LoRa TX)120 mA3 seconds
Deep sleep10 uA (0.01 mA)297 seconds
I_avg = (120 x 3 + 0.01 x 297) / 300
I_avg = (360 + 2.97) / 300
I_avg = 1.21 mA

With a 3,000 mAh LiPo cell:

  • Naive (continuous active): 3,000 / 120 = 25 hours
  • With duty cycle: 3,000 / 1.21 = 2,479 hours = 103 days

The 99:1 sleep-to-active ratio transforms a one-day battery into a three-month one. This is why IoT power budgeting obsesses over sleep current. The 10 uA sleep current contributes 2.97 mA-seconds per cycle, which is less than 1% of the per-cycle energy. But if deep sleep current were 1 mA instead of 10 uA (a common mistake when forgetting to disable unused peripherals), I_avg jumps to 2.19 mA, cutting runtime from 103 days to 57.

Verify your duty cycle numbers with the battery life calculator.

The Peukert Effect: Lead-Acid's Hidden Tax

In 1897, German scientist Wilhelm Peukert documented that lead-acid batteries deliver less total charge at higher discharge rates. A 100 Ah battery rated at the C/20 rate (5 A for 20 hours) might deliver only 87 Ah when discharged at 10 A.

The relationship follows a power law:

t = H x (C / (I x H))^k

Where:

  • t = actual runtime in hours
  • H = rated discharge time (hours), typically 20 for lead-acid
  • C = rated capacity (Ah) at the H-hour rate
  • I = actual discharge current (A)
  • k = Peukert exponent (dimensionless, always >= 1)

For a duty-cycled load, do not put the arithmetic average current into the nonlinear Peukert term. The calculator weights the states as D ร— I_active^k + (1 - D) ร— I_standby^k, so a short high-current pulse consumes more of the Peukert budget than its average current alone suggests. When a load sits behind a converter, the calculator divides each load current by conversion efficiency before applying the exponent.

The exponent is battery-specific, not a chemistry lookup value. Victron's Peukert documentation defines 1.00 as ideal and describes 1.25 as an acceptable default average for many lead-acid batteries. A manufacturer datasheet or a value calculated from two rated discharge tests is better than either default. Leave the exponent at 1.00 when you do not have a supported value.

Worked example: golf cart battery

A 225 Ah flooded lead-acid battery (rated at C/20 = 11.25 A, k = 1.25) powering a motor drawing 50 A:

t = 20 x (225 / (50 x 20))^1.25
t = 20 x (225 / 1000)^1.25
t = 20 x (0.225)^1.25
t = 20 x 0.155
t = 3.10 hours

The naive calculation gives 225 / 50 = 4.5 hours. The Peukert correction reveals you actually get 3.10 hours, a 31% reduction. At the rated 11.25 A, the formula returns the full 20 hours. The penalty grows sharply with discharge rate.

The Calcflux battery life calculator includes optional fields for the Peukert exponent and rated capacity period. Set the exponent to 1.00 for the simple model. To apply the correction, enter both battery-specific values from the manufacturer.

The Derating Stack

Five factors reduce real-world runtime below the theoretical maximum. Apply them multiplicatively:

Runtime_real = Runtime_naive x DoD x (1 - self_discharge) x temp_factor x age_factor

Depth of Discharge (DoD)

Depth of discharge is a design input, not a universal chemistry constant. The usable limit depends on the cell datasheet, battery-management cutoff, warranty conditions, and cycle-life target. If a 100 Ah system is intended to use only 50 Ah before shutdown, enter 50% DoD. Do not hide that choice inside a generic efficiency value.

Self-Discharge

Every battery loses charge while sitting idle, but the rate varies widely with product, age, state of charge, and temperature. Use the storage-retention data for the exact cell rather than a chemistry-wide percentage. For long deployments, convert the datasheet loss over the planned period into an explicit capacity reduction and record that assumption outside the calculator.

Temperature Derating

Temperature changes usable capacity, internal resistance, and cutoff behavior. The result depends on chemistry, discharge rate, and the equipment's minimum voltage. Read the capacity-versus-temperature curve for the exact cell and enter its remaining-capacity ratio in the calculator's temperature factor. Design against the coldest expected operating condition, not a room-temperature label.

Battery Aging

Calendar time and cycling both reduce usable capacity, but the curve is product-specific. For an older pack, use a measured current capacity or the manufacturer's warranted end-of-life capacity instead of the original label.

Putting It All Together: Worked Example

Illustrative scenario: A LoRa temperature sensor deployed outdoors in the northeastern US. Operating temperature range: -10 C winter to 35 C summer. 3,000 mAh 3.7 V LiPo cell. Duty cycle from the earlier example: I_avg = 1.21 mA. The derating percentages below are example assumptions, not defaults; replace them with the cell's datasheet values.

Step 1. Naive runtime: 3,000 / 1.21 = 2,479 hours (103 days).

Step 2. Apply DoD (85% usable for Li-ion with BMS): 2,479 x 0.85 = 2,107 hours (88 days).

Step 3. Apply self-discharge (3% per month over ~3 months): roughly 9% total loss. 2,107 x 0.91 = 1,917 hours (80 days).

Step 4. Apply winter temperature derating (70% capacity at -10 C worst case). For a year-round deployment, use an average derating of 85%: 1,917 x 0.85 = 1,630 hours (68 days).

Step 5. Realistic runtime: ~68 days. The naive formula predicted 103. That is a 34% reduction from the stack of real-world factors.

For a 12-month deployment target, you would need a battery roughly 5.3x larger: 16,000 mAh. Or redesign the duty cycle to reduce I_avg. Extending the sleep interval from 5 minutes to 15 minutes drops I_avg to 0.41 mA, pushing the derated runtime past 200 days on the original 3,000 mAh cell.

Common Mistakes

Using mAh to compare batteries at different voltages. A 10,000 mAh USB power bank (3.7 V internal) stores 37 Wh. A 10,000 mAh 12 V lead-acid battery stores 120 Wh. The lead-acid pack holds over 3x the energy despite the same mAh headline number. Always compare in Wh.

Ignoring sleep current. An ESP32 module with WiFi disabled but the radio modem still powered draws 20 mA, not the 10 uA deep-sleep figure from the datasheet. Unused peripherals (GPS modules, LoRa radios, sensors) often have their own quiescent current that persists unless explicitly powered down via a MOSFET switch or regulator enable pin. Measure sleep current with a uA-resolution meter before trusting datasheet figures.

Treating rated capacity as usable capacity. A "100 Ah" lead-acid deep-cycle battery usable to 50% DoD provides 50 Ah. Designing for 100 Ah will either damage the battery or trigger the low-voltage cutoff well before the expected runtime.

Forgetting the voltage regulator. A 3.7 V LiPo feeding a 3.3 V LDO regulator wastes (3.7 - 3.3) / 3.7 = 10.8% of battery energy as heat in the regulator. A switching regulator at 90 to 95% efficiency reclaims most of that loss. Over a multi-month deployment, regulator efficiency compounds into weeks of difference.

Assuming linear discharge. Battery voltage drops as the cell discharges. A load that draws constant power (not constant current) draws increasing current as voltage sags, accelerating the discharge curve. Size for the highest current at the lowest expected voltage, not the nominal midpoint.

Use the CalcFlux battery life calculator to run these numbers, and the electrical power calculator to convert between watts, volts, and amps for your power budget.