Tafel I
LIBELLULA
Oliver Hockenhull  ·  OhMedia / Moksha  ·  Sooke, BC, Canada
Synthesizable Verilog-2001  ·  Bio-inspired neuromorphic RTL  ·  v27, October 2026
15 modules  ·  42 core benches + bit-exact detector replays  ·  Measured on public event-camera data
§0
Work Statement

The subject

is the dragonfly’s visual interception reflex — a neural circuit that has computed predictive motion since the Carboniferous period. Its medium is synthesizable Verilog RTL. The work has two parts. The first is a motion-prediction core: given a stream of events, it produces a coordinate where a moving object will be, five clock cycles after the event that triggered it. The second, built on the same blocks, is the dragonfly’s actual task: a detector for tiny moving targets against a quiet background, measured on public event-camera recordings of drones.

Neither part interprets. Neither learns. They measure, delay, correlate, inhibit and predict through fixed pipelines. Determinism is the work’s central property.

The biological model — the Hassenstein-Reichardt correlator, the T4/T5 dendritic mechanism, the small-target motion detector neurons of the dragonfly lobula — is not metaphor. It is the specification. The distance between the dragonfly’s optic lobe and this RTL is a translation, not an interpretation.

The work exists in three simultaneous registers. As engineering: a verified hardware core and a detector that exists, bit for bit, as Python, as fixed-point C, and as Verilog. As biology: a named circuit carried into logic without a learned weight anywhere in it.

§1
Source Material

The biological model

The dragonfly

The dragonfly’s aerial hunting strategy is predictive. It computes an intercept. Flight paths recorded in laboratory conditions are consistent with a constant-bearing, decreasing-range pursuit geometry — the geometry of prediction rather than reaction. The neural substrate responsible, target-selective descending neurons (TSDNs), projects from the optic lobe directly to flight motor circuits. Observation, computation, and action are one continuous process. Before pursuit comes detection: small-target motion detector (STMD) neurons in the lobula respond to a tiny dark object moving against clutter and to little else, and they do it from a perch, with the eye still.

The Hassenstein-Reichardt detector, 1956

Hassenstein and Reichardt derived a model of directional motion detection from purely behavioural experiments on walking beetles. No electrophysiology. A logical argument from stimulus to response. The model specifies: delay the signal from one photoreceptor, multiply it with the instantaneous output of an adjacent one, subtract the mirror-symmetric subunit. The result is direction-selective. Confirmed without modification in electrophysiology decades later. It remains the governing framework.

T4 and T5 neurons

T4 neurons (ON edges) and T5 neurons (OFF edges) in the Drosophila optic lobe each come in four subtypes tuned to one of four cardinal directions. Directional sharpness arises from a dual mechanism on the same dendritic tree: preferred-direction enhancement via GluCl-α receptors at the dendritic tips, null-direction suppression via GABA-A receptors at the base. Mi9, Mi1, and Mi4 provide excitatory and inhibitory inputs at mapped spatial locations. The geometry of the dendrite performs the computation. No learning. No weights. Fixed physics.

The elementary small-target motion detector

Wiederman, O’Carroll and Shoemaker (2008) proposed a model for STMD neurons that needs no explicit size template: adapt each photoreceptor, split the signal into ON and OFF channels, delay one and correlate it with the other at the same location (a dark target passing a point produces OFF then ON), and inhibit each channel with its spatial surround. Small moving targets survive this chain; wide-field motion and static texture do not. The detector in §2 is a per-event implementation of that chain for an event camera, with a tracker and two adaptive stages added for real recordings.

Architecture as translation

RPhotoreceptors R1–R6 — polarity-coded luminance change→aer_rx
LLamina monopolar cells — contrast encoding, buffering→aer_rx (REQ/ACK)
MiMedulla intrinsic neurons (Mi1, Mi4, Mi9) — temporal filtering, ON/OFF separation→lif_tile_tmux
DLSpatial offset & temporal delay — inter-column delay lattice→delay_lattice_rb
T4T4/T5 direction-selective multiplication — preferred-direction enhancement + null-direction suppression→reichardt_ds
LPLobula plate interneurons — opponent subtraction, noise gating→burst_gate + conf_gate
HSTangential cells / TSDN — wide-field integration, predictive pursuit vector→ab_predictor
PRPhotoreceptor / lamina adaptation — gain control under glare and flicker→stmd_frontend
ESESTMD — OFF/ON correlation, centre-surround inhibition→stmd_backend
STSTMD / TSDN — selection of one small target, tracked over time→stmd_backend (tracker)
Hassenstein B. & Reichardt W. — Zeitschrift für Naturforschung, 1956
Borst A. — T4/T5 circuit characterisation, Max Planck Institute of Neurobiology, 2009–2022
Wiederman S.D., O’Carroll D.C., Shoemaker P.A. — A model for the detection of moving targets in visual clutter inspired by insect physiology, PLoS ONE, 2008
Wiederman S.D. et al. — Predictive gain modulation in dragonfly target-tracking neurons, eNeuro, 2024
Fabian J.M. et al. — Spike bursting in a dragonfly target-detecting neuron, Sci. Rep., 2021
Mauss A.S. et al. — Neural circuit to integrate opposing motions in the visual field, Cell, 2015
§2
Small-target detector · v24–v27

Measured on real event-camera data

The detector takes the event stream of a fixed DVS camera and labels, event by event, which events belong to a small moving target. It is causal and per-event: no frames, no batching, no learned weights. It exists in three forms that agree with one another: a Python reference model, a fixed-point C port with documented bit widths, and two Verilog-2001 modules. Chained, the Verilog reproduces the C model on 88 000 replayed events with zero mismatches on the candidate flag, zero on the label, and the same count of confirmed-track records on every scene.

Pipeline — click any stage

01activity filter
02habituation
03glare · noise
04ESTMD
05centre-surround
06tracker pool
07labelling

Background-activity filter — stmd_frontend

An event passes if enough of its eight neighbours fired within a window (80 ms in the selected configuration). The same idea as the core’s LIF filter, kept as per-pixel timestamps.

16-bit ms timestamps · stale sweep expires entries older than 4095 ms · window shortens under noise

Flicker habituation — stmd_frontend

A leaky per-pixel count of polarity reversals. Pixels that keep reversing (foliage, water, flicker) are suppressed. Insect lamina adaptation, in integer arithmetic.

Q12.4 count · 128-entry decay table indexed by a shift · no per-event division

Glare and noise adaptation — stmd_frontend

A slow per-region event-rate estimate mutes regions that stay hot (sun glare on the sensor). A global background-rate estimate shortens the activity-filter window, demands two supporting neighbours and raises the candidate threshold when the sensor is noisy. Removing glare adaptation drops held-out IoU from 0.76 to 0.55.

16×16 px regions, τ 4 s · 64-entry rate tables indexed by a shift

ESTMD polarity correlation — stmd_backend

The Wiederman OFF-then-ON signature: an event is weighted up if the opposite polarity fired at the same pixel 3–100 ms earlier. Implemented and verified; in every configuration searched it contributes under one percent to the result, and switching it off saves a third of the state memory. A finding, not a design choice.

per-polarity timestamps · 2 × 17 bits per pixel

Centre-surround inhibition — stmd_backend

Responses accumulate in 3 px cells. A candidate is declared when the 3×3 centre exceeds the inhibited 9×9 ring of responses and of raw activity. This stage and the tracker carry the result.

Q12.4 accumulators with telescoping decay · 81 cell reads per response event · integer score test, 64-bit intermediates

Tracker pool — stmd_backend

Eight gated tracks with an α–β position/velocity update, confirmation by hits, time and displacement, and a stationarity check that stops a track from labelling once it has stopped moving. The core’s predictor, re-used.

Q8 px positions · Q16 px/ms velocities · one sequential division per track at most every 50 ms

Labelling — stmd_backend

An event is a target event if it lies within a velocity-extended radius of a confirmed, moving track. The output is the per-event label and a record for every update of a confirmed track.

88 000 replayed events · 0 label mismatches against the C reference

Results — EV-UAV dataset, held-out split

EV-UAV is a public dataset of tiny drones recorded with a static DAVIS346 event camera, with per-event labels (arXiv 2506.23575). Scores use a port of the dataset authors’ own evaluator. The held-out split is twenty train sequences never used for tuning, scored once per variant; brackets are 95 % bootstrap intervals over sequences. The dataset’s test split has been untouched since v25.

VariantIoUPd (per 50 ms)Targets detectedWindow coverageFalse tracks / min
v26 segmentation point0.764 [0.68–0.84]0.888 [0.84–0.94]0.940.8020.6
v27 segmentation + false-track penalty0.807 [0.73–0.88]0.837 [0.75–0.92]0.880.744.5
v26 alarm point (2/min budget)0.664 [0.55–0.79]0.745 [0.62–0.87]0.800.653.0
v27 point, ESTMD stage off0.8090.8340.920.724.1
EV-UAV test split, scored once (v25)IoURecallPd
LIBELLULA-STMD v25 (tuned on train + val)0.8130.9340.902
EV-SpSegNet, the dataset authors’ trained network (4 M weights, whole-clip, GPU)0.5520.6500.775

What holds up: centre-surround inhibition, the tracker, and glare adaptation. What does not: dense low-light sensor noise, where no configuration keeps both a low false-track rate and useful coverage. The v27 point trades 0.05 Pd for four and a half times fewer false tracks; only the false-track change is outside the intervals.

Hardware

Front end — stmd_frontend.v
activity filter · habituation · glare · noise
Replay vs C model88 000 events, 0 mismatches
Verilator lint0 warnings
Yosys generic, 32×327 085 cells · 118 FF
Per-pixel state51 bits
Bit-exact · reset + stale sweeps
Back end — stmd_backend.v
ESTMD · cells · surround · tracker · labelling
Replay vs C model0 label · 0 candidate mismatches
Track records vs Cidentical counts, 4 scenes
Yosys generic, 32×3282 247 cells · 763 FF
Worst case per event~265 cycles
Arithmetic at C widths, not yet narrowed
State at 346×260
1.03 MB  ·  654 kB without ESTMD
Divisions per event
none  ·  one sequential divider per velocity update
Timestamps
16-bit ms, expiry rule + idle-cycle sweep; replays fail without it (387 / 33 mismatches)
Camera assumption
fixed mount; moving platforms are out of scope

Status

Shown
✓ Python, C and Verilog agree bit for bit on replayed events
✓ Scored on public recordings with the dataset authors’ evaluator; held-out protocol, intervals, ablations
✓ Every number comes from a committed script with stored output; CI regenerates the RTL vectors
✓ Stale-timestamp sweeps proven load-bearing by a negative test that runs in CI
Not yet
○ A live camera: every result is replayed recordings and Icarus simulation
○ Timing, placement or power for the detector modules
○ Ego-motion compensation; the model assumes a quiet background
○ Any dataset beyond EV-UAV
§3
Verification

Motion-prediction core

FPGA implementation — out-of-context results

Out-of-context implementation was completed on Xilinx UltraScale+ VU9P at 200 MHz for both the bare core and an AXI-integrated evaluation shell. Both builds achieved positive setup and hold slack with zero routing errors. These are out-of-context results: materially stronger than simulation-only evidence, but not equivalent to full board-level timing closure. The reports are in the evaluator package; the public repository holds the simulation suite only.

Build A — Bare Core
libellula_top
LUTs1,008
Registers403
BRAM0
DSPs2
WNS+0.383 ns
Route errors0
Timing met · Fully routed
Build B — AXI Evaluation Shell
libellula_axi_eval_top
LUTs995
Registers445
BRAM0
DSPs2
WNS+0.338 ns
WHS+0.042 ns
Route errors0
Timing met · Fully routed
Target
Xilinx UltraScale+ VU9P  ·  xcvu9p-flgb2104-2L-e
Toolchain
Vivado 2025.2
Clock target
200 MHz (5.000 ns)

Simulation validation — 38 core benches, 4 AXI benches

ClaimSpecificationResultTestbench
Latency≤ 5 cycles @ 200 MHz, every emitted prediction5 cycles · 25 nstb_latency · tb_latency_default
Output cadenceCharacterisation, not assertedfirst prediction after 32 events; ~1 per 17 events for one slow targettb_latency_default
Accuracy±2 px, constant velocity 1 px/eventmean 0.73 px, max 2 px; beats echotb_px_bound
Accuracy outside the claim2–3 px/event; 300 events/smax 3–4 px; within ±2 but no better than echomake pxbound-char
Throughput1 Meps, zero drops2000 / 2000 ACK (ACK=REQ by construction)tb_aer_throughput_1meps
Power scalingActivity-proportional toggle countLow/high confirmedtb_power_lo · tb_power_hi
8-direction motionCardinal + diagonalAll 8 axes exercisedtb_reichardt_ds
DeterminismTwo identically stimulated cores bit-exactZero divergencetb_deterministic_replay
Hostile conditionsReset mid-stream, stuck REQ, 50 000-event random stressNo leaks, no X, deterministic re-entrytb_hostile/
Full suite42 benches + lintall PASS, 0 Verilator warnings, CI on every pushmake test axi lint

Comparative benchmark — synthetic scenes

A harness runs the core against three software baselines (Kalman, event-motion heuristic, normalised-LMS velocity regressor) on six synthetic scenarios. The software baselines are more accurate on clean scenes (0.5–1 px against 2.4–4.5 px); the core is ahead on the distractor-crossing and noise-burst scenes. Baseline latencies are nominal constants, all stimulus is synthetic, and the harness is not gated in CI. An earlier version of this harness paired predictions with the wrong events and reported the core as failing; v23 corrected it.

Status

Validated
✓ Functionally validated in simulation, lint clean, CI green
✓ Synthesized in Vivado 2025.2
✓ Out-of-context implementation on UltraScale+ VU9P at 200 MHz
✓ Positive setup and hold slack, zero routing errors
Not claimed
○ Board-level validation or a sensor in the loop
○ System-level timing closure in integrated fabric
○ A power figure: toggle counts exist, a power report does not
○ Prediction accuracy beyond 1 px/event, or any accuracy at 300 events/s better than echoing the input
§4
Structure

Core processing pipeline

AER → LIF tile → 8-direction delay lattice → Reichardt direction selector → burst gate → α–β predictor → confidence gate. Fixed feed-forward architecture, unchanged since v22. Click any stage to expand.

01aer_rx
02lif_tile_tmux
03delay_lattice_rb
04reichardt_ds
05burst_gate
06ab_predictor
07conf_gate

aer_rx — Address-Event Receiver

Level-sensitive, combinational receiver: every clock cycle with REQ high is one event and ACK mirrors REQ. It is not a 4-phase handshake; a bridge is required for a 4-phase source. Sensor-agnostic at the address-event level (Prophesee, iniVation, Samsung formats via the AXI4-Stream bridge).

Validated: REQ=2000, ACK=2000 at 1 Meps, zero drops (ACK=REQ by construction)

lif_tile_tmux — Leaky Integrate-and-Fire Array

Time-multiplexed, 14-bit. Filters incoherent events. Analogue to temporal filtering in medulla intrinsic neurons Mi1, Mi4, Mi9.

14-bit accumulator · time-multiplexed · ON/OFF polarity preserved · leak rate configurable

delay_lattice_rb — 8-Direction Retinotopic Delay Lattice

Ring-buffer delay lattice across cardinal (E, W, N, S) and diagonal (NE, NW, SE, SW) axes. Diagonal contributions scaled for geometric equivalence approximation.

8-direction retinotopic · ring buffer · diagonal scaling applied

reichardt_ds — Reichardt Elementary Motion Detector

Implements both preferred-direction enhancement and null-direction suppression — direct analogue of T4/T5 dendritic computation. All eight axes exercised in tb_reichardt_ds.

Dual mechanism · leaky integration of temporal gradients into directional motion vectors

burst_gate — Event Density Filter

Hysteretic density thresholding. TH_OPEN=3, TH_CLOSE=1. Only sustained coherent activity propagates to the predictor.

WINDOW=16 · TH_OPEN=3 · TH_CLOSE=1

ab_predictor — α–β Continuous-Time Predictor

Q8.8 fixed-point. Forward extrapolation: p̂ = p + v·Δt. Outlier rejection above OUTLIER_TH=128; predictor coasts on current velocity estimate. Velocity is zeroed on direction reversal.

Q8.8 fixed-point · ≤ ±2 px at 1 px/event · Δt selectable · outlier rejection

conf_gate — Confidence Scoring

Reliability score from event rate and direction magnitude across all eight axes. Gates output with pred_valid strobe. Downstream: (x̂, ŷ, conf).

confidence = f(event rate × direction magnitude) · pred_valid strobe

RTL modules

aer_rxLevel-sensitive AER receiver+

ACK mirrors REQ within the same cycle; one event per cycle with REQ high. Validated at ≥106 events/s with zero drops. Behavioural shell for FPGA bring-up.

lif_tile_tmuxTime-multiplexed LIF array, 14-bit+

Single accumulator shared across spatial array via time-multiplexing. 14-bit precision. Configurable leak rate. Filters sparse or incoherent events.

delay_lattice_rb8-direction retinotopic delay lattice+

Ring-buffer delay lattice, cardinal and diagonal axes. Diagonal contributions scaled for geometric equivalence. Provides temporal gradient structure for reichardt_ds.

reichardt_dsReichardt elementary motion detector+

Preferred-direction enhancement and null-direction suppression. Direct computational analogue of T4/T5 dendritic physics. All eight axes in tb_reichardt_ds.

burst_gateEvent density filter with hysteresis+

TH_OPEN=3, TH_CLOSE=1. Reduces chatter at threshold boundary. Only sustained activity propagates to the predictor.

tracker_poolN-target tracker pool+

L1-distance routing of measurements to tracks, coast counter for missed updates.

ab_predictorα–β predictor, Q8.8 fixed-point+

Trajectory extrapolation in continuous time. Outlier rejection: residuals above OUTLIER_TH=128 cause the predictor to coast on current velocity. ≤ ±2 px at 1 px/event verified against the next position, not the current one.

conf_gateConfidence scoring, rate × direction magnitude+

Reliability score across all eight axes. Downstream receives (x̂, ŷ, conf) only on pred_valid strobe.

axi4s_to_aer · axi4s_pred_wrapper · libellula_socAXI4-Stream bridges and SoC wrapper+

200 MHz AXI4-Stream on both event input and prediction output, 48-bit TDATA packing, back-pressure handled; four benches, 111 assertions.

stmd_frontend · stmd_backendSmall-target detector (§2)+

Per-pixel front end and cell/tracker back end, bit-exact against the fixed-point C reference. Verified by replay of C-generated vectors, lint, and a negative test for the stale sweeps.

Key parameters

ParameterDefaultDescription
XW / YW10Coordinate width, bits
AW8LIF address width
DW6Delay lattice depth, bits
PW16Predictor output width, bits
WINDOW16Burst gate counting window
TH_OPEN3Events to open burst gate
TH_CLOSE1Events to hold gate open
OUTLIER_TH128Residual threshold; predictor coasts above this

Build & reproducibility

# Core: full suite, AXI layer, lint
make -C sim test axi lint
make -C sim latency latency-default pxbound meps # claim benches

# Detector: RTL lint, bit-exact replays, negative sweep test
make -C sim lint-stmd-fe stmd_fe stmd_pipe stmd_sweep_neg

# Detector: scores (EV-UAV data not included)
python3 stmd/scripts/final_eval_v27.py path/to/EV-UAV/train
python3 stmd/scripts/c_equivalence.py stmd/configs/v26_segmentation.json path/to/EV-UAV/train --only stmd/splits/holdout_v26.txt
§5
Context

Relation to adjacent systems

Event-based sensors

LIBELLULA requires DVS cameras. It operates on asynchronous events — one per pixel per polarity change, timestamped to the microsecond. Frame-based cameras cannot provide the temporal precision required by the delay lattice, the Reichardt correlator, or the ESTMD correlation. This is a property of the architecture, not a limitation of the implementation. The detector further assumes a fixed camera: a moving platform floods the stream with background events and the static-scene assumptions fail together. Ego-motion compensation is a separate module and does not exist here.

Relation to AI-based vision

Neural networks operating on event-camera streams batch or accumulate events before inference. Even purpose-built SNN inference takes on the order of 100 µs to several milliseconds to produce a position estimate. LIBELLULA produces a forward-extrapolated coordinate 25 ns after the event that triggers it, and the detector labels each event as it arrives. These are complementary operations: a direction-confirmed, cheap, always-on signal that tells a heavier system where to look, rather than raw accumulated events.

LIBELLULA
Event-driven
detection and prediction
(x̂, ŷ, conf)
25 ns per emitted prediction
→
AI / Neural Network
Classification
context assessment
decision logic
1–50 ms
→
Actuator / Control
Motion control
gimbal slew
downstream logic
hardware latency

Comparative context

Published system-level figures for the comparison rows, as reported by their authors; the LIBELLULA row is from simulation and out-of-context implementation. The core’s latency is per emitted prediction; output cadence depends on scene event density. No power measurement exists for LIBELLULA.

SystemCore latencyForward forecastPower
DJI / Skydio commercialFrame CNN on ARM + GPU20–40 msReactive only3–8 W
ETH-UZH event-camera avoidanceScience Robotics, 20203.5 msNone~10 W
FPGA event-vision acceleratorBonazzi et al., arXiv 2024~2 msNone3–5 W
EV-SpSegNetEV-UAV authors’ network, 2025whole clip, GPUNoneGPU
LIBELLULA — core logicSynthesizable RTL · 200 MHz · UltraScale+ VU9P (OOC)25 ns (5 cycles)Δt selectable; ±2 px shown at 1 px/eventnot measured
§6
Distribution

Repository & evaluator package

The public repository (GPL v3; commercial licence by arrangement) holds the RTL, the simulation suite, the comparative benchmark harness, the detector in all three forms, its configurations, held-out split, scored results with intervals, search records, and the CI that re-checks all of it on every push. The EV-UAV data is not included; it comes from the dataset authors.

▸ RTL source: 15 Verilog-2001 modules, core and detector
▸ 42 core and AXI testbenches, plus detector replays, lint and the negative sweep test
▸ Detector: Python reference, fixed-point C reference, RTL parameter and table generator
▸ Results with 95 % intervals, ablations, hardware budget, Yosys logs, C/Python equivalence
▸ Engineering overview, claims traceability, changelog v22–v27
▸ Evaluator package, by arrangement: Vivado synthesis and OOC implementation reports, Tcl flows, design checkpoints, SHA-256 manifest

Repository & contact

Technical engagement, a licence, or a camera to run it on can be arranged directly. The next step the work needs is a DVS on a bench; the repository is ready for it.

Oliver Hockenhull  ·  Sooke, BC, Canada
oliver.hockenhull@gmail.com

github.com/vertov/LIBELLULA