"""Sensor row generators. Pure functions: (pose, rng, ts) -> row dict. Every row carries int64 epoch nanoseconds. Values are emitted at full float precision - quantization happens only in the broadcast payload, never in stored telemetry. """ from __future__ import annotations import math import random from typing import Any from .flight import Pose Row = dict[str, Any] def imu_row(pose: Pose, rng: random.Random, ts_ns: int) -> Row: return { "ts_ns": ts_ns, "accel_x": rng.gauss(0.0, 0.35), "accel_y": rng.gauss(0.0, 0.35), "accel_z": rng.gauss(-9.81, 0.25), "gyro_x": math.radians(rng.gauss(pose.roll, 0.8)), "gyro_y": math.radians(rng.gauss(pose.pitch, 0.8)), "gyro_z": math.radians(rng.gauss(0.0, 0.5)), } def baro_row(pose: Pose, rng: random.Random, ts_ns: int) -> Row: pressure = 101325.0 * math.exp(-pose.z / 8434.0) + rng.gauss(0.0, 4.0) return {"ts_ns": ts_ns, "pressure_pa": pressure, "alt_est_m": pose.z + rng.gauss(0.0, 0.3)} def temp_row(_pose: Pose, rng: random.Random, ts_ns: int) -> Row: return { "ts_ns": ts_ns, "cpu_c": 55.0 + rng.gauss(0.0, 3.0), "gpu_c": 62.0 + rng.gauss(0.0, 4.0), "ambient_c": 24.0 + rng.gauss(0.0, 0.5), } def battery_row(_pose: Pose, rng: random.Random, ts_ns: int, elapsed_s: float, duration_s: float) -> Row: level = max(0.0, 100.0 - 80.0 * elapsed_s / max(duration_s, 1.0) + rng.gauss(0.0, 0.2)) return {"ts_ns": ts_ns, "level_pct": level, "voltage_v": 22.2 * (0.85 + 0.15 * level / 100.0)} DETECTION_CLASSES = ("vehicle", "person", "animal", "structure", "unknown") def detection_row(pose: Pose, rng: random.Random, ts_ns: int) -> Row: return { "ts_ns": ts_ns, "cls": rng.choice(DETECTION_CLASSES), "confidence": round(rng.uniform(0.42, 0.99), 3), "obj_x": pose.x + rng.uniform(-40.0, 40.0), "obj_y": pose.y + rng.uniform(-40.0, 40.0), "obj_z": rng.uniform(0.0, 5.0), "ego_x": pose.x, "ego_y": pose.y, "ego_z": pose.z, } def state_row(pose: Pose, ts_ns: int) -> Row: return { "ts_ns": ts_ns, "pos_x": pose.x, "pos_y": pose.y, "pos_z": pose.z, "roll": pose.roll, "pitch": pose.pitch, "yaw": pose.yaw, "vel_x": pose.vx, "vel_y": pose.vy, "vel_z": pose.vz, "frame_ref": 0, }