The default data approach: testing individual long-lived units under test#
Use this approach by default if no other seems to fit your use case better.
This approach is for units under test that are high cost and limited in quantity and are operated over a long time across many test campaigns, such as vehicles or engines, where test campaigns mix checks against known criteria with exploratory testing.
Implementing this approach#
Map each physical unit under test to one Nominal asset with one dataset attached, and put all of that unit’s data in that dataset. When a new unit comes online, create an asset and a dataset for it.
As the UUT undergoes tests, all data is streamed or uploaded to the single associated dataset. Conceptually, that looks like:
---
config:
layout: elk
---
flowchart BT
classDef green fill:#dcfce7,stroke:#15803d,color:#1f2937
classDef red fill:#fee2e2,stroke:#b91c1c,color:#1f2937
classDef purple fill:#e0e7ff,stroke:#4338ca,color:#1f2937
asset1["Asset: UUT1"]:::green
dataset1[("Dataset<br>UUT1")]:::purple
dataset1 --> asset1
asset2["Asset: UUT2"]:::green
dataset2[("Dataset<br>UUT2")]:::purple
dataset2 --> asset2
asset3["Asset: UUT3"]:::green
dataset3[("Dataset<br>UUT3")]:::purple
dataset3 --> asset3
click asset1,asset2,asset3 href "../../#asset" "Asset"
click dataset1,dataset2,dataset3 href "../../#time-series-data" "Time-series data"
Each dataset is attached to its asset under a ref name, and the ref name is the same on every unit, such as default.
---
config:
layout: elk
---
flowchart BT
classDef green fill:#dcfce7,stroke:#15803d,color:#1f2937
classDef red fill:#fee2e2,stroke:#b91c1c,color:#1f2937
classDef purple fill:#e0e7ff,stroke:#4338ca,color:#1f2937
asset1["Asset: UUT1"]:::green
dataset1[("Dataset<br>UUT1")]:::purple
dataset1 -->|"ref name=default"| asset1
asset2["Asset: UUT2"]:::green
dataset2[("Dataset<br>UUT2")]:::purple
dataset2 -->|"ref name=default"| asset2
asset3["Asset: UUT3"]:::green
dataset3[("Dataset<br>UUT3")]:::purple
dataset3 -->|"ref name=default"| asset3
click asset1,asset2,asset3 href "../../#asset" "Asset"
click dataset1,dataset2,dataset3 href "../../#time-series-data" "Time-series data"
To set up one unit under test in code and write one point to one channel:
from nominal.core import NominalClient
client = NominalClient.from_profile("default")
# One asset per unit under test, with its own dataset attached under the ref name "default"
asset = client.create_asset("UUT1")
dataset = asset.get_or_create_dataset("default", name="UUT1")
# Write a point to the unit's dataset
with dataset.get_write_stream() as stream:
stream.enqueue("Vsignal", "2026-01-01T12:00:00Z", 5.0)
use nominal::core::{AssetCreate, DatasetCreate};
use nominal::streaming::prelude::*;
use nominal::streaming::stream::NominalDatasetStreamBuilder;
use std::time::UNIX_EPOCH;
let client = nominal::NominalClient::from_profile("default")?;
// One asset per unit under test, with its own dataset attached under the ref name "default"
let asset = client.assets().create(AssetCreate::new("UUT1")).await?;
let dataset = client.catalog().create_dataset(DatasetCreate::new("UUT1")).await?;
client.assets().add_dataset(asset.rid(), "default", dataset.rid()).await?;
// Write a point to the unit's dataset
let token = BearerToken::new(&std::env::var("NOMINAL_TOKEN")?)?;
let stream = NominalDatasetStreamBuilder::new()
.stream_to_core(token, ResourceIdentifier::new(dataset.rid())?, tokio::runtime::Handle::current())
.build();
stream.double_writer(ChannelDescriptor::new("Vsignal")).push(UNIX_EPOCH.elapsed()?, 5.0);
client = nominal.Client.fromProfile();
% One asset per unit under test, with its own dataset attached under the ref name "default"
asset = client.getOrCreateAsset("UUT1");
dataset = asset.getOrCreateDataset("UUT1", "default");
% Write a point to the unit's dataset
stream = dataset.stream();
vsignal = stream.channel("Vsignal");
vsignal.push(datetime("now"), 5.0);
import (
"time"
"github.com/nominal-io/nominal-api-go/api/rids"
assetapi "github.com/nominal-io/nominal-api-go/scout/asset/api"
"github.com/nominal-io/nominal-api-go/scout/assets"
"github.com/nominal-io/nominal-api-go/scout/catalog"
runapi "github.com/nominal-io/nominal-api-go/scout/run/api"
nominal "github.com/nominal-io/nominal-streaming-go"
)
// httpClient is a conjure-go-runtime httpclient.Client for your Nominal REST API URL,
// token is your API key as a bearertoken.Token, and apiKey is the same key as a string
catalogClient := catalog.NewCatalogServiceClient(httpClient)
assetClient := assets.NewAssetServiceClient(httpClient)
// One asset per unit under test, with its own dataset attached under the ref name "default"
dataset, _ := catalogClient.CreateDataset(ctx, token, catalog.CreateDataset{Name: "UUT1"})
assetClient.CreateAsset(ctx, token, assetapi.CreateAssetRequest{
Title: "UUT1",
DataScopes: []assetapi.CreateAssetDataScope{{
DataScopeName: "default",
DataSource: runapi.NewDataSourceFromDataset(rids.DatasetRid(dataset.Rid)),
}},
})
// Write a point to the unit's dataset
streamClient, _ := nominal.NewClient(apiKey)
stream, _, _ := streamClient.NewDatasetStream(ctx, dataset.Rid.String())
stream.FloatStream("Vsignal").Enqueue(time.Now().UnixNano(), 5.0)
stream.Close()
Add a run for each test performed on the unit. With one run per test, you build a workbook once and view any test’s results in it by pointing the workbook at that test’s run.
---
config:
layout: elk
---
flowchart BT
classDef green fill:#dcfce7,stroke:#15803d,color:#1f2937
classDef red fill:#fee2e2,stroke:#b91c1c,color:#1f2937
classDef purple fill:#e0e7ff,stroke:#4338ca,color:#1f2937
classDef blue fill:#e0f2fe,stroke:#0369a1,color:#1f2937
%% basic asset
asset1["Asset: UUT1"]:::green
dataset1[("Dataset<br>UUT1")]:::purple
dataset1 -->|"ref name=default"| asset1
run1["Run: Test A"]:::red
asset1 --> run1
run2["Run: Test B"]:::red
asset1 --> run2
workbook1["Workbook for<br>Test Results<br><br>Points at one run at a time"]:::blue
run1 -.->|"pointing at A"| workbook1
run2 -.->|"pointing at B"| workbook1
click asset1 href "../../#asset" "Asset"
click dataset1 href "../../#time-series-data" "Time-series data"
click run1,run2 href "../../#runs" "Runs"
click workbook1 href "../../../workbooks/" "Workbooks"
Or, configure a workbook to compare runs, which compares results across many tests.
---
config:
layout: elk
---
flowchart BT
classDef green fill:#dcfce7,stroke:#15803d,color:#1f2937
classDef red fill:#fee2e2,stroke:#b91c1c,color:#1f2937
classDef purple fill:#e0e7ff,stroke:#4338ca,color:#1f2937
classDef blue fill:#e0f2fe,stroke:#0369a1,color:#1f2937
%% basic asset
asset1["Asset: UUT1"]:::green
dataset1[("Dataset<br>UUT1")]:::purple
dataset1 -->|"ref name=default"| asset1
run1["Run: Test A"]:::red
asset1 --> run1
run2["Run: Test B"]:::red
asset1 --> run2
workbook2["Workbook for<br>Test Comparison<br><br>Points at many runs"]:::blue
run1 --> workbook2
run2 --> workbook2
click asset1 href "../../#asset" "Asset"
click dataset1 href "../../#time-series-data" "Time-series data"
click run1,run2 href "../../#runs" "Runs"
click workbook2 href "../../../workbooks/" "Workbooks"
Because the ref name is always the same across units, workbooks can also compare test results across runs from different assets.
---
config:
layout: elk
---
flowchart BT
classDef green fill:#dcfce7,stroke:#15803d,color:#1f2937
classDef red fill:#fee2e2,stroke:#b91c1c,color:#1f2937
classDef purple fill:#e0e7ff,stroke:#4338ca,color:#1f2937
classDef blue fill:#e0f2fe,stroke:#0369a1,color:#1f2937
classDef hidden fill:none,stroke:none
%% basic assets
asset1["Asset: UUT1"]:::green
dataset1[("Dataset<br>UUT1")]:::purple
dataset1 -->|"ref name=default"| asset1
asset2["Asset: UUT2"]:::green
dataset2[("Dataset<br>UUT2")]:::purple
dataset2 -->|"ref name=default"| asset2
run1["Run: Test A<br>On UUT1"]:::red
asset1 --> run1
run2["Run: Test A<br>On UUT2"]:::red
asset2 --> run2
workbook1["Workbook for<br>Test Comparison<br><br>Looks for `default`.(channel)<br>under each asset"]:::blue
run1 --> workbook1
run2 --> workbook1
click asset1,asset2,asset3 href "../../#asset" "Asset"
click dataset1,dataset2,dataset3 href "../../#time-series-data" "Time-series data"
click run1,run2,run3 href "../../#runs" "Runs"
click workbook1,workbook2 href "../../../workbooks/" "Workbooks"
Extensions#
Multiple sources for different data channels#
Use this extension if you have data from multiple logging systems and want to keep each system’s data in its own dataset, for example to apply different data classifications or retention rules. Reach for it only when there is a concrete need like these.
To implement this extension, create one dataset per source and attach each to the asset under its own ref name, using the same ref names on every asset. For example, a test might have data logged by the tester, data from the UUT itself, and data from an environmental monitoring system. Ref names such as tester, uut, and env tell those sources apart on every unit.
---
config:
layout: elk
---
flowchart BT
classDef green fill:#dcfce7,stroke:#15803d,color:#1f2937
classDef red fill:#fee2e2,stroke:#b91c1c,color:#1f2937
classDef purple fill:#e0e7ff,stroke:#4338ca,color:#1f2937
asset1["Asset: UUT1"]:::green
dataset1[("Dataset<br>UUT")]:::purple
dataset2[("Dataset<br>Tester")]:::purple
dataset3[("Dataset<br>Environmental")]:::purple
dataset1 -->|"ref name=uut"| asset1
dataset2 -->|"ref name=tester"| asset1
dataset3 -->|"ref name=env"| asset1
click asset1,asset2,asset3 href "../../#asset" "Asset"
click dataset1,dataset2,dataset3 href "../../#time-series-data" "Time-series data"
The drawback of this extension is the added complexity for your team. Workbooks still reach every dataset on the asset, each through its own ref name.
Combining with the tagged approach#
Use this extension when a source shared by many units, such as a ground station, records data during their tests and tags it with the unit under test, instead of writing to each unit’s dataset. Each unit’s asset links the shared dataset under its own ref name, filtered to that unit’s tag. See Combining the default and tagged approaches.
Multiple measurements for the same signals#
Use this extension if you have existing files from multiple logging systems for the same asset and the multiple logging systems use identical channel names.
For example, a tester commands a voltage, Vsignal, and the unit under test measures that same voltage. If both log it as Vsignal, the asset has two channels with the same name. When you control the channel names, prefix or suffix them instead, such as Tester.Vsignal and UUT.Vsignal.
When the files already exist and renaming their channels isn’t reliable, upload each logging system’s files to its own dataset and attach each dataset under a distinct ref name.
---
config:
layout: elk
---
flowchart BT
classDef green fill:#dcfce7,stroke:#15803d,color:#1f2937
classDef red fill:#fee2e2,stroke:#b91c1c,color:#1f2937
classDef purple fill:#e0e7ff,stroke:#4338ca,color:#1f2937
asset1["Asset: UUT1"]:::green
dataset1[("Dataset<br>UUT<br><br>Channels: Vsignal,<br>...")]:::purple
dataset2[("Dataset<br>Tester<br><br>Channels: Vsignal,<br>...")]:::purple
dataset1 -->|"ref name=uut"| asset1
dataset2 -->|"ref name=tester"| asset1
click asset1,asset2,asset3 href "../../#asset" "Asset"
click dataset1,dataset2,dataset3 href "../../#time-series-data" "Time-series data"
A workbook then tells the two channels apart by ref name, as uut.Vsignal and tester.Vsignal.
The drawback of this extension is the added complexity of having many data sources.
Production tester monitoring#
Monitoring a production tester over time is also possible with this approach. Compare it with production tester monitoring in the tagged approach. If the tester is the asset you care about most, use the tagged approach. If the unit under test matters most, use this extension.
To implement this extension, users must create a tester asset and connect all of their datasets to that asset. The exception would be data generated onboard the unit under test.
For example, in a hardware-in-the-loop (HiL) scenario, you may have an HiL tester which provides stimulus and an onboard computer which provides internal analytics. If those are routed to different datasets, as described in the other extensions, you need not attach the data from the onboard computer to your tester asset.
---
config:
layout: elk
---
flowchart BT
classDef green fill:#dcfce7,stroke:#15803d,color:#1f2937
classDef red fill:#fee2e2,stroke:#b91c1c,color:#1f2937
classDef purple fill:#e0e7ff,stroke:#4338ca,color:#1f2937
classDef blue fill:#e0f2fe,stroke:#0369a1,color:#1f2937
classDef darkred fill:#fecaca,stroke:#b91c1c,color:#1f2937
classDef darkgreen fill:#bbf7d0,stroke:#15803d,color:#1f2937
asset1["Asset: UUT1"]:::green
dataset1[("Dataset<br>UUT1")]:::purple
dataset1 -->|"ref name=default"| asset1
asset3["Asset: Tester"]:::darkgreen
dataset2 -->|"ref name=UUT2"| asset3
dataset1 -->|"ref name=UUT1"| asset3
asset2["Asset: UUT2"]:::green
dataset2[("Dataset<br>UUT2")]:::purple
dataset2 -->|"ref name=default"| asset2
click asset1,asset2,asset3 href "../../#asset" "Asset"
click dataset1,dataset2,dataset3 href "../../#time-series-data" "Time-series data"
The drawback of this extension is that every unit’s dataset must be attached to the tester asset under its own ref name, because the units’ channel names match. The diagram above uses each unit’s name, such as UUT1, as that ref name.