— Semtech Lo">
Classroom Glossary Public page

RF-201 Week 6 — LoRa + ISM-Band Experiments

1,061 words

"LoRa is the first commercial spread-spectrum system designed from the ground up for the IoT constraint: transmit microwatts, sleep gigaseconds, reach kilometers." — Semtech LoRa documentation framing


Lecture (90 min)

6.1 The ISM Band Landscape at RF-201 Depth

WIR-101 Week 9 surveyed the sub-GHz ISM bands for protocol recognition. RF-201 experiments at a deeper level: not just "what's there" but "how does it work and how do you demodulate it from scratch?"

The three primary sub-GHz ISM bands relevant to RF-201:

Band Region Frequency Primary protocols
433 MHz Worldwide (varies by country) 433.05-434.79 MHz OOK remotes; RFID; LoRa 433; temperature sensors
868 MHz Europe (ETSI EN 300 220) 863-870 MHz LoRa EU868; Z-Wave EU; Sigfox EU
915 MHz Americas (FCC Part 15.247) 902-928 MHz LoRa US915; Zigbee; Z-Wave US; Wi-SUN

Each band has regional regulatory constraints on duty cycle (EU: 1% or 10% depending on sub-band), transmit power (EU: typically +14 dBm ERP for general ISM), and channel plans.

The security relevance: These bands are crowded, uncoordinated, and almost entirely unencrypted at the application layer in deployed IoT devices. A passive SDR receiver hears everything. Your RTL-SDR at 433 MHz on a quiet day will see temperature sensors, tire pressure monitors, power meters, weather stations, pagers, and remote controls — all broadcasting plaintext sensor data.

6.2 LoRa Physical Layer: Chirp Spread Spectrum in Detail

Building on Week 3's spread-spectrum introduction, LoRa's CSS mechanism in engineering detail.

LoRa symbol encoding:

A LoRa symbol is one chirp. The chirp sweeps bandwidth B over a duration T_s = 2^SF / B. The symbol value (0 to 2^SF - 1) is the cyclic start frequency of the chirp.

For SF=7, BW=125kHz: T_s = 2^7 / 125000 = 1.024 ms per symbol. Data rate = 7 bits × CR / 1.024 ms. With CR=4/5: DR = 5468 bps.

The IQ representation of a LoRa chirp:

import numpy as np

def lora_chirp(sf, bw, fs, symbol_val, upchirp=True):
    """Generate a single LoRa chirp IQ sample stream."""
    M = 2**sf                          # symbols per chirp
    T_s = M / bw                       # symbol duration (s)
    N = int(T_s * fs)                  # samples
    t = np.arange(N) / fs              # time vector
    
    # Initial phase offset from symbol value
    f0 = -bw/2 + symbol_val * bw/M    # starting frequency
    
    if upchirp:
        f_t = f0 + bw/2 * t/T_s       # linearly increasing
    else:
        f_t = f0 - bw/2 * t/T_s       # linearly decreasing (reference dechirp)
    
    # Wrap frequency at band edges (cyclic chirp)
    f_t = ((f_t + bw/2) % bw) - bw/2
    
    # Integrate frequency to get phase
    phase = 2 * np.pi * np.cumsum(f_t) / fs
    return np.exp(1j * phase)

# Generate 8 LoRa symbols (SF=7, BW=125kHz, fs=500kHz)
sf, bw, fs = 7, 125e3, 500e3
symbols = [lora_chirp(sf, bw, fs, v) for v in [0, 10, 50, 100, 0, 0, 0, 0]]
signal = np.concatenate(symbols)

LoRa demodulation:

  1. Multiply received IQ by the conjugate reference down-chirp
  2. Take FFT
  3. Find the peak bin index → that is the symbol value
def demodulate_lora_symbol(rx_chirp, sf, bw, fs):
    M = 2**sf
    ref_downchirp = lora_chirp(sf, bw, fs, 0, upchirp=False)
    dechirped = rx_chirp[:len(ref_downchirp)] * np.conj(ref_downchirp)
    spectrum = np.abs(np.fft.fft(dechirped, M))**2
    return np.argmax(spectrum)

This is the complete core of a LoRa demodulator. The rest of the LoRa physical layer adds: preamble detection, sync word, header, cyclic redundancy check, and optional data whitening + interleaving.

6.3 LoRaWAN: The Network Layer Above LoRa

LoRaWAN is the network-layer specification built on LoRa physical. Semtech's LoRaWAN specification (v1.0.x, v1.1) defines:

Device classes:

  • Class A: ALOHA-like uplink; two RX windows after each TX; most power-efficient
  • Class B: scheduled downlink; beacon-synchronized; moderate power
  • Class C: continuous RX; highest power; fastest downlink latency

Security: LoRaWAN uses AES-128-based message authentication (CMAC) and encryption:

  • NwkSKey: Network Session Key — authenticates uplink MIC; encrypts MAC commands
  • AppSKey: Application Session Key — encrypts application payload

Keys are derived from: AppKey (pre-provisioned), DevEUI, AppEUI, and a device nonce during OTAA (Over-the-Air Activation) join procedure.

Known vulnerabilities in LoRaWAN 1.0.x:

  • Nonce reuse: DevNonce in OTAA join is a 16-bit counter in v1.0.x (not random). Predictable nonce allows replay attacks against the join procedure.
  • Key derivation from known parameters: if AppKey is extracted from a device (firmware dump or side channel), all session traffic is decryptable.
  • No downlink replay protection in v1.0.x: the FCntDown counter can be reset by a gateway.

LoRaWAN 1.1 addresses most of these: separate NwkSKey/AppSKey paths, 32-bit DevNonce (random), separate uplink/downlink frame counters.

6.4 RTL-SDR + rtl_433 for Sub-GHz Protocol Survey

rtl_433 is a tool specifically for passive reception and decoding of common sub-GHz IoT protocols. It knows about 400+ device types.

# Listen on 433.92 MHz (EU common frequency)
rtl_433 -f 433.92M -s 250000

# Listen on 915 MHz (US ISM)
rtl_433 -f 915M -s 250000

# Output decoded frames as JSON
rtl_433 -f 433.92M -F json

# Sample output:
# {"time":"2026-05-29 10:14:22","model":"Generic-Remote","id":2151,
#  "channel":1,"button":4,"event":"pressed","mic":"CHECKSUM"}

A 30-minute passive survey of the 433 MHz band in a residential or office environment will typically reveal: temperature/humidity sensors, motion detectors, smart meter pulses, tire pressure monitors, weather stations, and remote-control key fobs. All unencrypted. All with device identifiers.

6.5 The DOCSIS RF Stage: SB6141 Forward Pointer

The SB6141 cable modem (VCA-RE-101's hardware target) uses DOCSIS (Data Over Cable Service Interface Specification) which runs on the cable plant at downstream 54-860 MHz, upstream 5-42 MHz. DOCSIS is an RF protocol — specifically an OFDM-based (DOCSIS 3.0 uses SC-QAM; DOCSIS 3.1 uses OFDMA) wired RF link.

RF-201's connection to RE-101: a student who understands LoRa's chirp-based robust sub-noise reception and OFDM modulation theory (Week 2) reads the DOCSIS RF stage of the SB6141 as an application of the same principles on a coaxial cable plant rather than free-space wireless.

DOCSIS 3.0 downstream: 256-QAM, 6 MHz channels, 38.8 Mbps/channel. The SB6141 has 16 downstream and 4 upstream channels. The RF front-end receives each channel's QAM signal, delivers it to the SoC demodulator. The RE-101 RF stage analysis asks: which frequency ranges does the tuner accept, what RF standards does it implement, and what side-channel or hardware-layer signals can be observed?


Homework

Reading (1.5 hr):

  • PySDR Ch 7 (Pulse Shaping) — root-raised cosine filtering applies to LoRa pulse shaping
  • Semtech AN1200.13 (LoRa Modulation Basics) — free PDF; the primary LoRa PHY reference
  • LoRaWAN specification v1.0.4 §4 (device activation) — free at lora-alliance.org

Hands-on (2 hr): Run rtl_433 on 433 MHz and 915 MHz for 15 minutes each. Document:

  1. Total unique device types decoded
  2. For each device type: model string, frequency, data fields, update interval
  3. For any device: use Python to parse the rtl_433 JSON output and plot signal frequency vs. time
import subprocess, json
import matplotlib.pyplot as plt

proc = subprocess.Popen(['rtl_433', '-f', '433.92M', '-F', 'json'],
                        stdout=subprocess.PIPE, text=True)
events = []
for i, line in enumerate(proc.stdout):
    if i >= 200: break  # collect 200 events
    try: events.append(json.loads(line.strip()))
    except json.JSONDecodeError: pass
proc.terminate()

models = [e.get('model', 'unknown') for e in events]
from collections import Counter
print(Counter(models).most_common(10))

Toolchain Diary Entry

First-introduce this week: rtl_433; PySDR LoRa decoder

rtl_433: passive RF protocol decoder for RTL-SDR. Decodes ~400+ protocols including temperature sensors, weather stations, power meters, remotes. Output: JSON, CSV, or human-readable. Command: rtl_433 -f 433.92M -F json. The default gain is AGC; set explicit gain with -g 30 if packets are missed.


Key Terms

  • LoRa: proprietary CSS physical-layer technology by Semtech; chirp spread spectrum; SF 7-12; BW 125/250/500 kHz
  • LoRaWAN: network-layer specification on top of LoRa; defines device classes (A/B/C); AES-128 encryption + MIC
  • OTAA (Over-the-Air Activation): LoRaWAN join procedure; device sends JoinRequest with DevNonce; server derives session keys
  • Chirp rate: k = BW/T_s; the rate at which instantaneous frequency changes during a LoRa symbol
  • Dechirp: multiply received signal by conjugate reference chirp; converts cyclic frequency offset to a single tone; the core of LoRa demodulation
  • Duty cycle (EU ISM): regulatory limit on fraction of time a sub-GHz device can transmit; typically 1% for 868 MHz general sub-band
  • rtl_433: open-source tool for decoding 400+ sub-GHz IoT protocols from RTL-SDR raw IQ; JSON/CSV output