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 bytesSF— spreading factor (7–12)BW— bandwidth in Hz (125000, 250000, 500000)CRC— 1 if CRC enabledIH— 1 for implicit header, 0 for explicitDE— 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/8n_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-band | Frequencies | Duty cycle | Max EIRP |
|---|---|---|---|
| g | 863–868 MHz | 1% | 25 mW |
| g1 | 868.0–868.6 MHz | 1% | 25 mW |
| g2 | 868.7–869.2 MHz | 0.1% | 25 mW |
| g3 | 869.4–869.65 MHz | 10% | 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.