LoRa Time on Air Calculator — Airtime, Duty Cycle & Battery

Calculate LoRa packet time on air for any SF, bandwidth, and payload size. Includes EU868 duty cycle compliance check, max packets per hour, and battery drain estimate for SX1276 and SX1262.

LoRa parameters

Spreading factor

Bandwidth

Coding rate

TX power & packet rate

Result

Time on air (SF7 / 125 kHz / 12 B)

41.2 ms

12.5 ms preamble + 28.7 ms payload (28 symbols)

Duty cycle at 240 pkt/hr (limit: 1%)

0.275%

Headroom: 0.725% — max 873 pkt/hr

Symbol duration

1.024 ms

Data rate

2329 bps

TX current

100 mA

Avg TX current

0.3 µA

TX-only battery drain (2000 mAh)

830.9 years

TX contribution only — add sleep/active current in the Battery Life Estimator

Time on air reference (12-byte payload, CR 4/5, explicit header, CRC, 8 preamble symbols)

SF125 kHz250 kHz500 kHzMax pkt/hr (1% DC)Data rate (125k)
SF741.2 ms20.6 ms10.3 ms8732329 bps
SF882.4 ms41.2 ms20.6 ms4361165 bps
SF9144.4 ms72.2 ms36.1 ms249665 bps
SF10288.8 ms144.4 ms72.2 ms124332 bps
SF11577.5 ms288.8 ms144.4 ms62166 bps
SF121.155 s577.5 ms247.8 ms3183 bps

Formula: Semtech AN1200.13 Rev 2.0. Low data rate optimization auto-applied for SF11/SF12 at 125 kHz. Max pkt/hr assumes 1% EU868 duty cycle limit on the g1 sub-band.

How it works

Time on air (ToA) is the total duration a LoRa packet occupies the channel, from the first preamble chip to the last payload chip. It determines everything downstream: duty cycle compliance, gateway capacity, and battery life.

The formula (Semtech AN1200.13)

T_symbol    = 2^SF / BW
T_preamble  = (n_preamble + 4.25) × T_symbol

payloadSymbNb = 8 + max(⌈(8×PL − 4×SF + 28 + 16×CRC − 20×IH) / (4×(SF − 2×DE))⌉ × (CR+4), 0)

T_payload   = payloadSymbNb × T_symbol
T_packet    = T_preamble + T_payload

Where:

  • PL — payload bytes
  • SF — spreading factor (7–12)
  • BW — bandwidth in Hz (125000, 250000, 500000)
  • CRC — 1 if CRC enabled
  • IH — 1 for implicit header, 0 for explicit
  • DE — 1 if low data rate optimization enabled (required when T_symbol > 16 ms)
  • CR — coding rate value: 1 for 4/5, 2 for 4/6, 3 for 4/7, 4 for 4/8
  • n_preamble — preamble symbols (default 8 in LoRaWAN)

Low data rate optimization

At SF11 and SF12 with 125 kHz bandwidth, the symbol duration exceeds 16 ms. The SX127x requires low data rate optimization (LDRO bit in MODEM_CONFIG3) to be set. This effectively halves the usable data in the denominator, increasing the payload symbol count. The calculator applies this automatically.

If you forget to set LDRO in firmware, the receiver won’t decode SF11/SF12 packets correctly.

/* lorawan/lora_sx12xx_common.c sets LDRO automatically when SF >= 11 */

/* For direct SX1276 register access: */
if (sf >= 11 && bw == BW_125KHZ) {
    SX1276Write(REG_LR_MODEMCONFIG3,
        SX1276Read(REG_LR_MODEMCONFIG3) | 0x08); /* set LowDataRateOptimize */
}
// lora-phy crate (used by embassy-lora) sets LDRO automatically
// based on the computed symbol duration — no manual register write needed.

// For direct SX1276 register access via embedded-hal SPI:
if sf >= 11 && bw == Bandwidth::_125KHz {
    let config3 = spi_read(REG_LR_MODEMCONFIG3)?;
    spi_write(REG_LR_MODEMCONFIG3, config3 | 0x08)?; // LowDataRateOptimize
}

In Arduino LoRa library, call LoRa.setLdoFlag().

EU868 duty cycle

ETSI EN 300 220 divides 868 MHz into sub-bands with different duty cycle limits:

Sub-bandFrequenciesDuty cycleMax EIRP
g863–868 MHz1%25 mW
g1868.0–868.6 MHz1%25 mW
g2868.7–869.2 MHz0.1%25 mW
g3869.4–869.65 MHz10%500 mW

Most LoRaWAN Class A deployments use g1. At 1% duty cycle, a device can transmit for 36 seconds per hour total. An SF12 packet at 125 kHz is ~1 second — so you get at most 36 packets per hour on that sub-band.

This is the wall most EU LoRa projects hit when trying to increase transmission frequency. The fix is: use a lower SF (SF7 = ~40 ms → 900 packets/hr), reduce payload size, or use the g3 sub-band for high-duty-cycle applications.

Battery drain from TX

For a given packet rate:

duty_cycle     = T_packet × packets_per_hour / 3600
avg_tx_current = duty_cycle × TX_peak_current

For an SX1276 at +14 dBm (~100 mA peak), SF7, 12-byte payload, 10 packets/hour:

T_packet ≈ 41 ms
duty = 0.041 × 10 / 3600 = 0.000114 (0.011%)
avg_tx_current = 0.000114 × 100 mA = 11.4 µA

This is why LoRa IoT nodes last years — the radio is active for a tiny fraction of time. The limiting factor is usually sleep current and the MCU, not the radio.

Common mistakes

Not checking duty cycle before deploying. A device that works fine at 1 packet/minute in testing may exceed the 1% limit at 4 packets/minute with SF9. Calculate ToA × rate first.

Using SF12 for everything. SF12 gives the best range but 23× the airtime of SF7. Every hop up in SF roughly doubles the ToA, halves the max packet rate, and costs the same fade margin as increasing TX power by 2.5 dB. Use the minimum SF that achieves your link margin.

Forgetting LoRaWAN overhead. If you’re using LoRaWAN, the MAC layer adds 13 bytes of overhead (FHDR + FPORT) before your application payload. A “10-byte message” actually transmits as a 23-byte packet. For small payloads this significantly increases ToA.

Wrong preamble length. The default is 8 symbols. LoRaWAN requires exactly 8. Point-to-point custom networks sometimes use longer preambles (up to 65535 symbols) for extended wake-from-sleep receivers, which can dominate the ToA.

Not accounting for TX ramp-up time. The SX127x adds ~2 ms of TX oscillator stabilization on top of the calculated ToA. For precise duty cycle budgeting, add this margin.

Frequently asked questions

What is LoRa duty cycle and why does it matter for EU868? +

EU868 sub-bands cap TX time to 0.1–10% per hour. If your packet is 500 ms and you send 240/hr, you use 3.3% — over the 1% g1 limit. Violating duty cycle is illegal and will trigger network-side blocking on TTN/Helium.

How does spreading factor affect time on air? +

Each SF step doubles the symbol duration. SF12 at 125 kHz has a symbol of 32.8 ms vs 1.0 ms at SF7 — roughly 30x longer airtime for the same payload. Higher SF improves link budget by ~2.5 dB per step but directly multiplies battery drain and duty cycle usage.

Why is time on air important for battery life? +

TX current on SX1276 at +14 dBm is ~100 mA. A 1155 ms SF12 packet draws ~32 µAh; SF7 at 41 ms draws ~1.1 µAh — a 28x difference per packet. At 96 packets/day that is 3080 µAh vs 110 µAh in TX energy alone, before sleep current.

Newsletter

The embedded engineer's weekly cheat sheet

Register tricks, timing gotchas, and tool updates. One email per week. No fluff.

No spam. Unsubscribe anytime.