Skip to main content

Data output

The data schema can be obtained with the sifibridge schema subcommand.

Data packet format

SiFi Bridge outputs sensor data as JSON packets (use -p flag for pretty-printed output). Each packet follows a standard structure defined by the DataPacket schema.

DataPacket structure

Each packet contains data from a single sensor at most.

Each data channel has the same number of samples, and the timestamps always has the same number of values too. Data values and timestamps are matched 1-to-1: (timestamps[0], data['ecg'][0]) form a pair.

{
"device": "BioPoint",
"id": "BP_7A1F",
"name": "my_bp",
"mac": "C2:EC:EF:30:0D:10",
"packet_type": "ecg",
"status": "ok",
"received_at": 1782573963.169,
"timestamps": [
17.826,
17.828,
17.83,
],
"data": {
"ecg": [
null,
0.0,
4.378609035326087e-7,
]
},
"sample_rate": 500.28058548806575,
"samples_lost": 1,
"download_progress": 90
}

Field descriptions

FieldTypeRequiredDescription
devicestringYesDevice type, i.e. BioPoint or SiFiBand
idstringYesDevice unique identifier
namestringYesDevice name
macstringYesDevice MAC address
packet_typestringYesSee Packet types
statusstringYesSee Packet Status
received_atdoubleYesPacket time of arrival (seconds since Unix epoch)
dataHashMap[string, list[float]] | nullNoSee Data channels
timestampslist[float] | nullNoData timestamps (seconds since the start of the acquisition)
sample_ratedouble | nullNoSampling rate (Hz). See Sampling rate
samples_lostuint | nullNoSee Lost samples
download_progressuint8 | nullNoMemory download progress (percent)

Packet types

The packet_type field indicates what kind of data is in the packet:

TypeDescriptionData channels
ecgElectrocardiographyecg
emgElectromyographyemg
edaElectrodermal Activityeda
imuInertial Measurement Unitax, ay, az, qw, qx, qy, qz
ppgPhotoplethysmographyir, r, g, b
emg_armbandEMG Armband (8 channels)emg0-emg7
temperatureTemperature sensortemperature
statusDevice status updatebattery_%
start_timeAcquisition start timeyear, month, day, hour, minute, second
memoryMemory event-

Packet Status

The status field indicates the state of the packet:

StatusDescription
okData received successfully
recordingDevice is recording to memory
memory_download_completedMemory download finished
memory_erasedDevice memory was erased
invalid_datetimeInvalid timestamp
invalidInvalid/corrupted packet

Channel names

Available channel names that can appear in the data object:

Biosignal channels

  • ecg - Electrocardiography (volts)
  • emg (BioPoint) / emg0-emg7 (SiFiBand) - Electromyography (volts)
  • eda - Electrodermal activity (siemens)
  • temperature - Skin temperature (°C)

IMU channels

  • ax, ay, az - Accelerometer (m/s²)
  • qw, qx, qy, qz - Normalized quaternions

PPG channels

PPG does not have a standardized unit since it mesures the intensity of the light reflected in the skin. Typical values are in the ~1000-10000 absolute units (AU) range.

  • ir - Infrared LED
  • r - Red LED
  • g - Green LED
  • b - Blue LED

Status channels

  • temperature - Temperature (°C). Redundant with dedicated temperature packets.
  • battery_% - Battery level (percentage)

Device types

The device field can be:

  • BioPoint - BioPoint device
  • SiFiBand - SiFiBand device
  • Invalid - Unknown/invalid device

Sampling rate

The sample_rate field reports the effective sampling rate in Hz of the sensor as measured by SiFi Bridge. SiFi Bridge continually measures this value as each packet is received. Normally, it converges toward and perhaps slightly oscillates around the configured rate due to the jitter in Bluetooth communications.

It is null for packet types that do not carry periodically sampled data, such as status, start_time, and memory. It is also null during a memory download, since packets are streamed as fast as possible, making the measured sampling rate meaningless.

Lost samples

The samples_lost field reports how many samples were lost since the last packet. This can happen if the BLE link is unstable, causing the effective bandwidth of the BLE link to be lower than what the device requires to deliver all data in real-time.

To preserve the 1-to-1 alignment between timestamps and data values, each lost sample is kept as a null entry in the affected data channel(s), with its corresponding timestamp still present. In the DataPacket example above, samples_lost is 1 and the first ecg value is null. Its associated timestamp is 17.826 s.

If the key is missing, it means no samples were lost.

Downloading memory with lost samples

Lost samples only affect streamed data. The on-device data is not lost!

For instance, if an acquisition is started with memory mode of both, and some samples are lost, you can still obtain the real data by downloading the data from the device's onboard memory afterward.


Example packets

ECG packet

{
"device": "SiFiBand",
"id": "SB_EFFD",
"name": "my_sb",
"mac": "CD:92:AD:DA:B7:71",
"packet_type": "ecg",
"status": "ok",
"received_at": 1782598065.104,
"sample_rate": 996.8285003209548,
"timestamps": [
8.184
],
"data": {
"ecg": [
0.0
]
}
}

EMG packet

This only applies to BioPoint.

{
"device": "BioPoint",
"id": "BP_7A1F",
"name": "my_bp",
"mac": "C2:EC:EF:30:0D:10",
"packet_type": "emg",
"status": "ok",
"received_at": 1783259483.825,
"sample_rate": 1998.5506970149786,
"timestamps": [
3.448,
3.499
],
"data": {
"emg": [
-0.000020798392917798913,
-0.000021455184273097826
]
}
}

8-channel EMG packet

This only applies to SiFiBand.

{
"device": "SiFiBand",
"id": "SB_EFFD",
"name": "my_sb",
"mac": "CD:92:AD:DA:B7:71",
"packet_type": "emg_armband",
"status": "ok",
"received_at": 1783476224.947,
"sample_rate": 1597.1503517986785,
"timestamps": [
1.541875,
],
"data": {
"emg0": [
6.56791355298913e-7,
],
"emg1": [
2.1893045176630434e-7,
],
"emg2": [
-8.757218070652174e-7,
],
"emg3": [
-4.378609035326087e-6,
],
"emg4": [
2.1893045176630434e-7,
],
"emg5": [
5.254330842391304e-6,
],
"emg6": [
1.970374065896739e-6,
],
"emg7": [
1.0946522588315218e-6,
]
}
}

EDA packet

{
"device": "BioPoint",
"id": "BP_7A1F",
"name": "my_bp",
"mac": "C2:EC:EF:30:0D:10",
"packet_type": "eda",
"status": "ok",
"received_at": 1730370226.150,
"timestamps": [1730370225.123, 1730370225.163, 1730370225.203],
"data": {
"eda": [1.6323e-6, 1.64873e-6 , 1.72176e-6]
},
"sample_rate": 50.0
}

IMU packet

{
"device": "SiFiBand",
"id": "SB_EFFD",
"name": "my_sb",
"mac": "CD:92:AD:DA:B7:71",
"packet_type": "imu",
"status": "ok",
"received_at": 1782598065.101,
"sample_rate": 198.82754760640623,
"timestamps": [
8.15,
8.16
],
"data": {
"ax": [
9.889045000076294,
9.698618143200875
],
"ay": [
-0.09820778757333756,
-0.13653277784585954
],
"az": [
-0.17845073595643043,
-0.14012574568390848
],
"qw": [
0.6869235096042648,
0.6868557952294714
],
"qx": [
0.03461920498869666,
0.034735847377314714
],
"qy": [
-0.7243495047894222,
-0.7243973636306342
],
"qz": [
0.047491025575671385,
0.0476549790856847
]
}
}

PPG packet

{
"device": "BioPoint",
"id": "BP_7A1F",
"name": "my_bp",
"mac": "C2:EC:EF:30:0D:10",
"packet_type": "ppg",
"status": "ok",
"received_at": 1730370225.150,
"timestamps": [1730370225.123, 1730370225.133, 1730370225.143],
"data": {
"ir": [2738.0, 2753.0, 2765.0],
"r": [3141.0, 3154.0, 3168.0],
"g": [3465.0, 3474.0, 3482.0],
"b": [2890.0, 2903.0, 2915.0]
},
"sample_rate": 100.0
}

Status packet

{
"device": "BioPoint",
"id": "BP_7A1F",
"name": "my_bp",
"mac": "C2:EC:EF:30:0D:10",
"packet_type": "status",
"status": "ok",
"received_at": 1782574161.811,
"timestamps": [
1782574161.811
],
"data": {
"temperature": [
27.607770919799805
],
"battery_%": [
92.0
],
"memory_used_kbytes": [
370808.490234375
]
}
}

Processing Data Packets

For Python, we recommend using sifi-bridge-py.