Wi-Fi and Zigbee Emitter Algorithms¶
IEEE 802.11 and 802.15.4 waveform synthesis paths.
Note
Layer 3 shipped, Pass-1. The Layer 3 implementation (emitters,
device-fingerprint, tx-impairments, propagation, rx-frontend) landed
on branch rfgen-impl-2026-06-25-105955 (PR #94). The class names,
Pydantic schemas, and Transformation enum members referenced below
match the shipped surface; Pass-1 stubs (GNU Radio OOT emitters,
cellular emitters, Sionna propagation backends) construct cleanly and
raise an EmitterError or ChannelError tagged with
stage="pass1_stub" until backend wiring lands. See
Reference / rfgen.emitters and
Reference / rfgen.channels for the shipped
class roster.
5. Zigbee / 802.15.4¶
Family. iot.zigbee. 2.4 GHz O-QPSK with half-sine pulse shaping and 32-chip DSSS per 4-bit symbol.
def generate_zigbee(*, class_label, sample_rate, duration_s, params, rng):
"""
params:
channel: int # 11..26 (2405..2480 MHz, 5 MHz spacing)
pdu_bytes: bytes
"""
chip_rate = 2e6 # 2 Mchip/s
samples_per_chip = sample_rate / chip_rate
bw = 2e6 # 99% occupancy
# Build bitstream: preamble + SFD + PHR + PSDU
bits = _zigbee_build_bitstream(params["pdu_bytes"])
# 4-bit symbol → 32-chip PN sequence (per IEEE 802.15.4 Table 73)
chips = []
for i in range(0, len(bits), 4):
symbol = sum(bits[i+j] << j for j in range(4))
chips.extend(IEEE_802_15_4_CHIP_TABLE[symbol])
chip_arr = torch.tensor(chips, dtype=torch.float32) * 2 - 1 # ±1
# O-QPSK: I from even chips, Q from odd chips, Q delayed by Tc/2
even = chip_arr[0::2]
odd = chip_arr[1::2]
# Half-sine pulse shaping per 802.15.4 §10.2.6
pulse = torch.sin(torch.pi * torch.arange(int(round(samples_per_chip * 2))) /
(2 * samples_per_chip))
i_pulses = torch.zeros(len(even) * int(round(samples_per_chip * 2)))
for k, c in enumerate(even):
start = k * int(round(samples_per_chip * 2))
i_pulses[start:start + len(pulse)] = c * pulse
q_pulses = torch.zeros_like(i_pulses)
delay_samples = int(round(samples_per_chip)) # Tc/2 offset
for k, c in enumerate(odd):
start = k * int(round(samples_per_chip * 2)) + delay_samples
if start + len(pulse) > len(q_pulses):
break
q_pulses[start:start + len(pulse)] = c * pulse
iq = i_pulses + 1j * q_pulses
iq = _resample_to(iq, target_len=int(round(sample_rate * duration_s)))
return Signal(iq=iq, metadata=SignalMetadata(bandwidth_hz=bw, ...))
Reference. IEEE 802.15.4 §10 (the public spec). gr-ieee802-15-4 (GPL) is the reference implementation we cross-check against.
6. Wi-Fi 802.11 a/g/p¶
Family. comms.wifi. Out of scope (for v1): 802.11n/ac/ax/be (MIMO, 40+ MHz). In scope: 802.11a/g (20 MHz OFDM), 802.11p (10 MHz V2X variant).
Library tier: Independent implementation (fallback). Concepts / Emitters / Library Landscape designates Wi-Fi as runtime-isolated with the MATLAB WLAN Toolbox (wlanWaveformGenerator) as the preferred backend. The NumPy/PyTorch implementation below is the Tier 3 fallback for environments where MATLAB is unavailable. Before implementing this path, check whether the MATLAB engine (via matlab.engine) or the open-source gr-ieee802-11 block (GPL; subprocess boundary required) is more appropriate for your deployment. This fallback is appropriate for rapid prototyping or CI environments without MATLAB licenses.
Custom logic: verify as follows. The 802.11a/g OFDM PHY (scrambler, convolutional encoder, puncturer, interleaver, constellation mapper, IFFT, cyclic prefix, STF/LTF preamble) is a self-contained NumPy/PyTorch re-implementation per IEEE 802.11-2020 §17. To verify: pass a known test frame through this encoder and through gr-ieee802-11’s decoder; both must decode the payload bit-exact. MathWorks’ WLAN Toolbox is the validation oracle for spectral mask compliance.
Modulation. 64-point IFFT OFDM PHY. 8 data rates from 6 to 54 Mbps (BPSK/QPSK/16-QAM/64-QAM at three coding rates).
def generate_wifi(*, class_label, sample_rate, duration_s, params, rng):
"""
class_label: "comms.wifi.{11a,11g,11p}.ofdm-{20,10}mhz.r-{6,9,12,18,24,36,48,54}mbps"
params:
psdu_bytes: bytes
data_rate_mbps: int
channel: int # 11g: 1-13; 11a: 36-165
"""
bw = 20e6 if "20mhz" in class_label else 10e6
nfft = 64
cp_length = 16 # 1/4 cyclic prefix per 802.11a/g
n_data_subcarriers = 48
n_pilot = 4
# Map data rate → modulation + coding
rate_table = {
6: ("BPSK", "1/2"), 9: ("BPSK", "3/4"),
12: ("QPSK", "1/2"), 18: ("QPSK", "3/4"),
24: ("16-QAM", "1/2"), 36: ("16-QAM", "3/4"),
48: ("64-QAM", "2/3"), 54: ("64-QAM", "3/4"),
}
mod, coding = rate_table[params["data_rate_mbps"]]
# 1. Scramble + convolutional code + puncture (per 802.11 §17.3)
bits = _wifi_scramble(_wifi_pdu_bits(params["psdu_bytes"]), seed=0x5d)
coded = _convolutional_encode_K7_g133_g171(bits)
coded = _puncture(coded, coding)
# 2. Interleave + map to constellation
interleaved = _wifi_interleave(coded, n_data_subcarriers, mod)
symbols = _constellation_map(interleaved, mod)
# 3. Build OFDM symbols (insert pilots, IFFT, CP)
ofdm_syms = []
for chunk in _chunks(symbols, n_data_subcarriers):
freq_grid = torch.zeros(nfft, dtype=torch.complex64)
# Place data + pilots per 802.11a subcarrier mapping
freq_grid = _place_subcarriers(chunk, _pilots(rng), freq_grid)
time_sym = torch.fft.ifft(torch.fft.ifftshift(freq_grid)) * nfft
# Add cyclic prefix
full = torch.cat([time_sym[-cp_length:], time_sym])
ofdm_syms.append(full)
# 4. Prepend STF + LTF + SIGNAL field
preamble = _wifi_preamble() # short + long training, SIGNAL field
iq_native = torch.cat([preamble] + ofdm_syms)
# 5. Resample 20 MSps → sample_rate
native_rate = bw # 20 MHz or 10 MHz
iq = _resample(iq_native, native_rate=native_rate, target_rate=sample_rate)
iq = _trim_or_pad(iq, target_len=int(round(sample_rate * duration_s)))
return Signal(iq=iq, metadata=SignalMetadata(bandwidth_hz=16.6e6 if bw == 20e6 else 8.3e6, ...))
Reference. IEEE 802.11-2020 §17 (OFDM PHY). gr-ieee802-11 (GPL) cross-check.
See Also¶
Emitter Algorithms: overview and cross-family invariants.
Signal Catalog: browsable family list with parameter ranges.
References¶
Wi-Fi 802.11a/g/p and Zigbee 802.15.4 PHY chains are public specs; the framework re-implements each from the canonical IEEE document and cross-checks the result against the gr-ieee802-* GNU Radio reference implementations.
IEEE Std 802.11-2020, IEEE Standard for Information Technology - Telecommunications and Information Exchange between Systems Local and Metropolitan Area Networks - Specific Requirements - Part 11: Wireless LAN Medium Access Control (MAC) and Physical Layer (PHY) Specifications. IEEE, 2020. (§17 OFDM PHY: 64-point IFFT, 48 data + 4 pilot subcarriers, 1/4 cyclic prefix, 8 data rates; scrambler seed 0x5d, K=7 g133 / g171 convolutional code, puncturing, interleaver)
IEEE Std 802.11p-2010, Amendment 6: Wireless Access in Vehicular Environments. IEEE, 2010. (10 MHz V2X variant; identical OFDM structure with halved subcarrier spacing)
IEEE Std 802.15.4-2020, IEEE Standard for Low-Rate Wireless Networks. IEEE, 2020. (§10.2 OQPSK PHY at 2.4 GHz: 2 Mchip/s, 32-chip PN per 4-bit symbol per Table 73, half-sine pulse shaping per §10.2.6, channels 11…26 at 5 MHz spacing)
Bloessl, B. et al. gr-ieee802-11: An IEEE 802.11 a/g/p OFDM Receiver for GNU Radio, ACM SRIF, 2013. https://github.com/bastibl/gr-ieee802-11. (Reference encoder / decoder used for round-trip cross-checks)
Bloessl, B. et al. gr-ieee802-15-4: An IEEE 802.15.4 transceiver for GNU Radio. https://github.com/bastibl/gr-ieee802-15-4. (Reference encoder / decoder for the Zigbee cross-check path)