intermediate
SoH
battery
state-of-health

Battery State of Health (SoH)

How Levy Fleets calculates per-pack State of Health using OEM telemetry — EFC, capacity fade, temperature exposure, internal resistance proxy, and the Levy SoH index

Levy Fleets TeamMay 18, 20269 min read

Battery State of Health (SoH)

State of Health is the answer to "how much useful life does this pack have left?" State of Charge tells you what's in the tank right now; SoH tells you whether the tank itself is shrinking.

Levy Swap calculates SoH for every deployed pack nightly. The result is a single dashboard-facing number between 0 and 100, plus the individual signals that produced it.

The Levy SoH Index

SoH RangeWhat It MeansRecommended Action
90 – 100New or near-newUse anywhere; ignore
75 – 89HealthyUse anywhere; keep an eye on temperature exposure
60 – 74AgingRotate into lower-demand vehicles
40 – 59End-of-life warningRetire from high-mileage vehicles; plan replacement
Below 40Forced retirementPack is automatically flagged for retirement on the next swap

The index is a weighted blend of the signals below. No single signal can push a pack to retirement on its own — but combined, they catch packs that look fine on a single dimension and rotten on another.

What Goes Into the Index

1. Equivalent Full Cycles (EFC)

Cumulative depth-of-discharge expressed as the equivalent number of full charge/discharge cycles. Two 50% discharges count as one EFC. This is the cleanest "how worked has this pack been?" signal and is comparable across vehicle types and ride patterns.

EFC is computed from the long-running SoC telemetry stream — every drop in battery_level is treated as a partial discharge and accumulated. The job is idempotent: re-running it doesn't double-count.

2. Capacity Fade Percentage

Derived from voltage-under-known-load measurements. Each vehicle model has a rated voltage (stored on the vehicle_model), and the nightly job compares observed voltage at low-load conditions to the rated baseline. A pack that consistently sags below its rated voltage at rest is losing usable capacity.

This is the most chemistry-sensitive signal — LFP packs hold flat for most of their life and fall off a cliff; NMC packs decline more linearly. The model accounts for the chemistry stored on the pack row.

3. Temperature Exposure Score

Two accumulators are tracked per pack:

  • Hot minutes — minutes spent above 45 °C battery temperature
  • Cold minutes — minutes spent below 0 °C battery temperature

Both are weighted heavily in the SoH formula because both materially accelerate fade. A pack that lives in a summer-Phoenix garage with no cooling will degrade roughly twice as fast as the same pack in a temperate-climate operator's storage.

4. Internal Resistance Proxy

Lithium packs increase their internal resistance as they age, and the symptom is voltage sag under load. The SoH engine correlates concurrent telemetry — voltage drops while the vehicle is being ridden hard (speed up, current up) — to estimate this resistance growth without firmware-level access.

5. EoL Prediction (End-of-Life Date)

Once a pack has at least 30 days of data, the engine does a linear extrapolation of the fade rate to project when SoH will cross 40 (forced retirement). The output is a predicted date with a confidence interval. Use this for ordering replacement packs ahead of time, not as a hard deadline.

Supported IoT Types and Confidence Weights

SoH quality depends on the telemetry fidelity of the underlying IoT type. Each OEM contributes data weighted by a confidence factor — the lower the weight, the more conservative the SoH score (we don't punish a pack for thin data, but we also don't claim high confidence in it).

OEM / IoT TypeConfidence WeightNotes
OKAI1.0Most fields; cleanest voltage + temperature stream
Segway0.9Full coverage; current draw available
Omni 4G0.85Voltage + temperature; some packets sparse
Queclink (ZK600 / ZK105L)0.8Reliable voltage; temperature gaps possible
Acton / Feishen / Physhen0.7Lower-frequency packets; H0 mapping varies
Zimo0.5MQTT-only payload; fewer fields, longer SoH "warmup"
AXA / Manualn/aNo live telemetry — SoH shows "n/a"

If a vehicle's IoT type isn't in this list, the pack still has a row but the index is blank and the Battery Health page shows "n/a" with the IoT-type reason.

Where to See SoH in the Dashboard

  • Dashboard → Swap → Battery Health — fleet-wide leaderboard, filterable by SoH band, EoL window, or rotation flag
  • Per-pack drill-down — click any pack to see its voltage curve, hot/cold minute history, swap history, and projected EoL
  • Per-vehicle detail — the assigned pack's SoH appears on each vehicle's detail page

When SoH Triggers Action

  • SoH below 60 raises a "rotation recommended" flag, which surfaces the vehicle on the operator-app Swap Queue with a non-SoC reason.
  • SoH below 40 flags the pack for retirement; the next swap completes the pack into the returned state instead of going back into station inventory.
  • EoL within 30 days appears in the Battery Health summary cards so you can place replacement orders ahead of the cliff.

What SoH Does Not Do

  • It does not require new hardware. We use existing OEM telemetry only.
  • It does not flash battery BMS firmware.
  • It is not a capacity test — a lab-grade discharge test is more accurate, but impractical at fleet scale. SoH is a continuous proxy that's been validated to within roughly ±10% MAE on 30-day-ahead capacity prediction across the supported OEM matrix.

Troubleshooting SoH

See Troubleshooting for the most common SoH issues — packs stuck "warming up," sudden drops after a firmware update, and discrepancies between SoH and observed range.