---
title: "Introduction"
canonical_url: https://developer.repebble.com/pebbleos/docs/libraries/fuel_gauge/introduction/
last_updated: 2026-11-13
sdk_version: 4.44
---
# Introduction

Source: https://developer.repebble.com/pebbleos/docs/libraries/fuel_gauge/introduction/

The fuel gauge estimates the SOC with a model of the cell, chosen at build time. The rest is shared by all models: the description of the cell, the reported level, the time estimates and the saved state.

## Features

- the SOC, raw or as a reported level that only moves in the direction the battery is going

- the time to empty, and the time to full through constant-current and constant-voltage charging

- a state to save and restore across reboots, discarded when it no longer matches the cell

## Cell

The cell is described by its capacity \(Q\), its open-circuit voltage (OCV) curve and its series resistance \(R\_0\), all at 25 °C (`struct pbl_fuel_gauge_cell`):

- \(\mathrm{OCV}(z)\) is the voltage of the cell after a long rest at SOC \(z\) (0 to 1). It is a table of points, interpolated linearly, that must increase with \(z\), from 0 (empty) to 1 (full).

- \(R\_0\) is the instantaneous drop when the current steps: electrolyte, contacts, tabs and anything else in series up to where the voltage is measured.

Anything else, such as polarization or how resistances change with temperature, is up to the [model](https://developer.repebble.com/pebbleos/docs/libraries/fuel_gauge/models.md) the SOC is estimated with, and is one of its parameters.

## Reported SOC

`pbl_fuel_gauge_update()` returns the SOC to show. While the estimate is still converging (its standard deviation above 2%, e.g. right after starting from the voltage), it follows the estimate. After that, it doesn’t rise while discharging or drop while charging, so the percentage never moves against the direction the battery is going. When the charger terminates, it is 100%. The raw estimate is available through `pbl_fuel_gauge_soc_get()`.

## Time to empty and time to full

Both use an exponentially weighted average current \(\bar\imath\) (3 h time constant). It restarts whenever the charge state changes, and is reported once it covers 10 minutes.

- **Time to empty** is the reported SOC times the capacity, divided by the average discharge current.

- **Time to full** follows the charger. In constant current (CC), the charger switches to constant voltage (CV) when \(\mathrm{OCV}(z) + \bar\imath\,R\_\text{dc}(T)\) reaches the termination voltage, with \(R\_\text{dc}(T)\) the resistance the estimator gives for a constant current. Inverting the OCV table gives the SOC where that happens, and the CC time is the charge up to it divided by the current. In CV, the current decays roughly exponentially from \(i\_0\) to the termination current \(i\_\text{term}\), which delivers a charge \(q\) in \(\frac{q}{i\_0 - i\_\text{term}} \ln \frac{i\_0}{i\_\text{term}}\).

## Persistence

`pbl_fuel_gauge_state_get()` returns a `struct pbl_fuel_gauge_state` for the caller to store, and `pbl_fuel_gauge_init()` resumes from it unless one of these holds:

- It was produced with another cell, estimator parameters or state layout: `model_id` is a hash of all three.

- Its SOC disagrees by more than 25% with the SOC implied by the voltage. That happens after a battery swap, or a long time without power.

- The OCV of its reported SOC is more than 50 mV below the voltage with the load removed, as the estimator computes it. The reported SOC doesn’t rise while discharging, so such a level would stay too low, e.g. a 0% saved on a cell that then got some charge back.

In these cases it starts over from the voltage.

Generated from PebbleOS [f4926c952](https://github.com/coredevices/pebbleos/commit/f4926c952bf9b82bce9e3cdb44645a59531c0ee9). This page is maintained in the pebbleos repository: [docs/libraries/fuel\_gauge/introduction.md](https://github.com/coredevices/pebbleos/blob/f4926c952bf9b82bce9e3cdb44645a59531c0ee9/docs/libraries/fuel_gauge/introduction.md).
