Software LoRa demodulator
8 May 2022
Here is an implementation of a LoRa demodulator in less than 900 lines of C. It reads I/Q samples from stdin has no dependencies outside of the standard library.
Notable features are:
It operates at the Nyquist rate for the modulation bandwidth, and uses very little CPU time (about a 2% duty cycle for 125 kHz SF7 on a Sandy Bridge). Most of the processing is due to one or two FFTs per frame. All further processing is done based on bin peaks.
It supports modulations SF7 through SF12, with or without LDRO.
It supports all coding rates (4/4 through 4/8) with parity checks. Bit-error rates are estimated and reported.
It tracks fractional carrier-frequency offset by estimating off-bin peak frequencies and mixing the fractional frequency with subsequent frames. This “fractional” frequency can actually accumulate to multiple bins’ worth of error, allowing the receiver to track and compensate for sampling frequency errors, up to a reasonable packet length.
No trigonometric functions are required after an initial table setup. The remaining trigonometric calls could, if necessary, be eliminated by the use of a precomputed complex-roots-of-unity table. This would ease conversion to fixed-point.
To compile:
gcc -O1 -Wall -o lora lora.c -lm
The program uses C99 complex floats. You can use the program in conjunction with software like rtl-sdr to receive LoRa frames:
rtl_sdr -g 30 -f 915000000 -s 1000000 - | ./lora -b 8 -s 7
The expected input sample rate must be an integer multiple of the expected bandwidth. This multiple should be specified on the command-line with -b
. Ideally, this will be twice the signal bandwidth, so as to minimize noise while allowing for the full range of carrier offset compensation. The example above is for 125 kHz of bandwidth (note that RTL-SDR dongles have a minimum sample rate of around 1 Msps).
As packets are received, blocks will be printed on stdout containing payload data and basic information:
Sync: 55
SNR: 20.6 dB
BER: 0/465
CRC: ok
Bytes (20): d3 5e 8f f9 26 4d 20 87 c3 99 ba 2a 26 d1 27 23 e3 6e 4b 2d
If you’re interested in debugging or improving the code, a couple of compile-time options may be useful:
-DDEBUG_DEMOD
: demodulation debugging. This will show debug output for each frame processed, with peaks, fractional CFO tracking, and state machine states.-DDEBUG_CODE
: decode debugging. This will show symbols and code blocks for received frames.
Licence
Copyright (C) 2022 Daniel Beer dlbeer@gmail.com
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.