Getting Started
Consume DSP-derived feature series from the AnyBio API.
This guide walks through the practical case: a stream is flowing, the DSP layer is running, and your application wants the heart rate, HRV, or other derived features that come out of it.
If you haven't yet captured a stream, start with the BioSDK quickstart. DSP runs automatically against any incoming waveform stream; you don't need to enable it.
Querying a feature series
Every signal stream that produces derived features exposes them through a single endpoint:
GET /api/v1/streams/{streamId}/featuresimport { fetchStreamFeatures } from "@anybio/sdk";
const features = await fetchStreamFeatures(streamId);
const hr = features.find((f) => f.name === "hr_ecg");
if (hr) {
console.log(`${hr.values.length} HR samples at ${hr.cadence_hz} Hz`);
console.log(`Latest: ${hr.values[hr.values.length - 1]} bpm`);
}Each feature series carries five fields:
type FeatureSeries = {
name: string; // "hr_ecg", "hrv_rmssd", "prv_sdnn_5min", ...
ts_ns: number[]; // nanosecond timestamps, one per value
values: number[]; // feature values
cadence_hz: number; // output sample rate
qmask: number[]; // quality mask, one per value (0=good, 1=suspect, 2=bad)
};The timestamps are nanosecond-precision and aligned with the source stream's clock, so feature series can be plotted alongside the raw waveform without resampling.
What features come from what biosignal
Map a biosignal abbreviation to its feature outputs:
| If your stream contains... | You get these features |
|---|---|
| ECG | hr_ecg, hrv_rmssd, hrv_sdnn_5min |
| PPG | hr_ppg, prv_rmssd, prv_sdnn_5min |
| EDA, TEMP, HR (device-reported), other discrete signals | Direct observations - see Biosignals: Lookup |
Discrete signals (anything emitted by the device at 1 Hz or slower) skip DSP and become observations directly.
Reading the quality mask
Every feature value has a qmask byte:
| Value | Meaning |
|---|---|
0 | Good. Use the value. |
1 | Suspect. The underlying window had partial signal quality issues. Use with caution; consider downweighting. |
2 | Bad. The window contained data the platform flagged as unreliable (motion artifact, dropped samples, lead-off). Skip in aggregations. |
A simple consumer pattern:
const cleanValues = hr.values.filter((_, i) => hr.qmask[i] === 0);
const meanHR = cleanValues.reduce((a, b) => a + b, 0) / cleanValues.length;Live vs. historical
The same /streams/{streamId}/features endpoint works for both live and completed streams. For live streams, poll periodically or subscribe to updates via WebSocket. For completed streams, the full feature series is available as soon as the stream closes.
For raw waveform data in real time, subscribe to the WebSocket feed - see BioSDK streaming.
Provenance
Every feature value is tagged with the algorithm that produced it. When the same feature is later persisted as an observation, the method_code field records this:
{
"biosignal_id": 1,
"value": 72,
"method_code": "algorithm:ecg_v1"
}The version suffix advances when an algorithm is updated. Historical values keep their original method_code so reanalysis is reproducible.