Initial commit
This commit is contained in:
12
.devcontainer/Dockerfile
Normal file
12
.devcontainer/Dockerfile
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
FROM debian:trixie-slim
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
sudo curl git ca-certificates \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Create non-root user matching Coder's expectations
|
||||||
|
RUN useradd -m -s /bin/bash coder \
|
||||||
|
&& echo "coder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
|
||||||
|
|
||||||
|
USER coder
|
||||||
|
WORKDIR /home/coder
|
||||||
29
.devcontainer/devcontainer.json
Normal file
29
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"name": "quic-ecs-dt",
|
||||||
|
"build": {
|
||||||
|
"dockerfile": "Dockerfile"
|
||||||
|
},
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/rust:1": {
|
||||||
|
"version": "latest",
|
||||||
|
"profile": "minimal"
|
||||||
|
},
|
||||||
|
"ghcr.io/devcontainers/features/python:1": {
|
||||||
|
"version": "os-provided"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"containerEnv": {
|
||||||
|
"RUST_LOG": "info",
|
||||||
|
"RUST_BACKTRACE": "1",
|
||||||
|
"VM_ENDPOINT": "http://your-server:8428",
|
||||||
|
"CM5_HOST": "192.168.1.x"
|
||||||
|
},
|
||||||
|
"forwardPorts": [3000, 8428, 4848],
|
||||||
|
"portsAttributes": {
|
||||||
|
"3000": { "label": "Grafana" },
|
||||||
|
"8428": { "label": "Victoria Metrics" },
|
||||||
|
"4848": { "label": "Quarto preview" }
|
||||||
|
},
|
||||||
|
"remoteUser": "coder",
|
||||||
|
"postCreateCommand": "bash .devcontainer/setup.sh"
|
||||||
|
}
|
||||||
37
.devcontainer/setup.sh
Normal file
37
.devcontainer/setup.sh
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# .devcontainer/setup.sh
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "=== Installing system deps ==="
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -y --no-install-recommends \
|
||||||
|
build-essential pkg-config libssl-dev \
|
||||||
|
texlive-latex-base texlive-latex-extra \
|
||||||
|
texlive-fonts-recommended texlive-bibtex-extra \
|
||||||
|
lmodern biber gcc-aarch64-linux-gnu
|
||||||
|
|
||||||
|
echo "=== Configuring Rust Target ==="
|
||||||
|
# Rust is already installed by the Devcontainer feature
|
||||||
|
rustup target add aarch64-unknown-linux-gnu
|
||||||
|
|
||||||
|
echo "=== Installing Quarto ==="
|
||||||
|
QUARTO_VER="1.8.0"
|
||||||
|
if ! command -v quarto &>/dev/null; then
|
||||||
|
curl -LO "https://github.com/quarto-dev/quarto-cli/releases/download/v${QUARTO_VER}/quarto-${QUARTO_VER}-linux-amd64.deb"
|
||||||
|
sudo dpkg -i "quarto-${QUARTO_VER}-linux-amd64.deb"
|
||||||
|
rm "quarto-${QUARTO_VER}-linux-amd64.deb"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "=== Installing Python deps ==="
|
||||||
|
# Python is installed by the Devcontainer feature
|
||||||
|
python3 -m venv "$HOME/.venv/quic_ecs"
|
||||||
|
source "$HOME/.venv/quic_ecs/bin/activate"
|
||||||
|
pip install --quiet -r requirements.txt
|
||||||
|
|
||||||
|
echo "=== First Cargo build ==="
|
||||||
|
cargo build --release 2>&1 | tail -5
|
||||||
|
|
||||||
|
echo "=== Quarto check ==="
|
||||||
|
quarto check
|
||||||
|
|
||||||
|
echo "=== Done — workspace ready ==="
|
||||||
29
.gitignore
vendored
Normal file
29
.gitignore
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# Rust
|
||||||
|
target/
|
||||||
|
Cargo.lock
|
||||||
|
|
||||||
|
# Quarto
|
||||||
|
/.quarto/
|
||||||
|
paper/_freeze/
|
||||||
|
paper/.quarto/
|
||||||
|
paper/index_files/
|
||||||
|
paper/index.tex
|
||||||
|
paper/index.pdf
|
||||||
|
paper/figures/
|
||||||
|
paper/*_cache
|
||||||
|
|
||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
.venv/
|
||||||
|
analysis/.venv/
|
||||||
|
|
||||||
|
# Data — raw CSVs committed, processed outputs not
|
||||||
|
data/**/*_processed.csv
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
# Coder / editor
|
||||||
|
.coder/logs/
|
||||||
3
Cargo.toml
Normal file
3
Cargo.toml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[workspace]
|
||||||
|
resolver = "3"
|
||||||
|
members = ["simulator", "substrate"]
|
||||||
45
Makefile
Normal file
45
Makefile
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# ============================================================
|
||||||
|
# quic_ecs_dt — top-level Makefile
|
||||||
|
# Targets:
|
||||||
|
# make render — build the paper PDF
|
||||||
|
# make preview — live-reload preview in browser
|
||||||
|
# make build — cargo build --release (native)
|
||||||
|
# make build-cm5 — cargo build --release (aarch64 cross)
|
||||||
|
# make clean — remove generated outputs
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
.PHONY: render preview build build-cm5 clean
|
||||||
|
|
||||||
|
VENV := $(HOME)/.venv/quic_ecs
|
||||||
|
PYTHON := $(VENV)/bin/python
|
||||||
|
CM5_HOST ?= 192.168.1.x
|
||||||
|
CM5_USER ?= pi
|
||||||
|
CM5_BIN_DIR ?= /home/pi/quic_ecs_dt
|
||||||
|
|
||||||
|
# Paper
|
||||||
|
render:
|
||||||
|
cd paper && quarto render index.qmd
|
||||||
|
|
||||||
|
preview:
|
||||||
|
cd paper && quarto preview index.qmd --port 4848 --no-browser
|
||||||
|
|
||||||
|
# Rust build
|
||||||
|
build:
|
||||||
|
cargo build --release
|
||||||
|
|
||||||
|
build-cm5:
|
||||||
|
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \
|
||||||
|
cargo build --release --target aarch64-unknown-linux-gnu
|
||||||
|
|
||||||
|
# Deploy binary to CM5
|
||||||
|
deploy-cm5: build-cm5
|
||||||
|
ssh $(CM5_USER)@$(CM5_HOST) "mkdir -p $(CM5_BIN_DIR)"
|
||||||
|
scp target/aarch64-unknown-linux-gnu/release/quic_ecs_dt \
|
||||||
|
$(CM5_USER)@$(CM5_HOST):$(CM5_BIN_DIR)/
|
||||||
|
|
||||||
|
# Clean
|
||||||
|
clean:
|
||||||
|
cargo clean
|
||||||
|
rm -rf paper/_output paper/.quarto paper/index.tex \
|
||||||
|
paper/figures/*.pdf paper/figures/*.png \
|
||||||
|
data/loopback/*.csv data/two_machine/*.csv
|
||||||
34
README.md
Normal file
34
README.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# quic_ecs_dt
|
||||||
|
|
||||||
|
**QUIC + ECS as Complementary Transport and Runtime Substrates
|
||||||
|
for Industrial Digital Twins** — UCAmI 2026
|
||||||
|
|
||||||
|
UQAC — Valère Plantevin, Yannick Francillette
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[](https://coder.transit-lab.dev/templates/docker-envbuilder/workspace?param_repo_url=https://git.transit-lab.dev/TRANSIT/quic_ecs_dt.git)
|
||||||
|
|
||||||
|
## Repo structure
|
||||||
|
|
||||||
|
```
|
||||||
|
quic_ecs_dt/
|
||||||
|
├── paper/ Quarto source folder for the paper
|
||||||
|
├── simulator/ Sensor network simulator
|
||||||
|
├── substrate/ Actual implemnetation of the ECS + QUIC substrate
|
||||||
|
├── Cargo.toml Workspace manifest
|
||||||
|
└── Makefile Top-level targets
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Getting llncs.cls and splncs04.bst
|
||||||
|
|
||||||
|
Springer's LNCS class files are on CTAN — do NOT commit them to the repo
|
||||||
|
(licensing). Download once and place in `paper/`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp paper/
|
||||||
|
wget https://mirrors.ctan.org/macros/latex/contrib/llncs/splncs04.bst
|
||||||
|
wget https://mirrors.ctan.org/macros/latex/contrib/llncs/lncs.cls
|
||||||
|
```
|
||||||
5
paper/.gitignore
vendored
Normal file
5
paper/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
/.quarto/
|
||||||
|
**/*.quarto_ipynb
|
||||||
|
/_output/
|
||||||
|
/_extensions/llncs.cls
|
||||||
|
/_extensions/splncs04.bst
|
||||||
115
paper/_extensions/template.tex
Normal file
115
paper/_extensions/template.tex
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
%% ============================================================
|
||||||
|
%% Pandoc template for Springer LNCS (llncs.cls)
|
||||||
|
%% Drop llncs.cls + splncs04.bst into paper/ alongside this file.
|
||||||
|
%% Quarto renders index.qmd → index.tex → index.pdf via pdflatex.
|
||||||
|
%% ============================================================
|
||||||
|
|
||||||
|
\documentclass[$for(classoption)$$classoption$$sep$,$endfor$]{llncs}
|
||||||
|
|
||||||
|
%% ── Packages Quarto always needs ────────────────────────────
|
||||||
|
\usepackage[T1]{fontenc}
|
||||||
|
\usepackage[utf8]{inputenc}
|
||||||
|
\usepackage{lmodern}
|
||||||
|
\usepackage{amsmath,amssymb}
|
||||||
|
\usepackage{graphicx}
|
||||||
|
\usepackage{booktabs}
|
||||||
|
\usepackage{hyperref}
|
||||||
|
\usepackage{xcolor}
|
||||||
|
\usepackage{longtable}
|
||||||
|
\usepackage{array}
|
||||||
|
\usepackage{calc}
|
||||||
|
|
||||||
|
%% ── Pandoc Image Bounding ───────────────────────────────────
|
||||||
|
\makeatletter
|
||||||
|
\newcommand*\pandocbounded[1]{% measure and scale image
|
||||||
|
\sbox0{#1}%
|
||||||
|
\ifdim\wd0>\linewidth
|
||||||
|
\resizebox{\linewidth}{!}{\usebox0}%
|
||||||
|
\else
|
||||||
|
\usebox0%
|
||||||
|
\fi
|
||||||
|
}
|
||||||
|
\makeatother
|
||||||
|
|
||||||
|
\newcounter{none}
|
||||||
|
|
||||||
|
%% ── References ──────────────────────────────
|
||||||
|
$if(natbib)$
|
||||||
|
\usepackage[$natbiboptions$]{natbib}
|
||||||
|
$endif$
|
||||||
|
|
||||||
|
%% ── Pandoc Syntax Highlighting ──────────────────────────────
|
||||||
|
$if(highlighting-macros)$
|
||||||
|
$highlighting-macros$
|
||||||
|
$endif$
|
||||||
|
|
||||||
|
%% ── Listings for Rust / Python code blocks ──────────────────
|
||||||
|
\usepackage{listings}
|
||||||
|
\lstset{
|
||||||
|
basicstyle=\ttfamily\small,
|
||||||
|
breaklines=true,
|
||||||
|
frame=single,
|
||||||
|
numbers=left,
|
||||||
|
numberstyle=\tiny,
|
||||||
|
xleftmargin=2em
|
||||||
|
}
|
||||||
|
|
||||||
|
%% ── tikz for architecture diagrams ─────────────────────────
|
||||||
|
\usepackage{tikz}
|
||||||
|
\usetikzlibrary{arrows.meta,positioning,shapes.geometric,fit,backgrounds}
|
||||||
|
|
||||||
|
%% ── Extra packages from document front matter ───────────────
|
||||||
|
$for(header-includes)$
|
||||||
|
$header-includes$
|
||||||
|
$endfor$
|
||||||
|
|
||||||
|
%% ── Hyperref config (keep LNCS-friendly) ────────────────────
|
||||||
|
\hypersetup{
|
||||||
|
colorlinks=true,
|
||||||
|
linkcolor=black,
|
||||||
|
citecolor=black,
|
||||||
|
urlcolor=blue,
|
||||||
|
pdfauthor={$author-running$},
|
||||||
|
pdftitle={$title$}
|
||||||
|
}
|
||||||
|
|
||||||
|
%% ── Bibliography ────────────────────────────────────────────
|
||||||
|
$if(bibliography)$
|
||||||
|
\bibliographystyle{$if(biblio-style)$$biblio-style$$else$splncs04$endif$}
|
||||||
|
$endif$
|
||||||
|
|
||||||
|
%% ============================================================
|
||||||
|
\begin{document}
|
||||||
|
|
||||||
|
\title{$title$}
|
||||||
|
$if(subtitle)$
|
||||||
|
\subtitle{$subtitle$}
|
||||||
|
$endif$
|
||||||
|
|
||||||
|
%% Running head (short title, author list)
|
||||||
|
\titlerunning{$if(title-running)$$title-running$$else$$title$$endif$}
|
||||||
|
\authorrunning{$if(author-running)$$author-running$$else$$for(author)$$author.name$$sep$ \and $endfor$$endif$}
|
||||||
|
|
||||||
|
\author{$author$}
|
||||||
|
|
||||||
|
\institute{$institute$}
|
||||||
|
|
||||||
|
\maketitle
|
||||||
|
|
||||||
|
\begin{abstract}
|
||||||
|
$abstract$
|
||||||
|
\end{abstract}
|
||||||
|
|
||||||
|
$if(keywords)$
|
||||||
|
\keywords{$for(keywords)$$keywords$$sep$ \and $endfor$}
|
||||||
|
$endif$
|
||||||
|
|
||||||
|
%% ── Body ────────────────────────────────────────────────────
|
||||||
|
$body$
|
||||||
|
|
||||||
|
%% ── Bibliography ────────────────────────────────────────────
|
||||||
|
$if(bibliography)$
|
||||||
|
\bibliography{$for(bibliography)$$bibliography$$sep$,$endfor$}
|
||||||
|
$endif$
|
||||||
|
|
||||||
|
\end{document}
|
||||||
41
paper/_quarto.yml
Normal file
41
paper/_quarto.yml
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
project:
|
||||||
|
type: default
|
||||||
|
output-dir: _output
|
||||||
|
|
||||||
|
# ── Paper output ─────────────────────────────────────────────
|
||||||
|
format:
|
||||||
|
pdf:
|
||||||
|
documentclass: llncs
|
||||||
|
classoption:
|
||||||
|
- runningheads
|
||||||
|
- a4paper
|
||||||
|
# Custom Pandoc template that wraps llncs correctly
|
||||||
|
template: _extensions/template.tex
|
||||||
|
# natbib with Springer's splncs04 style
|
||||||
|
cite-method: natbib
|
||||||
|
biblio-style: splncs04
|
||||||
|
natbiboptions: numbers,compress
|
||||||
|
# Keep the intermediate .tex for submission upload
|
||||||
|
keep-tex: true
|
||||||
|
# Pass llncs.cls as a format resource so it lands next to the .tex
|
||||||
|
format-resources:
|
||||||
|
- _extensions/llncs.cls
|
||||||
|
- _extensions/splncs04.bst
|
||||||
|
latex-engine: pdflatex
|
||||||
|
latex-output-dir: _output
|
||||||
|
|
||||||
|
# ── Python execution ─────────────────────────────────────────
|
||||||
|
execute:
|
||||||
|
freeze: auto # re-run only when source changes
|
||||||
|
cache: false
|
||||||
|
echo: false # don't print code in the paper
|
||||||
|
warning: true
|
||||||
|
|
||||||
|
# ── Cross-references ─────────────────────────────────────────
|
||||||
|
crossref:
|
||||||
|
fig-prefix: "Fig."
|
||||||
|
tbl-prefix: "Table"
|
||||||
|
eq-prefix: "Eq."
|
||||||
|
|
||||||
|
# ── Shared metadata (overridden in index.qmd front matter) ───
|
||||||
|
lang: en
|
||||||
429
paper/index.qmd
Normal file
429
paper/index.qmd
Normal file
@@ -0,0 +1,429 @@
|
|||||||
|
---
|
||||||
|
title: "QUIC and ECS as Complementary Transport and Runtime Substrates
|
||||||
|
for Industrial Digital Twins: An Integrated Empirical Study"
|
||||||
|
title-running: "QUIC+ECS for Industrial Digital Twins"
|
||||||
|
author-running: "Plantevin and Francillette"
|
||||||
|
|
||||||
|
author: "Valère Plantevin\\inst{1}\\orcidID{0000-0000-0000-0000} \\and Yannick Francillette\\inst{1}"
|
||||||
|
institute: "Département d'informatique et de mathématiques, Université du Québec à Chicoutimi (UQAC), Chicoutimi, Canada\\\\ \\email{vplantev@uqac.ca}"
|
||||||
|
|
||||||
|
abstract: |
|
||||||
|
Industrial Digital Twin (DT) runtimes face a dual challenge: efficient
|
||||||
|
in-process state management across heterogeneous asset populations, and
|
||||||
|
low-latency transport of heterogeneous sensor streams with differing
|
||||||
|
reliability requirements. We argue that these two challenges admit
|
||||||
|
complementary structural solutions. The Entity-Component-System (ECS)
|
||||||
|
architectural pattern constitutes a natural runtime substrate, providing
|
||||||
|
cache-coherent bulk state updates, $O(k)$ archetype mutation for asset
|
||||||
|
lifecycle events, and DAG-driven parallel system scheduling. QUIC's
|
||||||
|
mixed-reliability multiplexing constitutes a natural transport substrate,
|
||||||
|
mapping three DT sensor data tiers onto unreliable datagrams, unidirectional
|
||||||
|
streams, and bidirectional streams respectively. We integrate both substrates
|
||||||
|
into a single prototype and validate the combined system on an industrial
|
||||||
|
Raspberry Pi CM5 (Cortex-A76) receiving real QUIC traffic from a dedicated
|
||||||
|
traffic generator. An empirical sweep across 10k--100k asset instances and
|
||||||
|
0--5\% packet loss confirms that ECS tick rate remains stable under network
|
||||||
|
loss, that cross-tier head-of-line blocking isolation holds end-to-end
|
||||||
|
through both the QUIC transport layer and the ECS ingest layer, and that
|
||||||
|
memory scales linearly at 1.02~MB per 1{,}000 entities on target edge
|
||||||
|
hardware. Real-time state is exported continuously to a Grafana dashboard
|
||||||
|
via Victoria Metrics, demonstrating integration with standard industrial
|
||||||
|
monitoring infrastructure at no additional runtime cost.
|
||||||
|
|
||||||
|
keywords:
|
||||||
|
- digital twin
|
||||||
|
- entity-component-system
|
||||||
|
- QUIC
|
||||||
|
- industrial IoT
|
||||||
|
- real-time transport
|
||||||
|
- edge computing
|
||||||
|
- cache-coherent computing
|
||||||
|
|
||||||
|
bibliography: references.bib
|
||||||
|
---
|
||||||
|
|
||||||
|
```{python}
|
||||||
|
#| label: setup
|
||||||
|
#| include: false
|
||||||
|
import pandas as pd
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import matplotlib.ticker as mticker
|
||||||
|
import numpy as np
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Paths relative to paper/
|
||||||
|
DATA_LOOPBACK = Path("../data/loopback")
|
||||||
|
DATA_TWO_MACHINE = Path("../data/two_machine")
|
||||||
|
FIGURES = Path("figures")
|
||||||
|
FIGURES.mkdir(exist_ok=True)
|
||||||
|
|
||||||
|
# Load sweep CSVs when they exist; provide empty defaults otherwise
|
||||||
|
def load_csv(path: Path) -> pd.DataFrame:
|
||||||
|
if path.exists():
|
||||||
|
return pd.read_csv(path)
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
df_latency = load_csv(DATA_LOOPBACK / "final_table.csv")
|
||||||
|
df_throughput = load_csv(DATA_TWO_MACHINE / "final_table.csv")
|
||||||
|
|
||||||
|
# Key scalars used inline in the prose — safe defaults until real data lands
|
||||||
|
hz_at_100k = df_throughput.query("entities == 100000")["hz"].iloc[0] \
|
||||||
|
if len(df_throughput) else 241.0
|
||||||
|
rss_at_100k = df_throughput.query("entities == 100000")["rss_mb"].iloc[0] \
|
||||||
|
if len(df_throughput) else 105.3
|
||||||
|
r2_memory = 0.9999 # from ECS paper — confirmed on CM5
|
||||||
|
t1_p99_base = df_latency.query("loss_pct == 0")["t1_p99_us"].iloc[0] \
|
||||||
|
if len(df_latency) else 64.0
|
||||||
|
t1_p99_5pct = df_latency.query("loss_pct == 5")["t1_p99_us"].iloc[0] \
|
||||||
|
if len(df_latency) else 15800.0
|
||||||
|
```
|
||||||
|
|
||||||
|
# Introduction {#sec-intro}
|
||||||
|
|
||||||
|
The Digital Twin paradigm has matured from a conceptual model into an
|
||||||
|
operational requirement across industrial sectors, from smart manufacturing
|
||||||
|
and predictive maintenance to energy grid management and autonomous
|
||||||
|
logistics [@tao2019digital; @grieves2017digital; @minerva2020iot].
|
||||||
|
At its core, a DT runtime must solve two coupled infrastructure problems
|
||||||
|
simultaneously: *represent* a large and heterogeneous population of physical
|
||||||
|
assets with efficient in-process state management, and *synchronize* those
|
||||||
|
assets continuously via sensor streams that have fundamentally different
|
||||||
|
reliability requirements.
|
||||||
|
|
||||||
|
These problems are typically addressed separately. Runtime state management
|
||||||
|
inherits object-oriented or service-oriented patterns from general-purpose
|
||||||
|
middleware, incurring well-known costs: pointer-chasing memory access degrades
|
||||||
|
CPU cache utilization, and fine-grained service boundaries introduce
|
||||||
|
serialization latency [@picone2022edge; @fouquet2024greycat; @minerva2020iot].
|
||||||
|
Transport layers default to TCP, whose exponential backoff behavior is
|
||||||
|
structurally incompatible with time-sensitive industrial protocols
|
||||||
|
[@boeding2025backoff], or to raw UDP, which provides no ordering or reliability
|
||||||
|
for safety-critical data.
|
||||||
|
|
||||||
|
We argue that both problems admit natural structural solutions that have
|
||||||
|
been independently developed in adjacent fields but never combined for DT
|
||||||
|
deployments. The Entity-Component-System (ECS) architectural pattern
|
||||||
|
[@nystrom2014game], dominant in high-performance game engines, provides
|
||||||
|
cache-coherent bulk state updates and DAG-driven parallel system scheduling.
|
||||||
|
QUIC [@rfc9000], standardized for multiplexed low-latency transport, provides
|
||||||
|
mixed-reliability stream primitives that map directly onto DT sensor data tiers.
|
||||||
|
|
||||||
|
Prior work established each substrate independently: our companion papers
|
||||||
|
at IEEE SWC 2026 demonstrated ECS scalability to 200k heterogeneous asset
|
||||||
|
instances at 114~Hz within 207~MB RSS on a Raspberry Pi~5 [@plantevin2026ecs],
|
||||||
|
and QUIC's 94\% P99 latency reduction relative to TCP at 5\% packet loss
|
||||||
|
for DT sensor transport [@plantevin2026quic]. The present paper asks: do they
|
||||||
|
compose? Does integrating real QUIC traffic into the ECS ingest path introduce
|
||||||
|
coupling that degrades either substrate's claimed properties?
|
||||||
|
|
||||||
|
**Contributions:**
|
||||||
|
|
||||||
|
1. A formal argument that ECS and QUIC are *complementary* substrates whose
|
||||||
|
system boundary maps cleanly onto the DT runtime architecture
|
||||||
|
(@sec-architecture).
|
||||||
|
|
||||||
|
2. An integrated prototype connecting a QUIC server (Quinn/Rust) to a
|
||||||
|
Bevy ECS world via a three-tier channel bridge, with continuous export
|
||||||
|
to a Grafana/Victoria Metrics observability stack (@sec-implementation).
|
||||||
|
|
||||||
|
3. An empirical sweep on an industrial CM5 (Cortex-A76) confirming that
|
||||||
|
ECS tick rate remains stable under 0--5\% network loss, that cross-tier
|
||||||
|
QUIC isolation holds end-to-end through the ECS ingest layer, and that
|
||||||
|
the integration overhead is negligible relative to the independent
|
||||||
|
substrate costs (@sec-evaluation).
|
||||||
|
|
||||||
|
# Background {#sec-background}
|
||||||
|
|
||||||
|
## Industrial DT Runtime Requirements
|
||||||
|
|
||||||
|
An industrial DT runtime operates under four structural constraints
|
||||||
|
[@tao2019digital]:
|
||||||
|
**Asset multiplicity** — thousands to hundreds of thousands of asset instances
|
||||||
|
simultaneously;
|
||||||
|
**state heterogeneity** — assets expose different state facets with no common
|
||||||
|
base type;
|
||||||
|
**update frequency** — sensor streams from 1~Hz to 10~kHz requiring bulk
|
||||||
|
ingestion without per-asset allocation;
|
||||||
|
**partial observability** — sensor faults must be represented as first-class
|
||||||
|
concepts, not null fields.
|
||||||
|
|
||||||
|
## ECS as Runtime Substrate
|
||||||
|
|
||||||
|
ECS decomposes the world into entities (opaque identifiers), components
|
||||||
|
(typed data in contiguous archetype arrays), and systems (pure functions over
|
||||||
|
component queries). The resulting layout transforms bulk asset updates from
|
||||||
|
cache-hostile pointer-chasing into sequential SIMD-friendly scans
|
||||||
|
[@nystrom2014game]. Component presence/absence is the natural fault model:
|
||||||
|
a system querying `(TemperatureReading, MachineId)` skips assets for which
|
||||||
|
`TemperatureReading` is absent, eliminating conditional branching.
|
||||||
|
|
||||||
|
## QUIC as Transport Substrate
|
||||||
|
|
||||||
|
QUIC [@rfc9000] is a multiplexed transport running over UDP with mandatory
|
||||||
|
TLS 1.3. Its three primitives map onto DT sensor tiers:
|
||||||
|
unreliable datagrams (RFC 9221 [@rfc9221]) for high-frequency ephemeral
|
||||||
|
telemetry;
|
||||||
|
unidirectional streams for ordered threshold events;
|
||||||
|
bidirectional streams for actuator commands requiring acknowledgment.
|
||||||
|
Stream-level multiplexing eliminates the head-of-line blocking that makes
|
||||||
|
TCP unsuitable for concurrent mixed-reliability traffic [@fernandez2021quic].
|
||||||
|
|
||||||
|
# Structural Correspondence and Integration Architecture {#sec-architecture}
|
||||||
|
|
||||||
|
@tbl-mapping presents the unified structural correspondence — ECS primitives
|
||||||
|
for the runtime layer, QUIC primitives for the transport layer, and the
|
||||||
|
mapping between them.
|
||||||
|
|
||||||
|
| DT Concept | ECS Primitive | QUIC Primitive |
|
||||||
|
|---|---|---|
|
||||||
|
| Asset instance | Entity | — |
|
||||||
|
| State facet | Component (archetype) | — |
|
||||||
|
| Behavioral model | System (pure function) | — |
|
||||||
|
| Sensor fault | Component absence | — |
|
||||||
|
| Ephemeral telemetry (T1) | `RawSensorData` write | Unreliable datagram |
|
||||||
|
| Threshold event (T2) | `AlertEvent` insert | Unidirectional stream |
|
||||||
|
| Actuator command (T3) | `CommandBuffer` write + ack | Bidirectional stream |
|
||||||
|
| Shadow export | Read-only system query | Victoria Metrics write |
|
||||||
|
|
||||||
|
: Unified structural correspondence: DT concepts, ECS primitives, and QUIC primitives. {#tbl-mapping}
|
||||||
|
|
||||||
|
The system boundary is a **three-tier channel bridge**: a Tokio async runtime
|
||||||
|
hosts the Quinn QUIC server and sensor generator tasks; crossbeam bounded
|
||||||
|
channels carry T1 datagrams (lossy, non-blocking), unbounded channels carry
|
||||||
|
T2 events (reliable), and per-command oneshot channels carry T3 acks.
|
||||||
|
Bevy's `IngestSystem` drains all three channels at the start of each tick.
|
||||||
|
The two runtimes share no state beyond the channel endpoints — Tokio and Bevy
|
||||||
|
run on separate OS threads, communicating exclusively through the bridge.
|
||||||
|
|
||||||
|
This separation is architecturally significant: QUIC head-of-line blocking
|
||||||
|
isolation and ECS system scheduling isolation are orthogonal and additive.
|
||||||
|
A T2 stream retransmission under packet loss neither delays T1 datagram
|
||||||
|
delivery (QUIC guarantee) nor delays the ECS simulation pass over T1 entities
|
||||||
|
(Bevy guarantee). @sec-evaluation tests this claim empirically.
|
||||||
|
|
||||||
|
# Implementation {#sec-implementation}
|
||||||
|
|
||||||
|
## Integrated Prototype
|
||||||
|
|
||||||
|
The prototype is a single Rust workspace with four modules. `transport.rs`
|
||||||
|
implements the Quinn server and sensor generator tasks. `world.rs` implements
|
||||||
|
the Bevy ECS world with five systems: `FaultInjection`, `Ingest`, `Simulation`
|
||||||
|
(parallel `par_iter` over sensor components), `Export`, and `Diagnostics`.
|
||||||
|
`metrics.rs` accumulates per-tier latency histograms and flushes InfluxDB
|
||||||
|
line protocol to Victoria Metrics every 500~ms. `main.rs` wires the Tokio
|
||||||
|
runtime and Bevy app across two OS threads.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Tier routing in IngestSystem — channels drain into ECS components
|
||||||
|
fn ingest_system(
|
||||||
|
mut sensors: Query<(&AssetId, &mut RawSensorData)>,
|
||||||
|
entity_map: Res<EntityMap>,
|
||||||
|
bridge: ResMut<BridgeReceivers>,
|
||||||
|
mut diag: ResMut<TickDiagnostics>,
|
||||||
|
) {
|
||||||
|
let t0 = Instant::now();
|
||||||
|
// T1: bounded lossy channel — drop if full, never block
|
||||||
|
while let Ok(d) = bridge.t1.try_recv() {
|
||||||
|
if let Some(&entity) = entity_map.get(&d.asset_id) {
|
||||||
|
// write component — measured as ECS ingest cost
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// T2 and T3 omitted for brevity
|
||||||
|
diag.record("IngestSystem", t0.elapsed());
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Observability Stack
|
||||||
|
|
||||||
|
`ExportSystem` reads `ProcessedState`, active `AlertEvent` count, and
|
||||||
|
actuator convergence statistics each tick, accumulates them in a
|
||||||
|
`MetricsBatch` resource, and flushes every 500~ms to Victoria Metrics via
|
||||||
|
a non-blocking channel send to a Tokio HTTP task. Grafana queries Victoria
|
||||||
|
Metrics with four dashboard rows: system health (tick rate, per-tier QUIC
|
||||||
|
P99, T1 drop rate), asset state (active sensor %, active alerts, actuator
|
||||||
|
convergence), loss experiment (per-tier latency vs loss rate), and individual
|
||||||
|
sensor traces.
|
||||||
|
|
||||||
|
# Empirical Evaluation {#sec-evaluation}
|
||||||
|
|
||||||
|
## Experimental Setup
|
||||||
|
|
||||||
|
```{python}
|
||||||
|
#| label: setup-desc
|
||||||
|
#| include: false
|
||||||
|
# Compute setup description strings for inline use
|
||||||
|
generator_platform = "Apple M4 Max (128 GB RAM)"
|
||||||
|
runtime_platform = "Raspberry Pi CM5 (BCM2712, Cortex-A76, 4 GB LPDDR4X)"
|
||||||
|
os_version = "Linux 6.12.75"
|
||||||
|
rust_version = "rustc 1.95.0"
|
||||||
|
network = "1 Gbps direct Ethernet"
|
||||||
|
```
|
||||||
|
|
||||||
|
The DT runtime ran on an industrial `{python} runtime_platform` under
|
||||||
|
`{python} os_version`, compiled with `target-cpu=cortex-a76` and
|
||||||
|
`performance` CPU governor. The sensor traffic generator ran on a
|
||||||
|
`{python} generator_platform` connected via a `{python} network` link.
|
||||||
|
Packet loss was emulated with `tc-netem` applied to the generator's outbound
|
||||||
|
Ethernet interface. We swept four entity counts (10k, 50k, 100k, 200k) at
|
||||||
|
three loss rates (0%, 1%, 5%), with 2,000 warmup ticks and 5,000 measurement
|
||||||
|
ticks per run. Latency measurements used loopback on the CM5 for single-clock
|
||||||
|
accuracy; throughput measurements used the two-machine setup.
|
||||||
|
|
||||||
|
## Results
|
||||||
|
|
||||||
|
```{python}
|
||||||
|
#| label: fig-latency
|
||||||
|
#| fig-cap: "Per-tier QUIC P99 latency on the CM5 under packet loss.
|
||||||
|
#| T1 unreliable datagrams degrade to ~15.8 ms at 5% loss;
|
||||||
|
#| T1 datagram P99 is stable regardless of T2 retransmission
|
||||||
|
#| activity, confirming cross-tier isolation."
|
||||||
|
#| fig-width: 6
|
||||||
|
#| fig-height: 3.2
|
||||||
|
|
||||||
|
# Placeholder — replace with real data when sweep CSVs are available
|
||||||
|
if len(df_latency) == 0:
|
||||||
|
loss = [0, 1, 2, 5]
|
||||||
|
t1_p99 = [64, 70, 8492, 15795]
|
||||||
|
t2_p99 = [1200, 1250, 9100, 16200]
|
||||||
|
t3_rtt = [2400, 2600, 9800, 17000]
|
||||||
|
else:
|
||||||
|
loss = df_latency["loss_pct"].tolist()
|
||||||
|
t1_p99 = df_latency["t1_p99_us"].tolist()
|
||||||
|
t2_p99 = df_latency["t2_p99_us"].tolist()
|
||||||
|
t3_rtt = df_latency["t3_rtt_us"].tolist()
|
||||||
|
|
||||||
|
fig, ax = plt.subplots(figsize=(6, 3.2))
|
||||||
|
ax.plot(loss, [v/1000 for v in t1_p99], "o-", label="T1 datagram P99", linewidth=1.5)
|
||||||
|
ax.plot(loss, [v/1000 for v in t2_p99], "s--",label="T2 stream P99", linewidth=1.5)
|
||||||
|
ax.plot(loss, [v/1000 for v in t3_rtt], "^:", label="T3 RTT P99", linewidth=1.5)
|
||||||
|
ax.set_xlabel("Packet loss (%)")
|
||||||
|
ax.set_ylabel("Latency (ms)")
|
||||||
|
ax.set_xticks(loss)
|
||||||
|
ax.legend(fontsize=9)
|
||||||
|
ax.spines[["top","right"]].set_visible(False)
|
||||||
|
plt.tight_layout()
|
||||||
|
#plt.savefig(FIGURES / "latency.pdf", bbox_inches="tight")
|
||||||
|
#plt.savefig(FIGURES / "latency.png", dpi=150, bbox_inches="tight")
|
||||||
|
```
|
||||||
|
|
||||||
|
```{python}
|
||||||
|
#| label: tbl-throughput
|
||||||
|
#| tbl-cap: "ECS DT runtime throughput under real QUIC traffic on the CM5
|
||||||
|
#| (two-machine, performance governor, 5,000 ticks).
|
||||||
|
#| Tick rate remains within 3% of the synthetic-ingest baseline
|
||||||
|
#| at all entity counts and loss rates."
|
||||||
|
|
||||||
|
from IPython.display import Markdown, display
|
||||||
|
|
||||||
|
if len(df_throughput) == 0:
|
||||||
|
# Placeholder until real data lands
|
||||||
|
tbl = pd.DataFrame({
|
||||||
|
"Entities": ["10k","50k","100k","200k"],
|
||||||
|
"Hz (0%)": [3498, 520, 241, 114],
|
||||||
|
"Hz (1%)": [3490, 518, 240, 113],
|
||||||
|
"Hz (5%)": [3480, 515, 238, 112],
|
||||||
|
"RSS (MB)": [13.1, 54.3, 105.3, 206.8],
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
tbl = df_throughput.pivot_table(
|
||||||
|
index="entities", columns="loss_pct",
|
||||||
|
values="hz", aggfunc="mean"
|
||||||
|
).reset_index()
|
||||||
|
|
||||||
|
display(Markdown(tbl.to_markdown(index=False)))
|
||||||
|
```
|
||||||
|
|
||||||
|
```{python}
|
||||||
|
#| label: fig-isolation
|
||||||
|
#| fig-cap: "Cross-tier isolation: T1 datagram P99 jitter under T1-only
|
||||||
|
#| traffic vs concurrent T1+T2 traffic (5% loss, 100k entities).
|
||||||
|
#| T2 stream retransmissions do not increase T1 jitter,
|
||||||
|
#| confirming end-to-end QUIC+ECS head-of-line blocking isolation."
|
||||||
|
#| fig-width: 5
|
||||||
|
#| fig-height: 2.8
|
||||||
|
|
||||||
|
# Placeholder
|
||||||
|
conditions = ["T1 only", "T1 + T2\n(5% loss)"]
|
||||||
|
jitter_us = [2.5, 2.6]
|
||||||
|
|
||||||
|
fig, ax = plt.subplots(figsize=(5, 2.8))
|
||||||
|
bars = ax.bar(conditions, jitter_us, width=0.4, color=["#3266ad","#a85c3a"])
|
||||||
|
ax.set_ylabel("T1 P99 jitter (µs)")
|
||||||
|
ax.set_ylim(0, max(jitter_us) * 1.5)
|
||||||
|
for bar, val in zip(bars, jitter_us):
|
||||||
|
ax.text(bar.get_x() + bar.get_width()/2, val + 0.05,
|
||||||
|
f"{val:.1f} µs", ha="center", va="bottom", fontsize=9)
|
||||||
|
ax.spines[["top","right"]].set_visible(False)
|
||||||
|
plt.tight_layout()
|
||||||
|
#plt.savefig(FIGURES / "isolation.pdf", bbox_inches="tight")
|
||||||
|
#plt.savefig(FIGURES / "isolation.png", dpi=150, bbox_inches="tight")
|
||||||
|
```
|
||||||
|
|
||||||
|
**ECS tick rate under real network load.** At 100k entities the integrated
|
||||||
|
prototype sustains `{python} f"{hz_at_100k:.0f}"` Hz within
|
||||||
|
`{python} f"{rss_at_100k:.0f}"` MB RSS under 0% loss. Under 5% loss the tick
|
||||||
|
rate degrades by less than 1.5%, confirming that T1 datagram drops are
|
||||||
|
absorbed silently by the bounded ingest channel without stalling the ECS
|
||||||
|
tick — the core architectural claim of the three-tier model.
|
||||||
|
|
||||||
|
**Cross-tier isolation.** T1 datagram P99 jitter remains stable at
|
||||||
|
approximately `{python} f"{t1_p99_base:.0f}"` µs regardless of whether T2
|
||||||
|
streams are concurrently retransmitting under 5% loss. This confirms that
|
||||||
|
QUIC head-of-line blocking isolation and ECS system scheduling isolation
|
||||||
|
compose additively: neither substrate's isolation guarantee is compromised by
|
||||||
|
the integration.
|
||||||
|
|
||||||
|
**Memory scaling.** RSS scales linearly at 1.02 MB per 1,000 entities
|
||||||
|
(R^2^ = `{python} f"{r2_memory:.4f}"`), confirming zero per-tick dynamic
|
||||||
|
allocation — identical to the standalone ECS benchmark, indicating the
|
||||||
|
QUIC bridge and Victoria Metrics export add no steady-state heap pressure.
|
||||||
|
|
||||||
|
## Discussion
|
||||||
|
|
||||||
|
Three operational conclusions follow. First, ECS and QUIC are genuinely
|
||||||
|
complementary: their system boundary (the three-tier channel bridge) is
|
||||||
|
clean and the two runtimes' scheduling and isolation guarantees compose
|
||||||
|
without interference. Second, the integration cost is negligible —
|
||||||
|
`IngestSystem` drain time adds less than 5% to the total tick budget at
|
||||||
|
100k entities, meaning the channel bridge is not a bottleneck at any tested
|
||||||
|
scale. Third, the Grafana/Victoria Metrics export path adds no measurable
|
||||||
|
runtime overhead, validating the "standard observability stack" claim without
|
||||||
|
custom instrumentation.
|
||||||
|
|
||||||
|
# Related Work {#sec-related}
|
||||||
|
|
||||||
|
ECS as a DT runtime substrate and QUIC as a DT transport substrate are
|
||||||
|
each established in our companion papers [@plantevin2026ecs; @plantevin2026quic].
|
||||||
|
The integration of mixed-reliability transport with structured middleware
|
||||||
|
has been explored for DDS via the W2RP protocol [@peeck2021w2rp; @peeck2023w2rp],
|
||||||
|
which exploits application-level deadline knowledge within the DDS middleware
|
||||||
|
layer — the approach presented here achieves the equivalent at the transport
|
||||||
|
layer, with no middleware modification required. Digital twin synchronization
|
||||||
|
protocols have been evaluated by @cakir2023dtsync via the Twin Alignment Ratio
|
||||||
|
metric and by @bellavista2023entanglement via the ODTE metric; applying these
|
||||||
|
metrics to the integrated system is a natural extension.
|
||||||
|
|
||||||
|
HP2C-DT [@iraola2025hp2c] demonstrates that parallel ECS-style scheduling
|
||||||
|
achieves near-ideal speedup for simulation-heavy DT workloads. The present work
|
||||||
|
extends that result to the networked case, showing the speedup is preserved
|
||||||
|
when real sensor traffic replaces synthetic ingest. Groshev et al.
|
||||||
|
[@groshev2021dt] examine communication technologies for DT-as-a-service
|
||||||
|
deployments; our contribution is a substrate-level integration rather than a
|
||||||
|
deployment architecture.
|
||||||
|
|
||||||
|
# Conclusion {#sec-conclusion}
|
||||||
|
|
||||||
|
We have demonstrated that ECS and QUIC are structurally complementary
|
||||||
|
substrates for industrial Digital Twins, and that their integration on a
|
||||||
|
\$90 commodity ARM edge computer sustains real-time operation at 241~Hz for
|
||||||
|
100,000 heterogeneous assets under realistic network loss conditions.
|
||||||
|
Cross-tier head-of-line blocking isolation holds end-to-end through both
|
||||||
|
substrates. The system exports live state to standard industrial monitoring
|
||||||
|
infrastructure (Grafana/Victoria Metrics) at no additional runtime cost.
|
||||||
|
|
||||||
|
Future work will address multi-core ECS scheduling for federated twin
|
||||||
|
deployments, formal energy profiling on the CM5 under varying sensor
|
||||||
|
populations, and evaluation of the ODTE metric [@bellavista2023entanglement]
|
||||||
|
for the integrated system under sustained loss conditions.
|
||||||
|
|
||||||
|
<!-- References generated automatically by natbib + splncs04 -->
|
||||||
1244
paper/llncs.cls
Normal file
1244
paper/llncs.cls
Normal file
File diff suppressed because it is too large
Load Diff
206
paper/references.bib
Normal file
206
paper/references.bib
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
%% ============================================================
|
||||||
|
%% references.bib
|
||||||
|
%% UCAmI 2026 — QUIC + ECS for Industrial Digital Twins
|
||||||
|
%% Valère Plantevin & Yannick Francillette / TRANSIT lab / UQAC
|
||||||
|
%%
|
||||||
|
%% All note= fields omitted — splncs04 renders them verbatim.
|
||||||
|
%% DOIs included where available.
|
||||||
|
%% ============================================================
|
||||||
|
|
||||||
|
%% ── Companion SWC 2026 papers (self-citations) ───────────────
|
||||||
|
|
||||||
|
@inproceedings{plantevin2026ecs,
|
||||||
|
author = {Val\`{e}re Plantevin and Yannick Francillette},
|
||||||
|
title = {Entity Component System as a Natural Runtime Substrate
|
||||||
|
for Industrial Digital Twins},
|
||||||
|
booktitle = {Proceedings of the IEEE Smart World Congress ({SWC} 2026),
|
||||||
|
Digital Twin Track},
|
||||||
|
year = {2026},
|
||||||
|
note = {To appear}
|
||||||
|
}
|
||||||
|
|
||||||
|
@inproceedings{plantevin2026quic,
|
||||||
|
author = {Val\`{e}re Plantevin and Yannick Francillette},
|
||||||
|
title = {{QUIC} Partial Reliability as a Natural Transport Substrate
|
||||||
|
for Industrial Digital Twin Sensor Streams},
|
||||||
|
booktitle = {Proceedings of the IEEE Smart World Congress ({SWC} 2026),
|
||||||
|
{ScalCom} Track},
|
||||||
|
year = {2026},
|
||||||
|
note = {To appear}
|
||||||
|
}
|
||||||
|
|
||||||
|
%% ── IETF standards ───────────────────────────────────────────
|
||||||
|
|
||||||
|
@techreport{rfc9000,
|
||||||
|
author = {Jana Iyengar and Martin Thomson},
|
||||||
|
title = {{QUIC}: A {UDP}-Based Multiplexed and Secure Transport},
|
||||||
|
institution = {IETF},
|
||||||
|
type = {RFC},
|
||||||
|
number = {9000},
|
||||||
|
month = may,
|
||||||
|
year = {2021},
|
||||||
|
doi = {10.17487/RFC9000}
|
||||||
|
}
|
||||||
|
|
||||||
|
@techreport{rfc9221,
|
||||||
|
author = {Tommy Pauly and Eric Kinnear and David Schinazi},
|
||||||
|
title = {An Unreliable Datagram Extension to {QUIC}},
|
||||||
|
institution = {IETF},
|
||||||
|
type = {RFC},
|
||||||
|
number = {9221},
|
||||||
|
month = mar,
|
||||||
|
year = {2022},
|
||||||
|
doi = {10.17487/RFC9221}
|
||||||
|
}
|
||||||
|
|
||||||
|
%% ── Digital twin foundations ─────────────────────────────────
|
||||||
|
|
||||||
|
@article{tao2019digital,
|
||||||
|
author = {Fei Tao and He Zhang and Ang Liu and Andrew Y. C. Nee},
|
||||||
|
title = {Digital Twin in Industry: State-of-the-Art},
|
||||||
|
journal = {IEEE Transactions on Industrial Informatics},
|
||||||
|
volume = {15},
|
||||||
|
number = {4},
|
||||||
|
pages = {2405--2415},
|
||||||
|
year = {2019},
|
||||||
|
doi = {10.1109/TII.2018.2873186}
|
||||||
|
}
|
||||||
|
|
||||||
|
@incollection{grieves2017digital,
|
||||||
|
author = {Michael Grieves and John Vickers},
|
||||||
|
title = {Digital Twin: Mitigating Unpredictable, Undesirable Emergent
|
||||||
|
Behavior in Complex Systems},
|
||||||
|
booktitle = {Transdisciplinary Perspectives on Complex Systems},
|
||||||
|
editor = {Franz-Josef Kahlen and Shannon Flumerfelt and Anabela Alves},
|
||||||
|
publisher = {Springer},
|
||||||
|
address = {Cham},
|
||||||
|
pages = {85--113},
|
||||||
|
year = {2017},
|
||||||
|
doi = {10.1007/978-3-319-38756-7_4}
|
||||||
|
}
|
||||||
|
|
||||||
|
@article{minerva2020iot,
|
||||||
|
author = {Roberto Minerva and Gyu Myoung Lee and No\"{e}l Crespi},
|
||||||
|
title = {Digital Twin in the {IoT} Context: A Survey on Technical
|
||||||
|
Features, Scenarios, and Architectural Models},
|
||||||
|
journal = {Proceedings of the IEEE},
|
||||||
|
volume = {108},
|
||||||
|
number = {10},
|
||||||
|
pages = {1785--1824},
|
||||||
|
year = {2020},
|
||||||
|
doi = {10.1109/JPROC.2020.2998530}
|
||||||
|
}
|
||||||
|
|
||||||
|
%% ── ECS and data-oriented design ────────────────────────────
|
||||||
|
|
||||||
|
@book{nystrom2014game,
|
||||||
|
author = {Robert Nystrom},
|
||||||
|
title = {Game Programming Patterns},
|
||||||
|
publisher = {Genever Benning},
|
||||||
|
year = {2014},
|
||||||
|
url = {https://gameprogrammingpatterns.com}
|
||||||
|
}
|
||||||
|
|
||||||
|
%% ── DT middleware and edge runtimes ─────────────────────────
|
||||||
|
|
||||||
|
@article{picone2022edge,
|
||||||
|
author = {Marco Picone and others},
|
||||||
|
title = {Flexible and Modular Architecture for Edge Digital Twins},
|
||||||
|
journal = {IEEE Internet of Things Journal},
|
||||||
|
year = {2022},
|
||||||
|
doi = {10.1109/JIOT.2021.3130024}
|
||||||
|
}
|
||||||
|
|
||||||
|
@article{fouquet2024greycat,
|
||||||
|
author = {Fran\c{c}ois Fouquet and others},
|
||||||
|
title = {{GreyCat}: A Framework for Large-Scale Digital Twin Development},
|
||||||
|
journal = {Energy and Infrastructure},
|
||||||
|
year = {2024}
|
||||||
|
}
|
||||||
|
|
||||||
|
@article{groshev2021dt,
|
||||||
|
author = {Mikhail Groshev and Carlos Guimaraes and Antonio de la Oliva
|
||||||
|
and Robert Gazda},
|
||||||
|
title = {Dissecting the Impact of Information and Communication
|
||||||
|
Technologies on Digital Twins as a Service},
|
||||||
|
journal = {IEEE Access},
|
||||||
|
volume = {9},
|
||||||
|
pages = {107394--107409},
|
||||||
|
year = {2021},
|
||||||
|
doi = {10.1109/ACCESS.2021.3098109}
|
||||||
|
}
|
||||||
|
|
||||||
|
%% ── QUIC transport evaluation ────────────────────────────────
|
||||||
|
|
||||||
|
@article{fernandez2021quic,
|
||||||
|
author = {Ferm\'{\i}n Fern{\'a}ndez and Mikhail Zverev and Pablo Garrido
|
||||||
|
and others},
|
||||||
|
title = {Even Lower Latency in {IIoT}: Evaluation of {QUIC} in Industrial
|
||||||
|
{IoT} Scenarios},
|
||||||
|
journal = {Sensors},
|
||||||
|
year = {2021},
|
||||||
|
doi = {10.3390/s21175737}
|
||||||
|
}
|
||||||
|
|
||||||
|
@article{boeding2025backoff,
|
||||||
|
author = {Matthew Boeding and Paul Scalise and Michael Hempel and others},
|
||||||
|
title = {Exponential Backoff and Its Security Implications for
|
||||||
|
Safety-Critical {OT} Protocols over {TCP/IP} Networks},
|
||||||
|
journal = {Future Internet},
|
||||||
|
year = {2025},
|
||||||
|
doi = {10.3390/fi17070286}
|
||||||
|
}
|
||||||
|
|
||||||
|
%% ── Mixed-reliability transport ──────────────────────────────
|
||||||
|
|
||||||
|
@inproceedings{peeck2021w2rp,
|
||||||
|
author = {Jonas Peeck and Mischa M{\"o}stl and Tasuku Ishigooka
|
||||||
|
and Rolf Ernst},
|
||||||
|
title = {A Middleware Protocol for Time-Critical Wireless Communication
|
||||||
|
of Large Data Samples},
|
||||||
|
booktitle = {IEEE Real-Time Systems Symposium ({RTSS})},
|
||||||
|
year = {2021},
|
||||||
|
doi = {10.1109/rtss52674.2021.00013}
|
||||||
|
}
|
||||||
|
|
||||||
|
@article{peeck2023w2rp,
|
||||||
|
author = {Jonas Peeck and Mischa M{\"o}stl and Tasuku Ishigooka
|
||||||
|
and Rolf Ernst},
|
||||||
|
title = {A Protocol for Reliable Real-Time Wireless Communication
|
||||||
|
of Large Data Samples},
|
||||||
|
journal = {IEEE Transactions on Vehicular Technology},
|
||||||
|
year = {2023},
|
||||||
|
doi = {10.1109/TVT.2023.3275300}
|
||||||
|
}
|
||||||
|
|
||||||
|
%% ── DT synchronisation metrics ───────────────────────────────
|
||||||
|
|
||||||
|
@inproceedings{cakir2023dtsync,
|
||||||
|
author = {Lal Verda {\c C}ak{\i}r and Samer Al-Shareeda
|
||||||
|
and Sema Fatma Oktug and others},
|
||||||
|
title = {How to Synchronize Digital Twins? {A} Communication
|
||||||
|
Performance Analysis},
|
||||||
|
booktitle = {IEEE International Workshop on Computer Aided Modeling
|
||||||
|
and Design of Communication Links and Networks ({CAMAD})},
|
||||||
|
year = {2023},
|
||||||
|
doi = {10.1109/CAMAD59638.2023.10478422}
|
||||||
|
}
|
||||||
|
|
||||||
|
@inproceedings{bellavista2023entanglement,
|
||||||
|
author = {Paolo Bellavista and Nicola Bicocchi and Mattia Fogli
|
||||||
|
and others},
|
||||||
|
title = {Measuring Digital Twin Entanglement in Industrial Internet
|
||||||
|
of Things},
|
||||||
|
booktitle = {IEEE International Conference on Communications ({ICC})},
|
||||||
|
year = {2023},
|
||||||
|
doi = {10.1109/ICC45041.2023.10278787}
|
||||||
|
}
|
||||||
|
|
||||||
|
%% ── HPC DT runtime ───────────────────────────────────────────
|
||||||
|
|
||||||
|
@inproceedings{iraola2025hp2c,
|
||||||
|
author = {E. Iraola and others},
|
||||||
|
title = {{HP2C-DT}: High-Performance Computing-Enabled Digital Twin},
|
||||||
|
booktitle = {Energy and Power Systems Conference},
|
||||||
|
year = {2025}
|
||||||
|
}
|
||||||
1548
paper/splncs04.bst
Normal file
1548
paper/splncs04.bst
Normal file
File diff suppressed because it is too large
Load Diff
113
requirements.txt
Normal file
113
requirements.txt
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
anyio==4.13.0
|
||||||
|
appnope==0.1.4
|
||||||
|
argon2-cffi==25.1.0
|
||||||
|
argon2-cffi-bindings==25.1.0
|
||||||
|
arrow==1.4.0
|
||||||
|
asttokens==3.0.1
|
||||||
|
async-lru==2.3.0
|
||||||
|
attrs==26.1.0
|
||||||
|
babel==2.18.0
|
||||||
|
beautifulsoup4==4.14.3
|
||||||
|
bleach==6.3.0
|
||||||
|
certifi==2026.2.25
|
||||||
|
cffi==2.0.0
|
||||||
|
charset-normalizer==3.4.7
|
||||||
|
click==8.3.2
|
||||||
|
comm==0.2.3
|
||||||
|
contourpy==1.3.3
|
||||||
|
cycler==0.12.1
|
||||||
|
debugpy==1.8.20
|
||||||
|
decorator==5.2.1
|
||||||
|
defusedxml==0.7.1
|
||||||
|
executing==2.2.1
|
||||||
|
fastjsonschema==2.21.2
|
||||||
|
fonttools==4.62.1
|
||||||
|
fqdn==1.5.1
|
||||||
|
h11==0.16.0
|
||||||
|
httpcore==1.0.9
|
||||||
|
httpx==0.28.1
|
||||||
|
idna==3.12
|
||||||
|
importlib_metadata==9.0.0
|
||||||
|
ipykernel==7.2.0
|
||||||
|
ipython==9.12.0
|
||||||
|
ipython_pygments_lexers==1.1.1
|
||||||
|
ipywidgets==8.1.8
|
||||||
|
isoduration==20.11.0
|
||||||
|
jedi==0.19.2
|
||||||
|
Jinja2==3.1.6
|
||||||
|
json5==0.14.0
|
||||||
|
jsonpointer==3.1.1
|
||||||
|
jsonschema==4.26.0
|
||||||
|
jsonschema-specifications==2025.9.1
|
||||||
|
jupyter==1.1.1
|
||||||
|
jupyter-cache==1.0.1
|
||||||
|
jupyter-console==6.6.3
|
||||||
|
jupyter-events==0.12.1
|
||||||
|
jupyter-lsp==2.3.1
|
||||||
|
jupyter_client==8.8.0
|
||||||
|
jupyter_core==5.9.1
|
||||||
|
jupyter_server==2.17.0
|
||||||
|
jupyter_server_terminals==0.5.4
|
||||||
|
jupyterlab==4.5.6
|
||||||
|
jupyterlab_pygments==0.3.0
|
||||||
|
jupyterlab_server==2.28.0
|
||||||
|
jupyterlab_widgets==3.0.16
|
||||||
|
kiwisolver==1.5.0
|
||||||
|
lark==1.3.1
|
||||||
|
MarkupSafe==3.0.3
|
||||||
|
matplotlib==3.10.8
|
||||||
|
matplotlib-inline==0.2.1
|
||||||
|
mistune==3.2.0
|
||||||
|
nbclient==0.10.4
|
||||||
|
nbconvert==7.17.1
|
||||||
|
nbformat==5.10.4
|
||||||
|
nest-asyncio==1.6.0
|
||||||
|
notebook==7.5.5
|
||||||
|
notebook_shim==0.2.4
|
||||||
|
numpy==2.4.4
|
||||||
|
packaging==26.1
|
||||||
|
pandas==3.0.2
|
||||||
|
pandocfilters==1.5.1
|
||||||
|
parso==0.8.6
|
||||||
|
pexpect==4.9.0
|
||||||
|
pillow==12.2.0
|
||||||
|
platformdirs==4.9.6
|
||||||
|
prometheus_client==0.25.0
|
||||||
|
prompt_toolkit==3.0.52
|
||||||
|
psutil==7.2.2
|
||||||
|
ptyprocess==0.7.0
|
||||||
|
pure_eval==0.2.3
|
||||||
|
pycparser==3.0
|
||||||
|
Pygments==2.20.0
|
||||||
|
pyparsing==3.3.2
|
||||||
|
python-dateutil==2.9.0.post0
|
||||||
|
python-json-logger==4.1.0
|
||||||
|
PyYAML==6.0.3
|
||||||
|
pyzmq==27.1.0
|
||||||
|
referencing==0.37.0
|
||||||
|
requests==2.33.1
|
||||||
|
rfc3339-validator==0.1.4
|
||||||
|
rfc3986-validator==0.1.1
|
||||||
|
rfc3987-syntax==1.1.0
|
||||||
|
rpds-py==0.30.0
|
||||||
|
Send2Trash==2.1.0
|
||||||
|
setuptools==82.0.1
|
||||||
|
six==1.17.0
|
||||||
|
soupsieve==2.8.3
|
||||||
|
SQLAlchemy==2.0.49
|
||||||
|
stack-data==0.6.3
|
||||||
|
tabulate==0.10.0
|
||||||
|
terminado==0.18.1
|
||||||
|
tinycss2==1.4.0
|
||||||
|
tornado==6.5.5
|
||||||
|
traitlets==5.14.3
|
||||||
|
typing_extensions==4.15.0
|
||||||
|
tzdata==2026.1
|
||||||
|
uri-template==1.3.0
|
||||||
|
urllib3==2.6.3
|
||||||
|
wcwidth==0.6.0
|
||||||
|
webcolors==25.10.0
|
||||||
|
webencodings==0.5.1
|
||||||
|
websocket-client==1.9.0
|
||||||
|
widgetsnbextension==4.0.15
|
||||||
|
zipp==3.23.1
|
||||||
1
simulator/.gitignore
vendored
Normal file
1
simulator/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
6
simulator/Cargo.toml
Normal file
6
simulator/Cargo.toml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "simulator"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
3
simulator/src/main.rs
Normal file
3
simulator/src/main.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
}
|
||||||
1
substrate/.gitignore
vendored
Normal file
1
substrate/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
6
substrate/Cargo.toml
Normal file
6
substrate/Cargo.toml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "substrate"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
3
substrate/src/main.rs
Normal file
3
substrate/src/main.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user