Skip to content

Records

A Record is one observation unit. It can represent a patient visit, a machine run, or a market window.

Each Record owns a hierarchy of Sources and Signals:

flowchart TB
    R["Record"]
    D["Source: device"]
    S1["Source: sensor"]
    S2["Source: sensor"]
    A["Signal"]
    B["Signal"]
    R --> D
    D --> S1
    D --> S2
    S1 --> A
    S2 --> B

A Source represents a device, sensor, or subsystem. It can contain child Sources and direct Signals. A Signal is always a leaf.

Create a Record

Build the hierarchy from the leaves upward:

from timenet.dataset import Record, Source

accelerometer = Source(
    name="Accelerometer",
    signals=(acceleration_x, acceleration_y, acceleration_z),
)
imu = Source(
    name="IMU",
    sources=(accelerometer,),
)
record = Record(
    sources=(imu,),
    metadata={"site": "lab-a", "run": "run-001"},
)
dataset.add_record(record=record)

dataset.add_record() gives the Record and each of its Signals a read-only int64 id. A Source has no ID. Keep upstream identifiers, such as the run name above, in metadata or an annotation.

record.signals returns every Signal in deterministic hierarchy order. Use walk_sources() or walk_signals() when you need an iterator.

Each Source and Signal has one owner. TimeNet rejects cycles and objects attached in more than one place.

The root Sources of a Record must have distinct names, and so must the child Sources of a Source.

Store context

Use metadata for JSON-compatible details that do not need a typed schema. Examples include an internal site code or source-specific import data.

Use an Annotation for a typed, searchable fact. Examples include age, condition, firmware version, or an event on the timeline.

from timenet.types import Annotation

record.annotate(Annotation(key="condition", value="healthy"))

Sources and Signals also support metadata and annotate().

Add time information

Each Record has one TimeOrigin. All Signal offsets and time annotations use this common relative zero. The connector aligns the data before it constructs the Record.

from datetime import datetime, timezone
from timenet.dataset import Record, Source
from timenet.types import TimeOrigin

origin = TimeOrigin(datetime(2026, 1, 1, tzinfo=timezone.utc))
record = Record(
    start_time=origin,
    sources=(
        Source(name="sensor A", signals=(signal_a,)),
        Source(name="sensor B", signals=(signal_b,)),
    ),
)

record.start_time.timestamp is whole Unix microseconds or None. A missing absolute timestamp does not prevent relative alignment. The default is a fresh TimeOrigin(None) for each Record.

Related Records can explicitly share one origin, including an unknown origin. Separate unknown origins do not imply alignment. A converter must not invent a date, timezone, or synchronization.

A regular axis stores a cadence and an offset from the Record origin. An irregular axis stores each offset. An ordinal axis records order only, with no assumed elapsed time.

time_span can declare a session interval that contains all Signal windows. This field permits events during gaps when every sensor is off.

Connect tasks

A Task refers directly to its input Records. Registering a Task does not change those Records.

from timenet.types import ClassificationTask, Label, LabelSet

CONDITION = LabelSet(
    name="condition",
    labels=(Label(name="healthy"), Label(name="faulty")),
)

task = ClassificationTask(
    inputs=(record,),
    targets=("healthy",),
    label_set=CONDITION,
)
dataset.add_task(task=task)

Use dataset.tasks_for(record) to resolve the Task objects for one Record.