Ex: Synthetic Scene
Record a generated scene as a .vynt log with Python.
This example records a synthetic scene as a .vynt log: build each frame from a generated point matrix with VoyantFrame.synthetic(), declare the scan configuration with with_sdl(), and record the sequence. The output opens in the visualizer and replays like any sensor recording, identified by its SIM-SW device id — useful for turning simulator output (e.g. a Python-wrapped simulation scene) into an analyzable Voyant log.
Requires pip install voyant-api.
What You’ll Learn
- How to build frames from generated points with
VoyantFrame.synthetic() - How to declare the scan configuration a synthetic scene claims with
with_sdl() - How to record the sequence into a normal
.vyntrecording
Prerequisites
- Python 3.9 or later
voyant-apiinstalled:pip install voyant-api- No sensor needed — the scene is generated
Example Code
View the complete example on GitHub: synthetic_scene_example.py
Key Concepts
Generating Points
Frames are built from a matrix in the points() column layout — VoyantFrame.points_columns() gives the column order. The example generates a wall of points on an equally spaced azimuth/elevation grid whose range drifts over time; swap the generator for your own (e.g. points sampled from a simulator scene) and keep the rest of the loop as is:
import math
import numpy as np
from voyant_api import ProductId, RecordStatus, SdlCommand, SdlState, VoyantFrame, VoyantRecorder, init_voyant_logging
init_voyant_logging()
COLS = VoyantFrame.points_columns()
# Range drifts per frame so playback visibly moves
range_m = 10.0 + 2.0 * math.sin(2.0 * math.pi * frame_number / 50.0)
matrix = np.zeros((n_points, len(COLS)))
matrix[:, COLS.index("range_m")] = range_m
matrix[:, COLS.index("azimuth_rad")] = azimuths
matrix[:, COLS.index("elevation_rad")] = elevations
matrix[:, COLS.index("drop_reason")] = 1 # valid
Building Synthetic Frames
VoyantFrame.synthetic() takes the point matrix, a software source identity, and per-frame identity (timestamps and frame index). with_sdl() then declares the configuration the scene claims to have been generated under — it replays as applied sensor configuration, visible in the visualizer’s state panels:
sdl = SdlCommand()
sdl.req_state = SdlState.PointCloud
sdl.frame_rate_fps = 10.0
sdl.hfov_deg = 90.0
frame = VoyantFrame.synthetic(
matrix,
source=ProductId.SoftwareSimulator,
timestamp_seconds=seconds,
timestamp_nanoseconds=nanoseconds,
frame_index=i,
).with_sdl(sdl)
A synthetic frame always carries a software device identity — synthetic() rejects a real sensor’s id, so generated data cannot pass as a sensor’s. Points that did come from a real sensor but without its heartbeat (a ROS cloud, a CSV) belong in a stateless() frame, which may name it.
Recording the Sequence
Synthetic frames record like any other:
with VoyantRecorder("synthetic_scene.vynt", timestamp_filename=False) as recorder:
for i in range(n_frames):
frame = build_frame(i)
if recorder.record_frame(frame) != RecordStatus.OK:
raise SystemExit(f"Failed to record frame {i}")
Command Line Options
python synthetic_scene_example.py
# Custom output path and frame count
python synthetic_scene_example.py --output my_scene.vynt --frames 250
Expected Output
Recorded 100 synthetic frames to synthetic_scene.vynt
View it by running: voyant_visualizer --input synthetic_scene.vynt
Open the result in the visualizer — with --input as printed, or from its Open File… dialog — it plays back like a sensor recording.
Next Steps
- Synthetic Scene (C++) — the same flow with
VoyantFrame::synthetic() - Playback — process the recorded scene as DataFrames
- API Reference — full
VoyantFramereference