Dataset Format
What's inside every SIMaaS dataset and how to use it.
R2 directory structure
Every run uploads to R2 under jobs/<job_id>/. The tree includes per-vehicle sensor data, ground-truth metadata, and scenario snapshots.
Frame numbering: Binary files are zero-padded to 6 digits (e.g., 000042.bin). Frame is the primary key across all sensors — all sensors reporting frame N are synchronised to the same simulation tick.
CSV sensor schemas
actors.csv
Ground-truth per-tick actor manifest. One row per actor per frame.
| Column | Unit / Type | Description |
|---|---|---|
| frame | integer | CARLA frame number |
| timestamp | seconds | Simulation time since world init |
| actor_id | integer | Unique CARLA actor ID |
| type_id | string | Actor type (vehicle.car, walker.pedestrian, etc.) |
| role | string | Actor role (ego, npc, pedestrian) |
| vehicle_index | integer | Which ego vehicle (0, 1, …) |
| x, y, z | meters | World position |
| pitch, yaw, roll | degrees | Rotation in world frame |
| vx, vy, vz | m/s | Velocity in world frame |
| wx, wy, wz | rad/s | Angular velocity |
| bbox_ext_x, _y, _z | meters | Bounding box extent (half-width) |
radar.csv
Automotive radar detections. Multiple rows per frame (one per detection); empty frames have zero rows.
| Column | Unit / Type | Description |
|---|---|---|
| frame | integer | CARLA frame number |
| timestamp | seconds | Simulation time |
| azimuth | radians | Bearing angle to detection |
| altitude | radians | Elevation angle to detection |
| depth | meters | Radial range to detection |
| velocity | m/s | Radial velocity (+ = approaching) |
imu.csv & gnss.csv
IMU: Inertial measurement unit (acceleration, angular velocity, compass). ~20 rows/sec (one per frame).
GNSS: Simulated GPS (latitude, longitude, altitude). ~20 rows/sec. Coordinates are CARLA synthetic, not real-world.
Metadata files
_landmarks.json
OpenDRIVE landmarks (traffic lights, stop signs, speed limits). Exported from the map at run start.
{
"map": "Town01",
"landmarks": [
{
"id": "1_landmark_123",
"type": "1001",
"name": "stop",
"x": 456.2,
"y": 789.1,
"z": 0.0,
"yaw": 0.0
},
{
"id": "1_landmark_124",
"type": "1000",
"name": "traffic_light",
"x": 500.0,
"y": 800.0,
"z": 3.0,
"yaw": 1.57
}
]
}_meta/summary.json
Single-line run summary with exit code, frame counts, and cost estimate.
{
"job_id": "job_abc123def",
"status": "complete",
"frames": 400,
"bytes": 5242880000,
"wallclock_seconds": 1234,
"cost_estimate_gbp": 0.34,
"exit_code": 0,
"schema_version": 1
}Binary sensors (RGB, depth, lidar)
Raw CARLA byte buffers without re-encoding. One file per frame.
- RGB: 800×600 BGRA, 4 bytes/pixel. np.frombuffer(b, dtype=np.uint8).reshape(600, 800, 4)
- Depth: 800×600 BGRA-encoded depth in meters. depth_m = (R + G×256 + B×65536) / (256³ - 1) × 1000.0
- Lidar: Float32 quartets (x, y, z, intensity). np.frombuffer(b, dtype=np.float32).reshape(-1, 4)
Key notes
- Synchronisation: All sensors align by frame number (primary key). Join on
frameto align across modalities. - Frame rate: 20 Hz fixed. Each tick = 50 ms.
- Reproducibility: Same scenario + seed + CARLA version = identical sensor output.
- IMU note: Frame 1 contains spawn noise. Skip frames 1–2 or filter on
|ax| < 100during analysis.