53def load(run_id: str) -> dict[str, list[tuple[float, float]]]:
54 """entity -> [(applied_at_seconds, offset_kg), ...] ascending.
56 Missing or malformed → {}. A viewer must never fail to open a run over its metadata, and a
57 partially-written last line is expected: the file is appended to while the run is live.
65 events: dict[str, list[tuple[float, float]]] = {}
66 for line
in text.splitlines():
71 rec = json.loads(line)
72 except json.JSONDecodeError:
75 entity = rec.get(
"entity")
76 applied = rec.get(
"appliedAtMs")
77 if not isinstance(entity, str)
or not isinstance(applied, (int, float)):
79 offset = 0.0
if rec.get(
"event") ==
"clear" else rec.get(
"offsetKg")
80 if not isinstance(offset, (int, float))
or not np.isfinite(float(offset)):
82 events.setdefault(entity, []).append((float(applied) / 1000.0, float(offset)))
84 for ev
in events.values():
85 ev.sort(key=
lambda e: e[0])
113def apply(run_id: str, entity: str, t: np.ndarray, v: np.ndarray) -> np.ndarray:
114 """Subtract the offset that was in effect at each sample time.
116 A step function, not one offset across the whole array: a tare set partway through a run must
117 leave everything before it absolute, or the pre-tare portion of every run reads wrong.
119 events =
load(run_id).get(entity)
120 if not events
or len(t) == 0:
122 times = np.array([e[0]
for e
in events], dtype=float)
123 offsets = np.array([e[1]
for e
in events], dtype=float)
125 idx = np.searchsorted(times, t, side=
"right") - 1
126 applied = np.where(idx >= 0, offsets[np.clip(idx, 0, len(offsets) - 1)], 0.0)