Skip to content

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\)):

\[P_e^{(1/2)} = \frac{1}{2} \Big( 36 D^{10} + 211 D^{12} + 1404 D^{14} + 11633 D^{16} + 77433 D^{18} + 502690 D^{20} + 3322763 D^{22} + 21292910 D^{24} + 134365911 D^{26} \Big)\]

Code Rate 2/3 (\(b=2\)):

\[P_e^{(2/3)} = \frac{1}{4} \Big( 3 D^6 + 70 D^7 + 285 D^8 + 1276 D^9 + 6160 D^{10} + 27128 D^{11} + 117019 D^{12} + 498860 D^{13} + 2103891 D^{14} + 8784123 D^{15} \Big)\]

Code Rate 3/4 (\(b=3\)):

\[P_e^{(3/4)} = \frac{1}{6} \Big( 42 D^5 + 201 D^6 + 1492 D^7 + 10469 D^8 + 62935 D^9 + 379644 D^{10} + 2253373 D^{11} + 13073811 D^{12} + 75152755 D^{13} + 428005675 D^{14} \Big)\]

The chunk success rate for a field of \(N_{\text{bits}}\) is:

\[P_{\text{chunk success}} = \left(1 - \min(P_e, 1.0)\right)^{N_{\text{bits}}}\]

3.3 Two-Stage Frame Decoding (Veins Decider80211p)

When an incoming air frame arrives, decoding follows a two-stage process:

  1. PLCP Signal Header:
  2. Length: \(N_{\text{header}} = 24\,\text{bits}\)
  3. Transmitted at 3 Mbps (MCS 0, BPSK 1/2).
  4. If header decoding fails, the packet is discarded immediately.
  5. MPDU Data Field:
  6. Length: \(N_{\text{data}} = 16\,(\text{SERVICE}) + 8 \times L_{\text{payload}} + 6\,(\text{TAIL})\,\text{bits}\).
  7. Transmitted at the active payload MCS (default: 6 Mbps, QPSK 1/2).
  8. Collision vs. Attenuation Attribution:
  9. If a failure occurs under pure noise (\(SNR\)), the packet is classified as attenuation drop (is_collision: false).
  10. 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_11P and GUARD_INTERVAL_11P in Veins Consts80211p.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
  1. Precomputed NIST Error Rate LUT (NistLut):
  2. In OMNeT++, every air frame chunk evaluates chains of std::pow() and std::erfc(), taking ~250 ns per evaluation.
  3. 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).

  4. \(O(\log N)\) Spatial Filtering via 2D k-d Tree:

  5. Veins uses BaseConnectionManager with coarse grid cells or \(O(N^2)\) distance loops.
  6. 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.

  7. Zero-Allocation Discrete-Event Queue:

  8. OMNeT++ allocates every message on the heap (new cMessage(), delete cMessage()).
  9. RustV2XSimulator passes values by value using compact stack structs (EventPayload), entirely avoiding heap allocation in the critical inner event loop.

  10. Continuous 64-Bit Integer Ticks (SimTime):

  11. 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.