# Spreadsheet for LoRa airtime calculation

**URL:** <https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190>\
**Category:** Uncategorized\
**Created:** [February 4, 2016, 2:45pm UTC](https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190 "2016-02-04T14:45:50Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![matthijskooijman](https://www.thethingsnetwork.org/forum/letter_avatar_proxy/v4/letter/m/71c47a/32.png) [@matthijskooijman](https://www.thethingsnetwork.org/forum/u/matthijskooijman)\
**Post date:** [February 4, 2016, 2:45pm UTC](https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190/1 "2016-02-04T14:45:50Z")

</div>

Just now, I wanted to do some bandwidth calculations for LoRa, but I couldn’t find any easy to use tables with examples or online calculators (and didn’t want to download some Windows-only LoRa Calculator tool). So I took the formula from an application note from Semtech and put it into a spreadsheet, which seems to work fine.

_Spreadsheet is replaced by The Things Network’s Airtime Calculator:_  
See: [https://www.thethingsnetwork.org/airtime-calculator/](https://www.thethingsnetwork.org/airtime-calculator/)

---

<div class="post-metadata">

**Author:** ![iikaw](https://www.thethingsnetwork.org/forum/user_avatar/www.thethingsnetwork.org/iikaw/32/71_2.png) [@iikaw](https://www.thethingsnetwork.org/forum/u/iikaw)\
**Post date:** [February 4, 2016, 3:07pm UTC](https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190/2 "2016-02-04T15:07:09Z")

</div>

@matthijs Thanks for this.

Something I’m trying to do with the lora calculator with LoRaWAN.  
Assume that payload is the encrypted?  
If so how are getting the encrypted payload length?  
Also I thought Explicit header needs to be on?

---

<div class="post-metadata">

**Author:** ![telkamp](https://www.thethingsnetwork.org/forum/user_avatar/www.thethingsnetwork.org/telkamp/32/35697_2.png) [@telkamp](https://www.thethingsnetwork.org/forum/u/telkamp)\
**Post date:** [February 4, 2016, 3:07pm UTC](https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190/3 "2016-02-04T15:07:26Z")

</div>

Very nice!

One remark to prevent confusion: the payload size in your spreadsheet is the LoRa payload, so including LoraWAN header. A user should add 13 bytes to his own payload to get the correct numbers.

---

<div class="post-metadata">

**Author:** ![weradis](https://www.thethingsnetwork.org/forum/user_avatar/www.thethingsnetwork.org/weradis/32/45845_2.png) [@weradis](https://www.thethingsnetwork.org/forum/u/weradis)\
**Post date:** [February 4, 2016, 3:58pm UTC](https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190/4 "2016-02-04T15:58:16Z")

</div>

@thomas I think usually at least 13 [MHDR (1) + DevAddr (4) + FCtrl (1) + FCnt (2) + Fport(1) + MIC(4)] in a packet with no options  
@iikaw they payload size is independent from the encryption.

---

<div class="post-metadata">

**Author:** ![iikaw](https://www.thethingsnetwork.org/forum/user_avatar/www.thethingsnetwork.org/iikaw/32/71_2.png) [@iikaw](https://www.thethingsnetwork.org/forum/u/iikaw)\
**Post date:** [February 4, 2016, 4:11pm UTC](https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190/5 "2016-02-04T16:11:50Z")

</div>

@w4e ok but the payload is encrypted before transmission therefore will affect “time on air” no?

---

<div class="post-metadata">

**Author:** ![weradis](https://www.thethingsnetwork.org/forum/user_avatar/www.thethingsnetwork.org/weradis/32/45845_2.png) [@weradis](https://www.thethingsnetwork.org/forum/u/weradis)\
**Post date:** [February 4, 2016, 4:18pm UTC](https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190/6 "2016-02-04T16:18:21Z")

</div>

The number of bits stay the same - so I would say no effect on airtime.

---

<div class="post-metadata">

**Author:** ![iikaw](https://www.thethingsnetwork.org/forum/user_avatar/www.thethingsnetwork.org/iikaw/32/71_2.png) [@iikaw](https://www.thethingsnetwork.org/forum/u/iikaw)\
**Post date:** [February 4, 2016, 5:20pm UTC](https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190/7 "2016-02-04T17:20:30Z")

</div>

@w4e thanks hadn’t I hadn’t realised that.

---

<div class="post-metadata">

**Author:** ![telkamp](https://www.thethingsnetwork.org/forum/user_avatar/www.thethingsnetwork.org/telkamp/32/35697_2.png) [@telkamp](https://www.thethingsnetwork.org/forum/u/telkamp)\
**Post date:** [February 4, 2016, 6:09pm UTC](https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190/8 "2016-02-04T18:09:15Z")

</div>

> [@w4e](#):
>
> @thomas I think usually at least 13 [MHDR (1) + DevAddr (4) + FCtrl (1) + FCnt (2) + Fport(1) + MIC(4)] in a packet with no options

Thanks, 13 it is.

---

<div class="post-metadata">

**Author:** ![matthijskooijman](https://www.thethingsnetwork.org/forum/letter_avatar_proxy/v4/letter/m/71c47a/32.png) [@matthijskooijman](https://www.thethingsnetwork.org/forum/u/matthijskooijman)\
**Post date:** [February 4, 2016, 8:31pm UTC](https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190/9 "2016-02-04T20:31:14Z")

</div>

Thanks for the additions, I’ve added some clarifications to the sheet.

---

<div class="post-metadata">

**Author:** ![niels](https://www.thethingsnetwork.org/forum/letter_avatar_proxy/v4/letter/n/ebca7d/32.png) [@niels](https://www.thethingsnetwork.org/forum/u/niels)\
**Post date:** [February 5, 2016, 8:30am UTC](https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190/10 "2016-02-05T08:30:53Z")

</div>

im not an expert, but shouldn’t Preamble, PHDR, CRC be included as well?

---

<div class="post-metadata">

**Author:** ![matthijskooijman](https://www.thethingsnetwork.org/forum/letter_avatar_proxy/v4/letter/m/71c47a/32.png) [@matthijskooijman](https://www.thethingsnetwork.org/forum/u/matthijskooijman)\
**Post date:** [February 5, 2016, 10:04am UTC](https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190/11 "2016-02-05T10:04:02Z")

</div>

> [@niels](#):
>
> im not an expert, but shouldn’t Preamble, PHDR, CRC be included as well?

The preamble is taken into account (you specify the number of preamble symbols in the sheet). The PHDR and (header) CRC are included if you specify “disable header” as 0 in the sheet. The payload CRC is part of the payload.

---

<div class="post-metadata">

**Author:** ![arjanvanb](https://www.thethingsnetwork.org/forum/user_avatar/www.thethingsnetwork.org/arjanvanb/32/46626_2.png) [@arjanvanb](https://www.thethingsnetwork.org/forum/u/arjanvanb)\
**Post date:** [February 27, 2016, 11:22am UTC](https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190/12 "2016-02-27T11:22:15Z")

</div>

I guess not, but: is there any option in The Things Network to skip the LoRaWAN headers?

Like in a pet finder use case, one cannot send coordinates too often, due to the 1% duty cycle and 30 seconds/day Fair Access Policy. But even sending an empty “alive” message (for which a Class A node could then receive some specific reply to start sending coordinates) would take 1.16 seconds on SF12, for just the 13 bytes of the LoRaWAN header, hence would be limited to 26 empty packets a day…

Also [location by triangulation](https://www.thethingsnetwork.org/forum/t/location-by-triangulation/435/41) would need _some_ data to be sent. And [some say](https://www.thethingsnetwork.org/forum/t/location-by-triangulation/435/33) moving nodes should always use SF12, though [others](https://www.thethingsnetwork.org/forum/t/smallest-expected-node/568/81) have different experiences.

---

<div class="post-metadata">

**Author:** ![arjanvanb](https://www.thethingsnetwork.org/forum/user_avatar/www.thethingsnetwork.org/arjanvanb/32/46626_2.png) [@arjanvanb](https://www.thethingsnetwork.org/forum/u/arjanvanb)\
**Post date:** [February 27, 2016, 2:14pm UTC](https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190/13 "2016-02-27T14:14:55Z")

</div>

I’ve adjusted this nice sheet a bit, to split application payload and LoRaWAN headers, to show the results of all spread factors, and to include the maximum number of messages to adhere to the TTN Fair Access Policy.

Good to see how the number of symbols _decreases_ when the connection quality drops (assuming that is correct…), and how it only partly depends on the application payload. And scary how on low data rates the TTN Fair Access Policy is really limiting.

@matthijs, if you like these changes then maybe copy them into your sheet, to keep the existing URL? I can then delete this very post.

See [https://docs.google.com/spreadsheets/d/1QvcKsGeTTPpr9icj4XkKXq4r2zTc2j0gsHLrnplzM3I/edit?usp=sharing](https://docs.google.com/spreadsheets/d/1QvcKsGeTTPpr9icj4XkKXq4r2zTc2j0gsHLrnplzM3I/edit?usp=sharing)

---

<div class="post-metadata">

**Author:** ![arjanvanb](https://www.thethingsnetwork.org/forum/user_avatar/www.thethingsnetwork.org/arjanvanb/32/46626_2.png) [@arjanvanb](https://www.thethingsnetwork.org/forum/u/arjanvanb)\
**Post date:** [March 2, 2016, 7:46pm UTC](https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190/14 "2016-03-02T19:46:37Z")

</div>

I had a short discussion with @htdvisser about [some constants in the air time calculations used in `ttntool`](https://github.com/htdvisser/ttntool/blob/master/util/lora.go). He suggested @Thomas might know more, so here goes:

1. LoRaWAN might have a fixed coding rate of 1? (So, `CR=1`.) I cannot find that in the specification. Even more: it _does_ mention it explicitly for transmission of Class B beacons, so I doubt it’s also fixed for other operations?

2. As LoRaWAN includes its own header, the explicit LoRa header might not be needed? (So, `H=1`.) That would indeed need a fixed coding rate to start with (which otherwise would be set in the LoRa header). But it would also need some way to determine the payload length (which is in the LoRa header, but not in the LoRaWAN header). I think [the LoRaWAN specification](https://www.lora-alliance.org/portals/0/specs/LoRaWAN%20Specification%201R0.pdf#page=12) claims the LoRa header is always included though:

3. The [LoRa Modem Design Guide](http://www.semtech.com/forum/images/datasheet/LoraDesignGuide_STD.pdf) on which @matthijs based his nice sheet, states:

---

<div class="post-metadata">

**Author:** ![telkamp](https://www.thethingsnetwork.org/forum/user_avatar/www.thethingsnetwork.org/telkamp/32/35697_2.png) [@telkamp](https://www.thethingsnetwork.org/forum/u/telkamp)\
**Post date:** [March 3, 2016, 7:57pm UTC](https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190/15 "2016-03-03T19:57:46Z")

</div>

Arjan,

Thanks for caring about these details!

> [@arjanvanb](#):
>
> LoRaWAN might have a fixed coding rate of 1? (So, CR=1.) I cannot find that in the specification. Even more: it does mention it explicitly for transmission of Class B beacons, so I doubt it’s also fixed for other operations?

It is not fixed.

> [@](#):
>
> As LoRaWAN includes its own header, the explicit LoRa header might not be needed? (So, H=1.) That would indeed need a fixed coding rate to start with (which otherwise would be set in the LoRa header). But it would also need some way to determine the payload length (which is in the LoRa header, but not in the LoRaWAN header). I think the LoRaWAN specification claims the LoRa header is always included though:  
> 3.1 Uplink Messages[…]Uplink messages use the LoRa radio packet explicit mode in which the LoRa physical header (PHDR) plus a header CRC (PHDR\_CRC) are included.

LoRaWAN does use the explicit header indeed.

> [@](#):
>
> The LoRa Modem Design Guide on which @matthijs based his nice sheet, states:  
> To avoid issues surrounding drift of the crystal reference oscillator due to either temperature change or motion, the low data rate optimization bit is used. Specifically for 125 kHz bandwidth and SF = 11 and 12, this adds a small overhead to increase robustness to reference frequency variations over the timescale of the LoRa packet.  
> Does anyone know if this is automatically enabled by the chipset or the LoRaWAN stack, for SF11 and SF12? In ttntool this is currently indeed the case:  
> dataRateOptimization := 0  
> if int(spreadingFactor) \>= 11 {  
> dataRateOptimization = 1  
> }

The LoRaWAN stack handles this, for example an excerpt from the LMiC:

`if ((sf == SF11 || sf == SF12) && getBw(LMIC.rps) == BW125) { mc1 |= SX1272_MC1_LOW_DATA_RATE_OPTIMIZE; } `

---

<div class="post-metadata">

**Author:** ![arjanvanb](https://www.thethingsnetwork.org/forum/user_avatar/www.thethingsnetwork.org/arjanvanb/32/46626_2.png) [@arjanvanb](https://www.thethingsnetwork.org/forum/u/arjanvanb)\
**Post date:** [March 4, 2016, 11:53am UTC](https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190/16 "2016-03-04T11:53:19Z")

</div>

Okay, I’ve changed [my copy of the sheet](https://docs.google.com/spreadsheets/d/1QvcKsGeTTPpr9icj4XkKXq4r2zTc2j0gsHLrnplzM3I/edit?usp=sharing) to auto-enable low data rate correction for SF11…12, and to also make clear that SF6 is not used in LoRaWAN. So basically LoRaWAN users only need to adjust the value for application payload to see the results.

(@matthijs, if you ever copy those changes in your sheet at the original URL then let me know, so I can delete these posts.)

---

<div class="post-metadata">

**Author:** ![bvanderpol](https://www.thethingsnetwork.org/forum/user_avatar/www.thethingsnetwork.org/bvanderpol/32/593_2.png) [@bvanderpol](https://www.thethingsnetwork.org/forum/u/bvanderpol)\
**Post date:** [April 6, 2016, 11:16am UTC](https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190/17 "2016-04-06T11:16:03Z")

</div>

@matthijs @arjanvanb  
First of all, thank you very much for the sheet! Very useful for indication!

I have a question about payload comment in the sheet.  
‘For LoRaWAN: maximum 55 for low data rates (SF12), up to about 222 bytes for best conditions (SF7).’

In the LoRaWAN spec (7.1.6 EU863-870 Maximum payload size) DR0 - DR2 have a maximum payload of 51 bytes (absence of Fopt)  
Would this be a maximum of 51 for SF12 (DR0) according to this table, or am I missing something? Could you please elaborate?

Thank you!

---

<div class="post-metadata">

**Author:** ![arjanvanb](https://www.thethingsnetwork.org/forum/user_avatar/www.thethingsnetwork.org/arjanvanb/32/46626_2.png) [@arjanvanb](https://www.thethingsnetwork.org/forum/u/arjanvanb)\
**Post date:** [April 6, 2016, 11:59am UTC](https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190/18 "2016-04-06T11:59:58Z")

</div>

@bvanderpol, that comment is something I added to the original sheet, and took from [the FAQ](http://thethingsnetwork.org/wiki/faq).

The numbers were [added](http://thethingsnetwork.org/wiki/faq/diff/dcc9e3b%5E..dcc9e3b) to the FAQ after another discussion. But reading it again, [that discussion](https://www.thethingsnetwork.org/forum/t/parse-data-with-node-red/835/2) is clear about the maximum, and indeed also mentions 55 but does not explicitly state that’s the minimum. So maybe the minimum in the FAQ is indeed wrong. (I also think the figures are slightly different for different regions? I’m not sure though.)

---

<div class="post-metadata">

**Author:** ![hanshenrik](https://www.thethingsnetwork.org/forum/letter_avatar_proxy/v4/letter/h/76d3ee/32.png) [@hanshenrik](https://www.thethingsnetwork.org/forum/u/hanshenrik)\
**Post date:** [April 6, 2016, 2:12pm UTC](https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190/19 "2016-04-06T14:12:13Z")

</div>

Very nice sheet, incredibly helpful!

I am still not quite sure how to calculate the header and payload sizes though. I am using a Waspmote to send frames containing sensor data. The frame is converted into a hexadecimal array—which is the required format by the `LoRaWAN.sendUnconfirmed(...)` function—by using the following util function:

```auto
char sendableString[frame.length*2 + 1];
Utils.hex2str(frame.buffer, sendableString, frame.length);

```

Here’s some output from a transmission:

```auto
Frame Length: 105
Frame (STR): <=>#012345678#0123456789#0#BAT:42#IN_TEMP:17.00#GP_TC:-26.774#GP_HUM:25.70#GP_CO:25.918#GP_CO2:304.826#
Sendable string: 3c3d3e3f062330313233343536373823303132333435363738392330234241543a343223494e5f54454d503a31372e30302347505f54433a2d32362e3737342347505f48554d3a32352e37302347505f434f3a32352e3931382347505f434f323a3330342e38323623
strlen(sendableString): 210
sizeof(sendableString): 211
ADR: 1
DataRate: 5 (= SF7BW125)
Radio frequency: 869525000
Radio spreading factor: sf12
Radio bandwidth: 125
Radio coding rate: 4/5
Radio preamble length: 8

```

The corresponding TheThingsNetwork `data` field is:

```auto
PD0+gAYjNDAzMzE1ODQwI1dNMDIwMzIyMjIjMCNCQVQ6NDIjSU5fVEVNUDoxNy4wMCNHUF9UQzotMjYuNzc0I0dQX0hVTToyNS43MCNHUF9DTzoyNS45MTgjR1BfQ08yOjMwNC44MjYj

```

htdvisser’s ttntool calculated the air time to be **174.3ms** , which working backwards in the spreadsheet suggests a payload of **87-90 bytes** (if the header is 13 bytes).

So my question is simply: how do I know my payload and header sizes without working backwards based on air time calculated?

---

<div class="post-metadata">

**Author:** ![arjanvanb](https://www.thethingsnetwork.org/forum/user_avatar/www.thethingsnetwork.org/arjanvanb/32/46626_2.png) [@arjanvanb](https://www.thethingsnetwork.org/forum/u/arjanvanb)\
**Post date:** [April 6, 2016, 5:16pm UTC](https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190/20 "2016-04-06T17:16:28Z")

</div>

> [@hanshenrik](#):
>
> htdvisser’s ttntool calculated the air time to be 174.3ms

Note that there are some minor bugs there [as mentioned above](https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190/14), for which I promised a pull request which I still did not create… Not sure how much that affects the result though.

> [@hanshenrik](#):
>
> how do I know my payload and header sizes

As far as I know, the headers are always 13 bytes (as explained [above](https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190/4)), and the payload is just a number of bytes too, so 105 in your example. So in matthijs’ original sheet that’s 118 in total; in my version it’s 105 and 13.

By the way: ~~[Don’t. Send. Text.](https://www.thethingsnetwork.org/forum/t/limitations-data-rate-packet-size-30-seconds-day-fair-access-policy-nodes-per-gateway/1300)~~ [Don’t. Send. Text.](https://www.thethingsnetwork.org/forum/t/best-practices-to-limit-application-payloads/1302) It will eat [your maximum air time](https://www.thethingsnetwork.org/forum/t/limitations-data-rate-packet-size-30-seconds-day-fair-access-policy-nodes-per-gateway/1300) with no good reason. Also, it seems `#BAT:42#` is a counter value? Then note that the headers already have a counter. [see responses below]

[Next page](https://www.thethingsnetwork.org/forum/t/spreadsheet-for-lora-airtime-calculation/1190.md?page=2)
