Quick Start
This page gets you from installation to a running networked CartPole in five minutes, using the built-in Gilbert–Elliott channel (no ns-3 required).
Single observer
Wrap any Gymnasium environment with NetworkedEnv:
import gymnasium as gym
from netrl import NetworkedEnv, NetworkConfig
config = NetworkConfig(
p_gb=0.10, # Good → Bad transition probability per step
p_bg=0.30, # Bad → Good transition probability per step
loss_good=0.01, # Packet loss in Good state
loss_bad=0.20, # Packet loss in Bad state
delay_steps=2, # Propagation delay (integer steps)
buffer_size=10, # Observation window length
seed=42,
)
env = NetworkedEnv(gym.make("CartPole-v1"), config)
obs, info = env.reset()
print(obs["observations"].shape) # (10, 4) — 10-step window, 4-dim obs
print(obs["recv_mask"].shape) # (10,) — True where packet arrived
obs, reward, term, trunc, info = env.step(env.action_space.sample())
print(info["channel_info"]["state"]) # "GOOD" or "BAD"
print(info["arrived_this_step"]) # True / False
The agent receives a sliding-window buffer of the last buffer_size
observations. Slots where packets were lost or delayed are zero-filled;
recv_mask marks which slots actually received data.
Multiple observers (multi-view)
Use MultiViewNetworkedEnv when multiple sensors each transmit
their own (possibly different-shaped) observations to a central node.
import numpy as np
import gymnasium as gym
from netrl import NetworkConfig, MultiViewNetworkedEnv
from netrl.channels.comm_channel import GEChannel
from netrl.utils.multi_view_model import MultiViewModel
# --- Define what each sensor observes ---
class MySensors(MultiViewModel):
def observe(self, env, state):
# state is the raw gym observation; each sensor produces its own
return {
"lidar": state[:2].astype(np.float32), # 2-dim
"camera": np.random.randn(8).astype(np.float32), # 8-dim
}
mv_model = MySensors(
observer_ids=["lidar", "camera"],
obs_shapes=[(2,), (8,)],
obs_dtypes=[np.float32, np.float32],
)
env = MultiViewNetworkedEnv(
gym.make("CartPole-v1"),
NetworkConfig(buffer_size=8, loss_bad=0.3),
observer_ids=["lidar", "camera"],
multi_view_model=mv_model,
channel_factory=GEChannel,
)
obs, info = env.reset()
# obs["lidar"]["observations"].shape == (8, 2)
# obs["camera"]["observations"].shape == (8, 8)
# Per-step control: only transmit lidar this step, with 64 bytes
obs, r, term, trunc, info = env.step(
env.action_space.sample(),
transmit_mask={"lidar": True, "camera": False},
packet_sizes={"lidar": 64},
)
print(info["transmitted_this_step"]) # {"lidar": True, "camera": False}
print(info["arrived_this_step"]) # {"lidar": True/False, "camera": False}
Switching to the fast ns-3 WiFi channel
The recommended 802.11a backend runs entirely in-process — no subprocess to
build, no pipe overhead. It is compiled automatically by pip install -e .
when ns3 is pip-installed.
from netrl import NetworkedEnv, NetworkConfig, NS3WiFiChannelFastConfig
env = NetworkedEnv(
gym.make("CartPole-v1"),
NetworkConfig(buffer_size=10, seed=42),
channel_config=NS3WiFiChannelFastConfig(
distance_m=30.0,
step_duration_ms=2.0,
tx_power_dbm=20.0,
loss_exponent=3.0,
),
)
obs, info = env.reset()
for _ in range(1000):
obs, reward, term, trunc, info = env.step(env.action_space.sample())
if term or trunc:
obs, info = env.reset()
The simulation state (MAC buffers, backoff counters) persists across steps, giving temporally correlated, realistic channel behaviour.
Switching to the ns-3 WiFi channel (subprocess)
Build the binary once, then pass an NS3WifiConfig:
bash src/build_ns3_sim.sh
from netrl import NetworkedEnv, NetworkConfig, NS3WifiConfig
env = NetworkedEnv(
gym.make("CartPole-v1"),
NetworkConfig(buffer_size=10),
channel_config=NS3WifiConfig(
distance_m=30.0,
step_duration_ms=2.0,
tx_power_dbm=20.0,
loss_exponent=3.0,
),
)
The ns-3 process runs continuously alongside your Python code; the simulation state (MAC buffers, backoff counters) persists across steps.
Next steps
Single-Observer Environments — full NetworkedEnv usage guide
Multi-View Environments — complete MultiViewNetworkedEnv guide
Choosing a Channel Backend — choosing and configuring channel backends
API Reference — full API reference