"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:
- Multiply received IQ by the conjugate reference down-chirp
- Take FFT
- 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:
- Total unique device types decoded
- For each device type: model string, frequency, data fields, update interval
- 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