# Data model core concepts

Nominal’s data store carries two categories of information: your test data, in the form of [time series](https://dev.nominal.io/platform/data-model.md#time-series-data) information, and metadata which provides a relational mapping between that test data and the physical world. The metadata is what makes more complex queries possible.

## Overview

Assets reach datasets through data scopes, and runs and events mark time ranges on an asset. Click a box to go to its section.

```mermaid
---
config:
  layout: elk

---
flowchart TB
    asset["Asset"]
    run["Run"]
    event["Event"]
    scope["Data scope"]
    dataset[("Dataset")]
    asset ---|"many, time-bounded"| run
    asset ---|"many, time-bounded"| event
    asset ---|"many"| scope
    scope ---|"filters one"| dataset
    click asset href "#asset" "Asset"
    click run href "#runs" "Runs"
    click event href "#events" "Events"
    click scope href "#data-scopes-and-ref-names" "Data scopes and ref names"
    click dataset href "#data-model-dataset" "Time-series data"
    classDef linked fill:#dcfce7,stroke:#15803d,color:#1f2937
    classDef notlinked fill:#fee2e2,stroke:#b91c1c,color:#1f2937
    classDef data fill:#e0e7ff,stroke:#4338ca,color:#1f2937
    class asset linked
    class run,event notlinked
    class dataset data
```

## Time-series data

At the most fundamental level, [time-series](https://dev.nominal.io/platform/reference/glossary.md#series-or-time-series "A sequence of values over time that shows how a signal changes. It can be numeric, categorical, log-based, or range-based.") data is a named set of (time, value) points. The named identifier for the set is a [Channel](https://dev.nominal.io/platform/reference/glossary.md#channel "A named signal: a series of measurements or computed values, such as voltage, pressure, or system state.").

One time series

| Time | Measurement |
| --- | --- |
| 12:00:00 | 100.0 |
| 12:00:01 | 200.0 |
| 12:00:02 | 300.0 |
| 12:00:03 | 200.0 |

Separate channels may have identical time values or the time values can be unique – Nominal will store them just the same.

Two synchronized channels that share timestamps

| Time | Measurement A | Measurement B |
| --- | --- | --- |
| 12:00:00 | 100.0 | 300.0 |
| 12:00:01 | 200.0 | 200.0 |
| 12:00:02 | 300.0 | 100.0 |
| 12:00:03 | 200.0 | 200.0 |

Two channels with their own timestamps

| Time A | Measurement A | Time B | Measurement B |
| --- | --- | --- | --- |
| 12:00:00 | 100.0 | 12:00:00.4 | 300.0 |
| 12:00:01 | 200.0 | 12:00:01.9 | 200.0 |
| 12:00:02 | 300.0 | 12:00:03.1 | 100.0 |
| 12:00:03 | 200.0 |  |  |

These time-series channels are collected in a light wrapper called a [dataset](https://dev.nominal.io/platform/reference/glossary.md#dataset "A store in Nominal for time-series and log data, which grows as you upload or stream more into it."). A dataset provides the ability to mark the entire collection of time series data with useful metadata. Nominal will automatically report the time range of the set and the channels in the set while users may apply arbitrary [properties](https://dev.nominal.io/platform/reference/glossary.md#property "A key-value pair, of type Text or Number, that describes an asset, run, or data source, such as an identifier, context, or a quantity.") (key value pairs such as “serial”=”ABADCAFE”) or [labels](https://dev.nominal.io/platform/reference/glossary.md#label "A short piece of text for grouping, searching, and filtering assets, runs, data sources, and events, such as prototype or night-flight.") (standalone text like “aborted-test”).

The time-series data in a dataset can be streamed directly from your tester or uploaded from files in common data formats (csv, mat, tdms, hdf5, etc.).

### Channels

In addition to the name, [channels](https://dev.nominal.io/platform/reference/glossary.md#channel "A named signal: a series of measurements or computed values, such as voltage, pressure, or system state.") provide another metadata source which can be used to better identify data. Specifically channels can be assigned a unit and a description.

Each channel also has a data type, so it holds one kind of value, such as floating-point numbers, integers, strings or video.

In addition, each *point* in a channel can have key-value pairs associated with it. These key-value pairs are called [tags](https://dev.nominal.io/platform/reference/glossary.md#tag "A key-value pair on your data points, such as motor_id: 1, that lets you filter a subset of points from a single dataset.") and allow for advanced filtering (see [Using a single dataset for many identical assets](https://dev.nominal.io/platform/data-model/organization/tagged-data.md)).

## Metadata

Datasets alone can hold your data. Metadata describes it in terms of physical entities ([`assets`](https://dev.nominal.io/platform/data-model.md#asset)), time ranges ([`runs`](https://dev.nominal.io/platform/data-model.md#runs)), and zones of interest ([`events`](https://dev.nominal.io/platform/data-model.md#events)).

### Asset

An [asset](https://dev.nominal.io/platform/reference/glossary.md#asset "A physical or simulated device or system you track in Nominal, such as a vehicle, a component, a unit under test, or a test stand.") represents a physical piece of equipment. That could be a device/unit under test (DUT/UUT) or the reverse, a test station or harness.

Assets and datasets can be linked together in a many-to-many relationship. That is, an asset may be linked to many datasets, and a single dataset can be linked to many assets. The link between an asset or run and a dataset is called a [data scope](https://dev.nominal.io/platform/reference/glossary.md#data-scope "The link between an asset or run and a data source, named by its ref name. It can filter the data source by tags and shift its timestamps."), and it can filter the dataset.

```mermaid
---
config:
  layout: elk

---
flowchart TB
    asset1["Asset"]
    dataset1[("Dataset")]
    dataset2[("Dataset")]
    dataset3[("Dataset")]
    asset2["Asset"]
    asset1 ---|"data scope filter"| dataset1
    asset1 ---|"data scope filter"| dataset2
    asset1 ---|"data scope filter"| dataset3
    dataset1 ---|"data scope filter"| asset2
    dataset3 ---|"data scope filter"| asset2
    click asset1 href "#asset" "Asset"
    click asset2 href "#asset" "Asset"
    click dataset1 href "#data-model-dataset" "Datasets"
    click dataset2 href "#data-model-dataset" "Datasets"
    click dataset3 href "#data-model-dataset" "Datasets"
    classDef linked fill:#dcfce7,stroke:#15803d,color:#1f2937
    classDef data fill:#e0e7ff,stroke:#4338ca,color:#1f2937
    class asset1,asset2 linked
    class dataset1,dataset2,dataset3 data
```

### Runs

A [run](https://dev.nominal.io/platform/reference/glossary.md#run "A named, time-bounded period of interest on one or more assets, such as a test, a flight, or a race session.") is simply a labeled time range. You can apply time ranges, including overlapping time ranges, as appropriate to describe your data. For example, runs can describe a test step or a test campaign, or runs could describe the state of your system during a test (“idle”, “ramping”, “coast”, “shutdown”).

Runs also allow users to attach labels, properties, and links to further describe the time range. For example, a set of test steps could all be assigned a property or label which specifies the test campaign they are part of, or specific operational parameters used for the test.

```mermaid
---
config:
  layout: elk

---
flowchart TB
    asset1["Asset"]
    run1["Run: 12:00-12:13"]
    run2["Run: Test step 9.6"]
    run3["Run: Test Campaign A"]
    run4["Run: Idling"]
    asset2["Asset"]
    asset1 ---|" "| run1
    asset1 ---|" "| run2
    asset1 ---|" "| run3
    asset1 ---|" "| run4
    run1 ---|" "|asset2
    run3 ---|" "|asset2
    click asset1 href "#asset" "Asset"
    click asset2 href "#asset" "Asset"
    click run1 href "#runs" "Runs"
    click run2 href "#runs" "Runs"
    click run3 href "#runs" "Runs"
    click run4 href "#runs" "Runs"
    classDef linked fill:#dcfce7,stroke:#15803d,color:#1f2937
    class run1,run2,run3,run4 linked
```

### Events

An [event](https://dev.nominal.io/platform/reference/glossary.md#event "A point or span in time that marks something meaningful, such as the start of a burn, a failure, or a rule violation.") is a labeled time range or instant. A run describes what the *system* was doing during a time range, while an event marks how the *data* behaved. For example, an event can mark when a channel exceeds a limit, or an unusual result during a specific test step.

As with runs, events are associated with assets and can store additional labels and properties.

In the Nominal UI, events can also be reviewed. When a section of data looks wrong, you flag it for review by creating an event. [Checklists](https://dev.nominal.io/platform/reference/glossary.md#checklist "A versioned set of checks that you execute on runs or assets to evaluate test data during or after a test.") automate that flagging, because each [check](https://dev.nominal.io/platform/reference/glossary.md#check "A rule that evaluates time-series data against a condition, such as a threshold or a state change, and creates an event wherever the condition is met.") in a checklist creates an event wherever its condition is met.

```mermaid
---
config:
  layout: elk

---
flowchart TB
    asset1["Asset: System"]
    event1["Event: temperature too high"]
    event2["Event: power output mismatch"]
    event3["Event: undervoltage"]
    asset2["Asset: Subsystem"]
    asset1 ---|" "| event1
    asset1 ---|" "| event2
    asset1 ---|" "| event3
    event1 ---|" "|asset2
    event3 ---|" "|asset2
    click asset1 href "#asset" "Asset"
    click asset2 href "#asset" "Asset"
    click event1 href "#events" "Events"
    click event2 href "#events" "Events"
    click event3 href "#events" "Events"
    classDef linked fill:#dcfce7,stroke:#15803d,color:#1f2937
    class event1,event2,event3 linked
```

### Advanced Metadata

#### Data scopes and ref names

A [data scope](https://dev.nominal.io/platform/reference/glossary.md#data-scope "The link between an asset or run and a data source, named by its ref name. It can filter the data source by tags and shift its timestamps.") is the under-the-hood link between an asset or run and a dataset. This link is named by the [ref name](https://dev.nominal.io/platform/reference/glossary.md#ref-name "The name an asset or run gives each data source attached to it, such as default. Workbooks and checklists find channels by ref name and channel name."). For legacy reasons, some documentation refers to the ref name as a “data scope name” or “refname”, but these all represent the same concept.

Data scopes have an optional filter which permits users to indicate that only a *portion* of the dataset is actually associated with an asset.

Data scopes can also shift timestamps. For example, if two loggers on a test system aren’t precisely time-synchronized, their data is offset by a small, fixed amount. Once you’ve measured that offset, for example from a start trigger both loggers recorded, set it on the data scope to align the two sources without changing the stored timestamps. It doesn’t correct drift between clocks over a long test.

The most important thing for an advanced user looking at data scopes to understand is that the ref name is always used as a namespace for every channel in its *scoped* dataset. That is, workbooks don’t look at `dataset.channel` they look at `ref name.channel`. This is powerful because a ref name serves as a pointer to an arbitrary portion of a dataset regardless of the rest of the content in that dataset. That power adds complexity, and users are recommended to review [Organize and view your data](https://dev.nominal.io/platform/data-model/paradigms.md) to better understand how to configure this data model for their needs.

```mermaid
---
config:
  layout: elk

---
flowchart TB
    asset1["Asset A"]
    scope1["Data scope W"]
    scope2["Data scope X"]
    dataset1[("Dataset 1")]
    dataset2[("Dataset 2")]
    dataset3[("Dataset 3")]
    scope3["Data scope Y"]
    scope4["Data scope Z"]
    asset2["Asset B"]
    asset1 ---|"refname=tester"| scope1
    asset1 ---|"refname=controller"| scope2
    asset2 ---|"refname=controller"| scope3
    asset2 ---|"refname=tester"| scope4
    scope1 ---|"filters"| dataset1
    scope2 ---|"filters"| dataset2
    scope3 ---|"filters"| dataset2
    scope4 ---|"filters"| dataset3
    click asset1 href "#asset" "Asset"
    click asset2 href "#asset" "Asset"
    click scope1 href "#data-scopes-and-ref-names" "Data scopes and ref names"
    click scope2 href "#data-scopes-and-ref-names" "Data scopes and ref names"
    click scope3 href "#data-scopes-and-ref-names" "Data scopes and ref names"
    click scope4 href "#data-scopes-and-ref-names" "Data scopes and ref names"
    click dataset1 href "#data-model-dataset" "Datasets"
    click dataset2 href "#data-model-dataset" "Datasets"
    click dataset3 href "#data-model-dataset" "Datasets"
    classDef linked fill:#dcfce7,stroke:#15803d,color:#1f2937
    classDef notlinked fill:#fee2e2,stroke:#b91c1c,color:#1f2937
    classDef data fill:#e0e7ff,stroke:#4338ca,color:#1f2937
    class scope1,scope2,scope3,scope4 linked
```

#### Compositions

A composition is a dataset that combines other datasets without copying their points, so it stays current as those datasets grow. You can filter each input by tag, give it a tag that tells its data apart from the other inputs, and shift it in time. Attach a composition to an asset like any other dataset.

Create a composition on an empty dataset, and upload new data into its input datasets. To build one in the app, see [🔒︎Combine datasets with a composition](https://docs.nominal.io/core/documentation/platform/data/compositions).

## Putting it all together

Assets reach datasets through data scopes, and runs and events mark time ranges on an asset.

```mermaid
---
config:
  layout: elk

---
flowchart TB
    asset["Asset"]
    run["Run"]
    event["Event"]
    scope["Data scope"]
    dataset[("Dataset")]
    asset ---|"many, time-bounded"| run
    asset ---|"many, time-bounded"| event
    asset ---|"many"| scope
    scope ---|"filters one"| dataset
    click asset href "#asset" "Asset"
    click run href "#runs" "Runs"
    click event href "#events" "Events"
    click scope href "#data-scopes-and-ref-names" "Data scopes and ref names"
    click dataset href "#data-model-dataset" "Time-series data"
    classDef linked fill:#dcfce7,stroke:#15803d,color:#1f2937
    classDef notlinked fill:#fee2e2,stroke:#b91c1c,color:#1f2937
    classDef data fill:#e0e7ff,stroke:#4338ca,color:#1f2937
    class asset linked
    class run,event notlinked
    class dataset data
```
