OMNeT++ Veins & Artery: Parity, Translation, and Performance Architecture
This document establishes the exact mathematical, architectural, and algorithmic correspondence between the C++ implementation of OMNeT++ / Veins / Artery and the high-performance Rust implementation in RustV2XSimulator.
1. Architectural Motivation & Academic Provenance
Vehicular network research published in peer-reviewed journals demands rigorous traceability and academic rigour relative to established gold-standard simulators.
In the open-source community:
- Veins (Sommer, Dressler, Eckhoff) is the gold standard for IEEE 802.11p (DSRC) physical and MAC layers in OMNeT++.
- Artery (Riebl et al.) integrates Veins with the Vanetza protocol stack to model European ETSI C-ITS (ITS-G5).
While OMNeT++ provides high architectural fidelity, its single-threaded event loop, heavy C++ heap allocations (new cMessage), virtual method dispatch, and repeated calculation of high-degree polynomials incur severe runtime bottlenecks when scaling to thousands of vehicles.
RustV2XSimulator translates the exact mathematical and state-machine behavior of Veins and Artery into idiomatic, zero-allocation, lock-free Rust, maintaining numerical parity while delivering a 10x to 100x wall-clock execution speedup.
2. File-by-File Module Correspondence
The table below maps the original C++ classes in artery/extern/veins to their translated equivalents in rustv2xsimulator:
| OMNeT++ Veins / Artery C++ Source | Rust Module in rustv2xsimulator |
Role & Implemented Specification |
|---|---|---|
veins/modules/utility/Consts80211p.h |
src/phy/consts_80211p.rs |
Timing parameters (\(T_{\text{sym}}\), SIFS, Slot), 8 MCS bitrates, PLCP frame lengths, FCC channel frequencies |
veins/modules/phy/NistErrorRate.cc / .h |
src/phy/nist_error_rate.rs |
Exact NIST WiFi error model: raw BER (BPSK/QPSK/QAM) + convolutional code error bounds + high-speed LUT |
veins/modules/phy/Decider80211p.cc / .h |
src/phy/decider_80211p.rs |
Sensitivity verification, PLCP header decoding, MPDU decoding, and noise vs. collision classification |
veins/modules/mac/ieee80211p/Mac1609_4.cc / .h |
src/mac/edca.rs |
4-channel EDCA contention (AC_VO, AC_VI, AC_BE, AC_BK), internal contention resolution, backoff freeze/resume |
veins/modules/mac/ieee80211p/Mac1609_4.cc (switching) |
src/mac/channel_switching.rs |
IEEE 1609.4 alternating 50 ms CCH / SCH cycles and 4 ms guard intervals |
veins/modules/analogueModel/BreakpointPathlossModel.cc |
src/phy/path_loss.rs |
Dual-Slope Log-Distance model with \(d_{\text{break}} = 120\,\text{m}\) and log-normal shadow fading |
veins/modules/analogueModel/SimpleObstacleShadowing.cc |
src/phy/knife_edge.rs |
Fresnel knife-edge obstacle diffraction around 2D building polygons |
artery/src/artery/networking/ & Vanetza |
RustFlexstack |
ETSI C-ITS protocol stack: GeoNetworking (EN 302 636-4-1), BTP, CA Basic Service (CAM), DCC FSM/LIMERIC, TS 103 097 security |
3. Physical Layer Parity & NIST Error Model
3.1 Raw Modulation Bit Error Rate (BER)
For a received linear signal-to-noise ratio \(\gamma = \text{SNR}\), the raw (uncoded) bit error rate is evaluated identically to NistErrorRate.cc:
- BPSK:
$\(P_{b, \text{BPSK}}(\gamma) = \frac{1}{2} \text{erfc}\left(\sqrt{\gamma}\right)\)$
- QPSK:
$\(P_{b, \text{QPSK}}(\gamma) = \frac{1}{2} \text{erfc}\left(\sqrt{\frac{\gamma}{2}}\right)\)$
- 16-QAM:
$\(P_{b, \text{16-QAM}}(\gamma) = \frac{3}{8} \text{erfc}\left(\sqrt{\frac{\gamma}{10}}\right)\)$
- 64-QAM:
$\(P_{b, \text{64-QAM}}(\gamma) = \frac{7}{24} \text{erfc}\left(\sqrt{\frac{\gamma}{42}}\right)\)$
3.2 Coded Error Bounding (Punctured Convolutional Codes)
Forward Error Correction (FEC) uses standard rate \(1/2\) constraint length \(k=7\) convolutional code, punctured to rates \(2/3\) and \(3/4\). With Bhattacharyya distance parameter \(D = \sqrt{4 p (1 - p)}\), where \(p\) is the raw BER, the bit error probability after Viterbi decoding \(P_e\) is bounded by:
Code Rate 1/2 (\(b=1\)):
Code Rate 2/3 (\(b=2\)):
Code Rate 3/4 (\(b=3\)):
The chunk success rate for a field of \(N_{\text{bits}}\) is:
3.3 Two-Stage Frame Decoding (Veins Decider80211p)
When an incoming air frame arrives, decoding follows a two-stage process:
- PLCP Signal Header:
- Length: \(N_{\text{header}} = 24\,\text{bits}\)
- Transmitted at 3 Mbps (MCS 0, BPSK 1/2).
- If header decoding fails, the packet is discarded immediately.
- MPDU Data Field:
- Length: \(N_{\text{data}} = 16\,(\text{SERVICE}) + 8 \times L_{\text{payload}} + 6\,(\text{TAIL})\,\text{bits}\).
- Transmitted at the active payload MCS (default: 6 Mbps, QPSK 1/2).
- Collision vs. Attenuation Attribution:
- If a failure occurs under pure noise (\(SNR\)), the packet is classified as attenuation drop (
is_collision: false). - If the packet would have succeeded under pure noise (\(SNR\)) but failed due to interference (\(SINR\)), it is classified as a collision (
is_collision: true).
4. MAC Layer Parity & EDCA Contention
4.1 Access Category Parameterization
Per IEEE 802.11p / IEEE 1609.4 Table 9-1, four EDCA priority queues compete with prioritized timings:
| Access Category | Service Type | AIFSN | \(\text{AIFS} = \text{SIFS} + \text{AIFSN} \times \text{Slot}\) | \(CW_{\min}\) | \(CW_{\max}\) |
|---|---|---|---|---|---|
| AC_VO (Voice/Emergency) | DENM / High-priority safety | 2 | \(32 + 2 \times 13 = 58\,\mu\text{s}\) | 3 | 7 |
| AC_VI (Video) | Low-priority safety | 3 | \(32 + 3 \times 13 = 71\,\mu\text{s}\) | 7 | 15 |
| AC_BE (Best Effort) | Periodic CAM | 6 | \(32 + 6 \times 13 = 110\,\mu\text{s}\) | 15 | 1023 |
| AC_BK (Background) | Non-safety telematics | 9 | \(32 + 9 \times 13 = 149\,\mu\text{s}\) | 15 | 1023 |
4.2 Multi-Channel Switching (IEEE 1609.4)
In multi-channel configurations (MultiChannelMode::AlternatingSwitching), the radio coordinator enforces:
- 50 ms Cycle Period: Alternates between CCH (channel 178, 5.89 GHz) and SCH (channels 172..184).
- 4 ms Guard Interval: Enforced at the beginning of each 50 ms cycle. Transmissions are deferred until the guard interval elapses, matching
SWITCHING_INTERVAL_11PandGUARD_INTERVAL_11Pin VeinsConsts80211p.h.
5. Performance Engineering: Why Rust is 10x–100x Faster
OMNeT++ simulation runs often take hours or days for large vehicular networks. RustV2XSimulator addresses each root cause of OMNeT++ overhead:
graph TD
subgraph OmnetBottlenecks ["OMNeT++ / Veins Bottlenecks"]
A[Heap Allocations: new cMessage / new AirFrame] --> B[Dynamic Virtual Dispatch vtables]
B --> C[Single-Threaded Event Loop]
C --> D[Repeated pow D, 26 Polynomial Math]
end
subgraph RustOptimizations ["RustV2XSimulator Optimizations"]
E[Zero-Allocation Stack/Pooled Events] --> F[Static Monomorphic Trait Dispatch]
F --> G[Rayon Parallel Broadcast & k-d Tree Spatial Index]
G --> H[Precomputed NistLut 2ns Constant-Time Lookup]
end
D -.->|10x - 100x Speedup| E
- Precomputed NIST Error Rate LUT (
NistLut): - In OMNeT++, every air frame chunk evaluates chains of
std::pow()andstd::erfc(), taking ~250 ns per evaluation. -
RustV2XSimulator builds a static, cache-aligned Look-Up Table (
NistLut) covering \(-5.0\,\text{dB}\) to \(+30.0\,\text{dB}\) in \(0.1\,\text{dB}\) increments. Evaluation uses branch-free index calculation with linear interpolation, executing in ~2 nanoseconds (>100x faster math). -
\(O(\log N)\) Spatial Filtering via 2D k-d Tree:
- Veins uses
BaseConnectionManagerwith coarse grid cells or \(O(N^2)\) distance loops. -
RustV2XSimulator uses a 2D k-d tree with Rayon data parallelism, reducing candidate receiver queries from \(O(N)\) to \(O(\log N + k)\) across threads.
-
Zero-Allocation Discrete-Event Queue:
- OMNeT++ allocates every message on the heap (
new cMessage(),delete cMessage()). -
RustV2XSimulator passes values by value using compact stack structs (
EventPayload), entirely avoiding heap allocation in the critical inner event loop. -
Continuous 64-Bit Integer Ticks (
SimTime): - Avoids OMNeT++'s big-integer fixed-point conversions while preserving exact picosecond and microsecond numerical reproducibility.
6. Verification and Parity Test Suite
To guarantee that the Rust implementation does not deviate from published simulators, the repository includes automated verification suites:
-
ns-3 Physical Parity Test (
tests/ns3_phy_parity_test.rs): Evaluates Packet Delivery Ratio \(PDR(d)\) in 10-meter bins from 0 to 800 meters against the ns-3 v3.42 gold standard. Asserts \(\text{MAE} \le 0.04\). -
Analytical vs. LUT Parity Test (
src/phy/nist_error_rate.rs): Verifies that fast LUT lookups match the exact analytical polynomials within \(\epsilon \le 0.02\). -
Decider Collision Isolation Test (
src/phy/decider_80211p.rs): Confirms that frames corrupted by concurrent interferers are correctly isolated as collisions, exactly reproducing Veins' collision counter behavior.