Drone Emitter Algorithms¶
Drone telemetry, control, and video-shell waveform synthesis.
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.
7. Drone telemetry / video shells¶
Family. drone. The proprietary OcuSync / Lightbridge headers and codes are not publicly specified; only spectral envelope and FHSS-OFDM time-frequency footprint are modelable. The recommended path is hybrid: synthetic shell + captured template at IQ sample level for visual realism.
Warning
Library alignment. Concepts / Emitters / Library Landscape currently designates the drone family as Captured-IQ only because no credible waveform synthesizer for OcuSync or Lightbridge has been identified. The synthetic OcuSync shell algorithm in §7.1 and §7.2 is a speculative draft written before that policy was set; do not implement it without re-running the library research and updating library-landscape.md.
The FPV analog video (§7.3), MAVLink telemetry (§7.4), and Crossfire / ExpressLRS (§7.5) sections are based on public protocols and are appropriate for independent implementation (see Tier 3 in library-landscape.md). They do not conflict with the playback-only designation.
7.1 OcuSync shell (DJI Phantom 4 / Mavic / Inspire)¶
Approach. OFDM building block (TorchSig-style) + custom FHSS scheduler matching observed OcuSync hop patterns.
def generate_ocusync_shell(*, class_label, sample_rate, duration_s, params, rng):
"""
class_label: "drone.ocusync.{phantom4_pro,mavic3,inspire2}.{rc,video}"
params:
bandwidth_hz: float # 10e6, 20e6, or 40e6
hop_rate_hz: float = 100 # OcuSync ~100 Hz hop rate
modulation: "ofdm" | "fhss-ofdm"
capture_template_path: str | None # optional captured replay overlay
"""
if params.get("capture_template_path"):
# Load real OcuSync capture; resample; mix with synthetic shell at α weight
return _hybrid_synth_capture(...)
# Pure synthetic: OFDM frames with scheduled frequency hops
hop_period_n = int(round(sample_rate / params["hop_rate_hz"]))
hop_centers = _draw_hop_sequence(params["bandwidth_hz"],
num_hops=int(duration_s * params["hop_rate_hz"]),
rng=rng)
iq = torch.zeros(int(round(sample_rate * duration_s)), dtype=torch.complex64)
for k, f_center in enumerate(hop_centers):
# Generate one OFDM frame at baseband
frame = _make_ofdm_frame(num_subcarriers=64, payload_bytes=64,
rate=params["bandwidth_hz"] / 4, rng=rng)
# Mix to f_center within scene
t = torch.arange(len(frame)) / sample_rate
frame_mixed = frame * torch.exp(1j * 2 * torch.pi * f_center * t)
start = k * hop_period_n
end = min(start + len(frame), len(iq))
iq[start:end] += frame_mixed[:end - start]
return Signal(iq=iq, metadata=SignalMetadata(bandwidth_hz=params["bandwidth_hz"], ...))
Reference datasets. DroneRF, RFUAV, CardRF for capture templates.
7.2 Lightbridge shell¶
Similar to OcuSync but narrower (8 / 10 MHz) and a different hop schedule. Same algorithmic skeleton with different parameter ranges.
7.3 FPV analog video (NTSC/PAL VSB)¶
def generate_fpv_analog(*, class_label, sample_rate, duration_s, params, rng):
"""
class_label: "drone.fpv.analog.{ntsc-m,pal-b}"
params:
video_pattern: "color_bars" | "noise" | "captured_path"
carrier_offset_hz: float = 0.0 # within scene
"""
if class_label == "drone.fpv.analog.ntsc-m":
line_rate = 15734.26 # Hz
bw_video = 4.2e6
bw_audio = 0.1e6
elif class_label == "drone.fpv.analog.pal-b":
line_rate = 15625.0
bw_video = 5.5e6
bw_audio = 0.1e6
# Generate composite video signal (color bars or noise as luma + chroma + sync)
composite = _build_composite_video(params["video_pattern"],
line_rate, sample_rate, duration_s, rng)
# VSB-AM modulate: shift to IF carrier, attenuate lower sideband
iq = _vsb_modulate(composite, sample_rate, lower_sideband_attenuation_db=-20)
return Signal(iq=iq, metadata=SignalMetadata(bandwidth_hz=bw_video + bw_audio, ...))
7.4 MAVLink telemetry¶
def generate_mavlink_telemetry(*, class_label, sample_rate, duration_s, params, rng):
"""
class_label: "drone.mavlink.fsk.{433,915}.{1k,4k,8k,57k6,250k}"
params:
baud_rate: int # 1200..250000
deviation_hz: float
message_type: "HEARTBEAT" | "ATTITUDE" | "GLOBAL_POSITION_INT" | random
cadence_hz: float = 1.0
"""
# Use pymavlink (LGPL) to encode bytes; we synthesize the FSK ourselves.
msg_bytes = _pymavlink_encode(params["message_type"], rng)
bits = _bytes_to_bits(msg_bytes)
samples_per_bit = sample_rate / params["baud_rate"]
nrz = torch.tensor([2 * b - 1 for b in bits])
upsampled = nrz.repeat_interleave(int(round(samples_per_bit)))
# FSK: instantaneous frequency = ±deviation_hz
f_inst = upsampled * params["deviation_hz"]
phase = torch.cumsum(f_inst, dim=0) * 2 * torch.pi / sample_rate
iq = torch.exp(1j * phase)
# Place at cadence_hz across duration
iq = _place_at_cadence(iq, params["cadence_hz"], duration_s, sample_rate, rng)
bw = 2 * (params["deviation_hz"] + params["baud_rate"] / 2) # Carson's rule
return Signal(iq=iq, metadata=SignalMetadata(bandwidth_hz=bw, ...))
7.5 TBS Crossfire / ExpressLRS¶
LoRa-like CSS + FHSS. Uses the LoRa CSS algorithm (§3) with hop scheduling on top.
See Also¶
Emitter Algorithms: overview and cross-family invariants.
Signal Catalog: browsable family list with parameter ranges.
References¶
OcuSync and Lightbridge are proprietary headers; the framework only models their FHSS-OFDM time-frequency footprint and recommends a hybrid synth + capture approach. The FPV analog video, MAVLink telemetry, and Crossfire / ExpressLRS paths follow the public specs.
ITU-R BT.470-7, Conventional television systems. International Telecommunication Union, 2005. (NTSC-M line rate 15734.26 Hz, video bandwidth 4.2 MHz; PAL-B line rate 15625 Hz, video bandwidth 5.5 MHz)
EIA RS-170A, Color Television Studio Picture Line Amplifier Output. Electronic Industries Alliance, 1977. (Composite NTSC luma + chroma + sync waveform used by
_build_composite_video)Carson, J. R. Notes on the Theory of Modulation, Proc. IRE, 10(1), 1922. (Carson’s-rule bandwidth approximation \(2(f_d + R_b/2)\) used by the MAVLink FSK path)
ArduPilot / PX4 contributors. MAVLink: Micro Air Vehicle Communication Protocol. https://mavlink.io/en/. (HEARTBEAT / ATTITUDE / GLOBAL_POSITION_INT message formats;
pymavlinkreference encoder)Allahham, M. S. et al. DroneRF dataset: A dataset of drones for RF-based detection, classification and identification, Data in Brief, 2019. https://doi.org/10.1016/j.dib.2019.103845. (Capture templates for OcuSync / Lightbridge shells)
Medaiyese, O. et al. Wavelet Transform-Assisted Adaptive Generative Adversarial Network for Drone Identification, Drones, 6(11), 2022 (CardRF / RFUAV reference). (Reference capture corpora cross-checked for hop schedules and spectral envelopes)
Semtech Corporation. AN1200.22 LoRa Modulation Basics, 2015. (TBS Crossfire / ExpressLRS reuses the LoRa CSS algorithm; primary citation lives on
emitter-iot.md)