physics.robotics.perception
physics.robotics.perception
Spatial memory footprints, evidence horizons, and teleoperation data budgets.
Functions
| Name | Description |
|---|---|
| calc_3dgs_memory_footprint | Count Gaussian-state storage under an explicit packing. |
| calc_free_space_expiry | Compute a free-space claim’s erosion horizon. |
| calc_linear_invalidation_horizon | Find the first passage of a linearly growing error allowance. |
| calc_octree_depth | Count halvings from a map edge to a target voxel edge. |
| calc_spatial_information_age_displacement | Compute displacement during a perception delay. |
| calc_sphere_scan_cells | Estimate voxel reads from a spherical query volume. |
| calc_target_evidence_horizon | Find when constant target drift consumes an error margin. |
| calc_teleop_ingestion_budget | Count uncompressed teleoperation traffic and hourly storage. |
| calc_tracked_evidence_horizon | Find when residual acceleration consumes a tracked error margin. |
| calc_tsdf_voxel_grid_budget | Estimate TSDF payload storage and assumed traversal traffic. |
| calc_voxel_quantization_error | Compute the maximum center-representation error of a cubic voxel. |
calc_3dgs_memory_footprint
physics.robotics.perception.calc_3dgs_memory_footprint(
num_gaussians,
bytes_per_gaussian=56,
)Count Gaussian-state storage under an explicit packing.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| num_gaussians | int | Positive count of Gaussian state records. | required |
| bytes_per_gaussian | int | Positive bytes per record; default 56 is an assumed packing, not a universal 3DGS layout. | 56 |
Returns
| Name | Type | Description |
|---|---|---|
| Quantity | Packed state storage in bytes. |
Notes
Equation: memory = num_gaussians * bytes_per_gaussian.
Assumptions: Each record uses the same caller-specified packing.
Excludes: Optimizer state, allocator overhead, renderer workspaces, and additional harmonic coefficients.
Equation: Memory = K_gaussians * bytes_per_gaussian
References
Derivation: Count records and multiply by storage per record; the packing is an input convention.
Examples
>>> from mlsysim.physics.robotics.perception import calc_3dgs_memory_footprint
>>> from mlsysim.core.units import ureg
>>> small = calc_3dgs_memory_footprint(10)
>>> large = calc_3dgs_memory_footprint(20)
>>> assert large == 2 * smallcalc_free_space_expiry
physics.robotics.perception.calc_free_space_expiry(
free_depth,
loc_bound,
protective_clearance,
approach_speed,
)Compute a free-space claim’s erosion horizon.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| free_depth | Quantity | Observed free depth in length units. | required |
| loc_bound | Quantity | Nonnegative localization allowance in length units. | required |
| protective_clearance | Quantity | Nonnegative clearance reserved before an approaching object reaches the task region. | required |
| approach_speed | Quantity | Positive assumed approach speed in length / time; supplied by the caller. | required |
Returns
| Name | Type | Description |
|---|---|---|
| Quantity | Expiry time in milliseconds, floored at zero. |
Notes
Equation: expiry = max(free_depth - loc_bound - protective_clearance, 0) / approach_speed.
Assumptions: An unseen object enters from the free-space boundary at a bounded constant speed.
Excludes: Occlusion geometry beyond a scalar depth, braking, speed-bound validation, and standards compliance.
Equation: T_inv = max(0, (d_free - delta_loc - delta_margin) / v_h)
The free region erodes from its unobserved boundary at the approach speed v_h; localization error delta_loc and the protective clearance delta_margin are spent up front. It is calc_linear_invalidation_horizon with E_0 = delta_loc, r = v_h, and E_max = d_free - delta_margin.
Source: linear invalidation horizon applied to occluded free space; the walking-speed bound v_h is ISO 13855’s K (1.6 m/s).
References
Derivation: Apply the linear invalidation horizon with initial_error = loc_bound and error_limit = free_depth - protective_clearance.
Examples
>>> from mlsysim.physics.robotics.perception import calc_free_space_expiry
>>> from mlsysim.core.units import ureg
>>> h = calc_free_space_expiry(3 * ureg.meter, 1 * ureg.meter, 1 * ureg.meter, 1 * ureg.meter / ureg.second)
>>> assert h == 1 * ureg.secondcalc_linear_invalidation_horizon
physics.robotics.perception.calc_linear_invalidation_horizon(
initial_error,
error_growth_rate,
error_limit,
)Find the first passage of a linearly growing error allowance.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| initial_error | Quantity | Initial error allowance in length units. | required |
| error_growth_rate | Quantity | Positive error-growth rate in length / time. | required |
| error_limit | Quantity | Allowed error in length units; a spent limit returns zero. | required |
Returns
| Name | Type | Description |
|---|---|---|
| Quantity | Invalidation horizon in milliseconds, floored at zero. |
Notes
Equation: horizon = max(error_limit - initial_error, 0) / error_growth_rate.
Assumptions: Monotone constant-rate growth of a scalar error allowance.
Excludes: Acceleration, new evidence, stopping capability, and confidence calibration.
Equation: E(dt) = E_0 + r * dt ; T_inv = max(0, (E_max - E_0) / r)
A zero result means the belief never supported the task: its initial error already consumes the tolerance. Unlike calc_target_evidence_horizon this does not raise when E_0 >= E_max; it floors the deadline at zero.
Source: first-passage time of a linear error bound (definition of the invalidation horizon, T_inv = inf{dt >= 0 : E(dt) >= E_max}); the reachable-set lineage for occluded free space is Orzechowski, Meyer, and Lauer 2018 (IEEE ITSC).
References
Derivation: Set a linear error envelope equal to the limit; clamp past crossings to time zero.
Examples
>>> from mlsysim.physics.robotics.perception import calc_linear_invalidation_horizon
>>> from mlsysim.core.units import ureg
>>> h = calc_linear_invalidation_horizon(2 * ureg.meter, 1 * ureg.meter / ureg.second, 1 * ureg.meter)
>>> assert h.magnitude == 0calc_octree_depth
physics.robotics.perception.calc_octree_depth(map_edge, pitch)Count halvings from a map edge to a target voxel edge.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| map_edge | Quantity | Positive cubic map edge; the intended hierarchy has map_edge >= pitch. | required |
| pitch | Quantity | Positive target leaf edge in the same length dimension. | required |
Returns
| Name | Type | Description |
|---|---|---|
| int | Ceiling of the base-two edge ratio; can be negative for out-of-regime pitch > map_edge. |
Notes
Equation: depth = ceil(log2(map_edge / pitch)).
Assumptions: Each level halves an edge and a query descends the full hierarchy.
Excludes: Allocation sparsity, early termination, memory latency, and automatic clamping of out-of-regime input.
Equation: depth = ceil(log2(L / r))
Each level is one dependent read in a point query.
Source: Hornung et al., “OctoMap,” Autonomous Robots 34(3), 2013, Sec. III.
References
Derivation: After d binary subdivisions the edge is map_edge/2**d; choose the least integer d attaining pitch.
Examples
>>> from mlsysim.physics.robotics.perception import calc_octree_depth
>>> from mlsysim.core.units import ureg
>>> assert calc_octree_depth(8 * ureg.meter, 1 * ureg.meter) == 3calc_spatial_information_age_displacement
physics.robotics.perception.calc_spatial_information_age_displacement(
velocity,
information_age,
)Compute displacement during a perception delay.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| velocity | Quantity | Nonnegative constant translational speed in length / time. | required |
| information_age | Quantity | Positive sensor-to-use age in time units. | required |
Returns
| Name | Type | Description |
|---|---|---|
| Quantity | Displacement in meters. |
Notes
Equation: displacement = velocity * information_age.
Assumptions: The supplied speed remains constant over the age interval.
Excludes: Acceleration, object motion not included in velocity, and collision assessment.
Equation: Delta_x = v * tau_age
Source: OpenStax, University Physics Volume 1, Sec. 3.1. Physical AI perception pipeline waterfall (exposure, readout, transport, DMA, ISP, backbone, IPC).
References
Derivation: Integrate constant velocity over the elapsed perception age.
Examples
>>> from mlsysim.physics.robotics.perception import calc_spatial_information_age_displacement
>>> from mlsysim.core.units import ureg
>>> distance = calc_spatial_information_age_displacement(1 * ureg.meter / ureg.second, 1 * ureg.second)
>>> assert distance == 1 * ureg.metercalc_sphere_scan_cells
physics.robotics.perception.calc_sphere_scan_cells(reach, pitch)Estimate voxel reads from a spherical query volume.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| reach | Quantity | Positive sphere radius including any clearance allowance. | required |
| pitch | Quantity | Positive cubic voxel edge length. | required |
Returns
| Name | Type | Description |
|---|---|---|
| float | Dimensionless continuum estimate of cells, not an integer enumeration. |
Notes
Equation: cells = (4*pi/3) * (reach / pitch)**3.
Assumptions: A dense read of every voxel within the spherical volume.
Excludes: Boundary-cell rounding, early exits, spatial indexes, and clearance certification.
Equation: N = (4/3) pi (reach / r)^3
reach is the sphere radius plus the protective clearance; every cell within it must be read, because an occupancy cell answers only whether that one cell is occupied.
Source: volume of a sphere in units of the voxel volume r^3.
References
Derivation: Divide sphere volume by cubic voxel volume.
Examples
>>> from mlsysim.physics.robotics.perception import calc_sphere_scan_cells
>>> from mlsysim.core.units import ureg
>>> small = calc_sphere_scan_cells(1 * ureg.meter, 0.1 * ureg.meter)
>>> large = calc_sphere_scan_cells(2 * ureg.meter, 0.1 * ureg.meter)
>>> assert large == 8 * smallcalc_target_evidence_horizon
physics.robotics.perception.calc_target_evidence_horizon(
tolerance_radius,
sensor_noise,
drift_velocity,
)Find when constant target drift consumes an error margin.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| tolerance_radius | Quantity | Positive spatial tolerance in length units. | required |
| sensor_noise | Quantity | Positive initial error allowance below tolerance_radius; a quantile is not a hard bound. | required |
| drift_velocity | Quantity | Positive drift-speed allowance in length / time. | required |
Returns
| Name | Type | Description |
|---|---|---|
| Quantity | Target-evidence validity horizon in milliseconds. |
Notes
Equation: horizon = (tolerance_radius - sensor_noise) / drift_velocity.
Assumptions: An initial scalar error plus constant bounded drift; interpretation follows the supplied allowances.
Excludes: Braking, fallback feasibility, clearance checks, and safety certification.
This is not a stopping-time or stopping-distance bound. Motion admission also needs current clearance, total pre-brake delay, achievable deceleration, and a feasible fallback after this evidence expires.
Equation: tau = (r_tol - e_0) / v_drift
References
Derivation: Solve initial error + drift*time = tolerance for time.
Examples
>>> from mlsysim.physics.robotics.perception import calc_target_evidence_horizon
>>> from mlsysim.core.units import ureg
>>> h = calc_target_evidence_horizon(2 * ureg.meter, 1 * ureg.meter, 1 * ureg.meter / ureg.second)
>>> assert h == 1 * ureg.secondcalc_teleop_ingestion_budget
physics.robotics.perception.calc_teleop_ingestion_budget(
num_cameras,
rgb_width,
rgb_height,
rgb_fps,
rgb_bytes_per_pixel=3,
depth_width=0,
depth_height=0,
depth_fps=0.0,
depth_bytes_per_pixel=2,
kinematics_bytes_per_sec=None,
tactile_bytes_per_sec=None,
)Count uncompressed teleoperation traffic and hourly storage.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| num_cameras | int | Positive count of identical camera streams. | required |
| rgb_width | int | Positive RGB image width in pixels. | required |
| rgb_height | int | Positive RGB image height in pixels. | required |
| rgb_fps | float | Positive RGB frame frequency in frames per second. | required |
| rgb_bytes_per_pixel | int | Positive RGB bytes per pixel; default 3. | 3 |
| depth_width | int | Depth width in pixels; default zero disables depth. | 0 |
| depth_height | int | Depth height in pixels; default zero disables depth. | 0 |
| depth_fps | float | Depth frames per second; depth is enabled only when width, height, and frequency are positive. | 0.0 |
| depth_bytes_per_pixel | int | Positive depth bytes per pixel; default 2. | 2 |
| kinematics_bytes_per_sec | Quantity | Nonnegative kinematics bandwidth in bytes / time; None means zero. | None |
| tactile_bytes_per_sec | Quantity | Nonnegative tactile bandwidth in bytes / time; None means zero. | None |
Returns
| Name | Type | Description |
|---|---|---|
| dict | RGB, depth, vision, kinematics, tactile, and total bandwidth in MB/s; storage_per_hour in TB. |
Notes
Equation: camera bandwidth = cameras*width*height*bytes_per_pixel*fps; total = RGB + depth + kinematics + tactile; hourly storage = total*3600 seconds.
Assumptions: Identical continuous camera streams and uncompressed fixed-size payloads.
Excludes: Compression, transport headers, indexes, replication, and storage write amplification.
Equation: BW_rgb = num_cameras * (W_rgb * H_rgb * Bpp_rgb) * FPS_rgb BW_depth = num_cameras * (W_depth * H_depth * Bpp_depth) * FPS_depth BW_kinematics = bytes_per_sec_kinematics BW_tactile = bytes_per_sec_tactile BW_total = BW_rgb + BW_depth + BW_kinematics + BW_tactile Storage_1hr = BW_total * 3600 s
References
Derivation: Multiply pixels per frame by bytes per pixel and frames per second, sum independent streams, and integrate over one hour.
Examples
>>> from mlsysim.physics.robotics.perception import calc_teleop_ingestion_budget
>>> from mlsysim.core.units import ureg
>>> budget = calc_teleop_ingestion_budget(1, 10, 10, 1)
>>> assert budget["bw_depth"].magnitude == 0
>>> assert budget["storage_per_hour"] == (budget["bw_total"] * ureg.hour).to("terabyte")calc_tracked_evidence_horizon
physics.robotics.perception.calc_tracked_evidence_horizon(
tolerance_radius,
initial_error,
slip_acceleration,
)Find when residual acceleration consumes a tracked error margin.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| tolerance_radius | Quantity | Positive spatial tolerance in length units. | required |
| initial_error | Quantity | Nonnegative initial error below tolerance_radius. | required |
| slip_acceleration | Quantity | Positive residual relative acceleration in length / time**2. | required |
Returns
| Name | Type | Description |
|---|---|---|
| Quantity | Tracked-evidence horizon in milliseconds. |
Notes
Equation: horizon = sqrt(2*(tolerance_radius - initial_error)/slip_acceleration).
Assumptions: Tracking removes initial relative velocity; residual acceleration is bounded by the input.
Excludes: Velocity-estimation error, braking, and proof of an acceleration bound.
A tracker that follows a moving target removes its steady velocity, so the remaining error growth comes from a bounded residual acceleration a_slip. A segment executed open-loop for a time T then drifts by a_slip T^2 / 2; setting that drift equal to the error margin r_tol - e_0 gives
Equation: tau_ev = sqrt(2 (r_tol - e_0) / a_slip)
This is the constant-acceleration counterpart of calc_target_evidence_horizon (constant drift velocity, a_slip = 0). Like that function it is not a stopping-time bound.
Source: first-passage time of a constant-acceleration displacement (d = a T^2 / 2, solved for T at d = r_tol - e_0); kinematics, derived here.
References
Derivation: Integrate constant acceleration from zero residual velocity, then solve displacement = remaining margin.
Examples
>>> from mlsysim.physics.robotics.perception import calc_tracked_evidence_horizon
>>> from mlsysim.core.units import ureg
>>> h = calc_tracked_evidence_horizon(2 * ureg.meter, 0 * ureg.meter, 1 * ureg.meter / ureg.second**2)
>>> assert h == 2 * ureg.secondcalc_tsdf_voxel_grid_budget
physics.robotics.perception.calc_tsdf_voxel_grid_budget(
workspace_volume,
voxel_size,
bytes_per_voxel=4,
sparsity_ratio=0.03,
block_size_voxels=512,
block_header_bytes=32,
ray_rate=None,
dense_voxels_per_ray=300,
sparse_voxels_per_ray=6,
free_voxels_per_ray=294,
bytes_per_ray_voxel=8,
cache_hit_rate=0.95,
)Estimate TSDF payload storage and assumed traversal traffic.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| workspace_volume | Quantity | Positive workspace bounding volume, convertible to cubic meters. | required |
| voxel_size | Quantity | Positive isotropic voxel edge length. | required |
| bytes_per_voxel | int | Positive payload bytes per voxel; default 4 stores distance and fusion weight. | 4 |
| sparsity_ratio | float | Active voxel fraction in [0, 1]; default 0.03 is an assumed scenario. | 0.03 |
| block_size_voxels | int | Positive voxel capacity per allocated leaf block; default 512. | 512 |
| block_header_bytes | int | Nonnegative metadata bytes per block; default 32. | 32 |
| ray_rate | Quantity or float | Nonnegative integration rays per second; None omits bandwidth outputs. | None |
| dense_voxels_per_ray | int | Nonnegative dense lookups per ray; default 300. | 300 |
| sparse_voxels_per_ray | int | Nonnegative TSDF-band updates per ray; default 6. | 6 |
| free_voxels_per_ray | int | Nonnegative free-space occupancy updates per ray; default 294. | 294 |
| bytes_per_ray_voxel | int | Nonnegative read/write bytes per lookup; default 8. | 8 |
| cache_hit_rate | float | Assumed cache-hit fraction in [0, 1]; default 0.95, not an inherent sparse-map property. | 0.95 |
Returns
| Name | Type | Description |
|---|---|---|
| dict | Integer voxel/block counts, dense_memory in GB, sparse_memory in MB; optional dense_dram_bandwidth in GB/s and sparse_dram_bandwidth in MB/s. |
Notes
Equation: N = round(V / pitch**3); A = round(N*sparsity); blocks = ceil(A / block_size); sparse bytes = blocks*(block_size*voxel_bytes + header); traffic = ray_rate*lookups*lookup_bytes, discounted by sparse cache misses.
Assumptions: Fixed voxel packing, rounded voxel counts, full leaf allocation, and caller-specified traversal/cache behavior.
Excludes: Complete occupancy-state storage, evidence epochs, allocator/index metadata, cache capacity analysis, and measured traffic prediction.
The four-byte voxel stores distance and fusion weight only. The sparse result includes the stipulated leaf header, but neither result includes a separate occupancy layer, per-cell evidence epochs, lookup/allocator metadata, or other full-map state. The hit rate is an assumed workload input, not a property of sparse allocation.
Equation: N_dense = V_workspace / (Delta_v)^3 M_dense = N_dense * B_voxel N_active = N_dense * S_sparsity N_blocks = ceil(N_active / B_block) M_sparse = N_blocks * (B_block * B_voxel + B_header) BW_dense_dram = R_rays * N_dense_lookups * B_lookup BW_sparse_dram = R_rays * (N_free_occupancy + N_TSDF_band) * B_lookup * (1 - Hit_cache)
References
Derivation: Count a regular grid, round active occupancy, allocate whole blocks, and sum per-ray memory transactions; this is explicit byte accounting, not a claim about a particular mapper.
Examples
>>> from mlsysim.physics.robotics.perception import calc_tsdf_voxel_grid_budget
>>> from mlsysim.core.units import ureg
>>> budget = calc_tsdf_voxel_grid_budget(1 * ureg.meter**3, 0.1 * ureg.meter)
>>> assert budget["dense_voxel_count"] == 1000
>>> assert budget["sparse_block_count"] == 1calc_voxel_quantization_error
physics.robotics.perception.calc_voxel_quantization_error(pitch)Compute the maximum center-representation error of a cubic voxel.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| pitch | Quantity | Positive cubic voxel edge length. | required |
Returns
| Name | Type | Description |
|---|---|---|
| Quantity | Half the voxel diagonal in millimeters. |
Notes
Equation: error = sqrt(3) * pitch / 2.
Assumptions: A point anywhere in a cubic voxel is represented by its center.
Excludes: Sensor error, map registration error, and noncubic cells.
Equation: e_q = (sqrt(3) / 2) r
Source: geometry of a cube of edge r.
References
Derivation: Apply the three-dimensional Pythagorean theorem to a corner-to-center offset.
Examples
>>> from mlsysim.physics.robotics.perception import calc_voxel_quantization_error
>>> from mlsysim.core.units import ureg
>>> a = calc_voxel_quantization_error(1 * ureg.millimeter)
>>> b = calc_voxel_quantization_error(2 * ureg.millimeter)
>>> assert b == 2 * a