Docs menu

// Sensors

Sensor performance and troubleshooting

How sensor count, resolution and passes change render time, GPU memory and cloud price; the limits; and the rig errors you can hit, with their fixes.

View as Markdown

Render time#

A 3D render draws every camera at every one of its frames, so its time grows with the number of cameras x pixels x frames, plus a fixed cost to load the map. Lidar and radar add ray casts and a review video each. Measured on an RTX 5080 with the three example rigs on easterbrook-discovery-school, a 10 second scenario:

RigPresetFrames writtenRender timeOf which drawingOutput on disk
Front camera, 1280x720showcase200 x 4 passes15.3 s9.1 s0.9 GB
Seven cameras, 1280x720training1400 x 4 passes36.0 s23.8 s6.3 GB
Camera, lidar and radarshowcase200 x 4 passes, 200 scans, 200 radar frames25.6 s14.8 s1.8 GB

Peak GPU memory stayed under 2.5 GiB for all three, with full textures. Most of the rest of the time is encoding the videos (10.9 s for the seven cameras) and loading the map and actors (about 3 s). A single simforge preview frame took 9 s.

To render faster: use --preset training, lower width and height, render a part of the scenario with the rig's clip, ask only for the passes you need (--passes rgb), and skip videos you do not need (--video off). Check a mount with simforge preview frame before a full render.

GPU memory#

GPU memory depends far more on the map and the texture tier than on the cameras. On san-ramon-phase-1 with full textures, one 1280x720 camera peaks at 11.3 GiB and six 1920x1080 cameras at 11.9 GiB; with 512 px textures (--textures bc7-512), 3.8 and 4.5 GiB. The full table per map is in Preview and render. A render that does not fit fails with native_gpu_out_of_memory: use --textures bc7-512, fewer or smaller cameras, or --cloud.

Cloud price#

A cloud render's price does not depend on the rig: more cameras, lidar or radar do not change it, and 2D renders are free. --dry-run shows the price before anything runs, and --max-cost caps it (Run in the cloud). A cloud render returns each sensor's video, render.json and results.json; render locally for the per-frame images, depth and point clouds.

Limits#

WhatLimit
Sources in a rig1 to 64
Camera size64 to 8192 pixels in the file; the renderer draws at most 4096x4096
Camera frame rateabove 0, up to 240 fps
Pinhole field of viewabove 0, up to 180 degrees
Lidar1 to 256 channels, range up to 1000 m, up to 240 revolutions per second, symmetric vertical field
Radarfields up to 180 degrees, range up to 1000 m, at least one ray per frame
Rotationyaw and roll -pi to pi, pitch -pi/2 to pi/2, in radians

Rig errors and fixes#

simforge rig validate prints one JSON error and exits 2. These are its real messages:

Message (render_rig_invalid)Fix
sources[0].attributes: unknown field fx, expected one of width, height, fps, horizontalFovDeg, nearM, farM, cameraModelThe rig has no fx/fy/cx/cy: give horizontalFovDeg = 2 x atan(width / (2 x fx)) in degrees
sources[0]: a camera declares exactly one of horizontalFovDeg and cameraModelKeep the field of view or the lens, not both and not neither
sources[0]: camera size 10000x720 is outside 64..8192Lower width or height (the renderer draws at most 4096)
sources[0]: fps 0 is outside (0, 240]Give a frame rate above 0
sources[0]: nearM must be positive and farM greater than nearMUse nearM 0.05 and farM 1000 unless you need others
sources[6]: transform.rotation is outside yaw/roll [-pi, pi], pitch [-pi/2, pi/2]A rear camera is yaw 3.14159, not 3.1416; a downward camera is pitch -1.5708
duplicate source outputName "cam-front"Give every source its own outputName
sources[0]: outputName "front cam" must match ^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$Use letters, digits, - and _, no spaces
sources[0].modality "thermal" (rgb|depth|semantic|instance|lidar|radar)Thermal is not supported; use rgb, lidar or radar
rig schema "simforge.render-rig/v2" (expected simforge.render-rig/v1)Set schema to simforge.render-rig/v1

A render then checks what the renderer supports; its errors are listed in the rig file reference. The most common:

ErrorFix
native_modality_unsupportedA depth, semantic or instance source: make it rgb and choose passes with --passes
native_lidar_asymmetric_fov_unsupportedMake the lidar's field symmetric: upperFovDeg = -lowerFovDeg
render_schedule_invalid (a radar)Add video to the rig; its fps is the radar's sample rate
native_camera_size_unsupportedKeep cameras at 4096x4096 or smaller
render_ego_missingThe scenario has no ego: simforge scenario apply s.json set-ego --role-id <actor>
preview_camera_unknown--camera takes a camera's outputName; the error lists the rig's cameras
out_not_empty--out must be a new or empty folder; a failed render can leave <out>.input behind: remove it too

FAQ#

My images are mirrored left to right, or a side camera shows the wrong side. The frame is x forward, y up, z left, and yaw is positive to the left. A calibration in a right-handed frame needs converting. simforge rig show names each sensor's facing.

Can I give fx, fy, cx and cy? Not yet. A pinhole camera is square-pixelled with the principal point at the centre: set horizontalFovDeg = 2 x atan(width / (2 x fx)). For a lens with distortion, fit an f-theta polynomial.

Which distortion models are supported? The f-theta polynomial only. Brown-Conrady (OpenCV), Kannala-Brandt and equidistant fisheye are not supported yet.

Do I need one rig per scenario? No. A rig names no scenario: pass the same file to every render. Every source is mounted on the scenario's ego.

Do I need one rig per vehicle? Positions are absolute metres, so a car rig on a truck keeps the car's mount heights. Write one rig per vehicle class, or start from simforge rig init --preset <preset> --class <class>.

Can Studio use my rig file? Not yet: Studio offers the built-in rigs and the rig a scenario last rendered with. Render your rig with the CLI, locally or with --cloud.

Why does my cloud render have no PNGs or point clouds? A cloud 3D render returns the videos, render.json and results.json. Render locally for the per-frame files.

Every radar detection is a few centimetres away. The radar is inside the vehicle's body and sees only the body. Move it just outside: the example's front radar sits 0.2 m ahead of the box's front edge.

My lidar wrote more scans than it made revolutions. It writes one full scan per rendered frame, at the camera rate, not one per revolution. See lidar files.

Are IMU or GNSS supported? Not as sensors. The ego's exact pose at every frame is in observed-frames.jsonl.