Irregular streams
Irregular streams emit a row only when something specific happens — a variable is updated, an expression is detected, a button is pressed, an agent takes a step. No trigger, no row. The rate is data-driven.
Use irregular streams for discrete observations that only exist at specific moments. For continuous signals that always have a value (position, gaze, pose), use regular streams instead.
The streams
| Stream | File | Trigger |
|---|---|---|
| Events | EventPoints.csv | Event-point firing, action execution, epoch transitions. The authoritative experimental-event log. |
| Variables | Variables.csv | Every variable write — assignment, modification, list update. |
| Expressions | Expressions.csv | Facial / hand expression detections above threshold. |
| Agents | AgentsData.csv | Agent observations, actions, rewards, episode state. Requires USING_AGENTS. |
| Input | InputCapture.csv | Key down / up / hold events for configured keys. |
| Interactives | InteractivesData_<Object>.csv | Per-interactive object state. (Per-frame inside each file, but per-object in scope.) |
Each stream's writer exposes a RecordEntry(observation) method that external code calls when the trigger fires. The observation is stamped with the current frame / time / epoch context at the moment the trigger fires (via LaboObservation.Stamp()), then queued for the writer.
During a one-minute session a participant presses the spacebar 12 times. InputCapture.csv has 12 rows, one per press event. ParticipantTracking.csv, a regular stream, has ~5400 rows (90 Hz × 60 s) — the 12 button presses are not visible as distinct events in it, only as sudden changes in controller velocity or position.
When are irregular rows stamped?
At trigger time, not at write time. The MonotonicExecutionTime and FrameNumber in an irregular row reflect the moment the trigger actually fired, accurate to microseconds. The corresponding ExperienceState row for the same frame (written during LateUpdate) will land a millisecond or two later — both share the same FrameNumber, so joining is exact.
See Timing → When is MonotonicExecutionTime captured for the full story.