Engage Human Biometrics - rallytac/pub GitHub Wiki
Biometric Representation
Engage represents human biometric data as JSON objects where the JSON object is expressed as a data series consisting of a time at which the reading/value was taken, and the value itself.
Data Series
Before we get into the guts of the biometric data itself, we first need to discuss how a data series works, is represented in JSON, and how it is conveyed over the network. We'll do this by referring to sample data which, for purposes of this discussion, we'll view as heart rates (this is after all a briefing on biometrics).
Consider a data series of 5 heart rate values (heart rate has a numeric type of 1). The first value occurs at the beginning moment of the series at an offset of 0 and has a value of 37. The second occurs 3 seconds later with a value of 38. The third after anoter 1 second with a value of 42, and the final item 7 seconds later with a value of 36.
The JSON representation of this series is therefore (with the "t" field denoting type and "s" field denoting series):
{
"t":1,
"s":[0,37,3,38,1,42,7,36]
}
As there is no timestamp, the starting timestamp is taken to be when the data was received.
This is the most basic representation of a time-offset data series. But it gets a lot more sophisticated as we move on.
Timestamp
For the transmitting entity to indicate when the data series started, the timestamp field "ts" needs to be included; representing the number of seconds elapsed since January 1, 1970 - i.e. based on traditional Unix time.
The JSON representation of this series is as follows:
{
"t":1,
"ts":65889070,
"s":[0,37,3,38,1,42,7,36]
}
This data series represented in tabular form with absolute timestamps would look as follows:
Timestamp (Seconds) | Value | Detail |
---|---|---|
65889070 | 37 | 0 increment from ts |
65889073 | 38 | 3 seconds later |
65889074 | 42 | 1 second later |
65889081 | 36 | 7 seconds later |
There are a number of important items to note:
- The number of elements in the data series are (and must be) a multiple of 2 - i.e. a time offset from the timestamp start for the first element and from the previous element for subsequent items and, which each time offset, the value corresponding to that moment in time.
- The object will need to eventually be transferred across a network and must therefore fit inside a UDP MTU. As a result, elements must occupy as little space as possible. For this purpose, the timestamp is 32-bits (unsigned), while all other values may only be 8 bits in size - i.e. 1 byte with values between 0 and 255.
Timestamp Increments
So far, it's been assumed that our time offsets are in seconds - and that is the default. But what if we wanted the increment to be something other than seconds? For this purpose, the object allows for the "it" field - representing increment type. This field represents milliseconds, seconds, minutes, hours, and days. For example:
{
"t":1,
"ts":65889070,
"it":2,
"s":[0,37,3,38,1,42,7,36]
}
Here, the increment type is "2" - denoting a type of minutes. Therefore, our data series, instead of representing values obtained at second intervals, now indicates that the data was obtained at intervals of minutes at a time. Updating our table from above with this new increment type, results in the following:
Timestamp (Seconds) | Value | Detail |
---|---|---|
65889070 | 37 | 0 increment from ts |
65889250 | 38 | 3 minutes later |
65889310 | 42 | 1 minute later |
65889730 | 36 | 7 minutes later |
The valid timestamp increment type values are:
Value | Type | Comments |
---|---|---|
0 | Seconds | This is the default |
1 | Milliseconds | |
2 | Minutes | |
3 | Hours | |
4 | Days |
It's important to bear in mind what was stated above - that time offset values can only occupy 1 byte; and therefore have valid values from 0-255. Therefore, using just the it field alone, results in maximum time offset values of 255. If your time offsets for a particular data series exceed the maximum for a particular increment type, you need to move to the next-higher increment type ... or use the increment multiplier discussed below.
Increment Multiplier
The increment multiplier ("im") is an additional field that allows you apply a multiplier of 1-255 for time offset increments. For example: let's assume that our data is being gathered at 20-millisecond intervals. We could certainly represent the data as [0,37,60,38,20,42,140,36] where the time offset "3" becomes "60", "1" becomes "20", and "7" becomes "140". Alternatively, we can keep the original data of "[0,37,3,38,1,42,7,36]" and apply a multiplier of 20 as follows:
{
"t":1,
"ts":65889070,
"it":1,
"im":20,
"s":[0,37,3,38,1,42,7,36]
}
A more interesting example might be to have represent the time offsets as incrementing in weeks. Do so by specifying a increment type of 4 (for days) and an increment multiplier of 7. For example:
{
"t":1,
"ts":65889070,
"it":4,
"im":7,
"s":[0,37,3,38,1,42,7,36]
}
Now, our data series represents that data was gathered at intervals of 0 (to start), 3 weeks later, 1 week after that, and another 7 weeks following that value.
Note that the default increment multiplier is 1 - e.g. 1 millisecond, 1 second, 1 hour, 1 day, and so on.
Using the Data Series
With the above in mind, let's go ahead and see how JSON that describes a portion of a user's biometric data.
We will convey the heart rate, and we'll say we have 5 measurements (62,62,64,63) starting at 65889070, and each one second apart. Our representation would be as follows:
{
"t":1,
"t":65889070,
"s":[0,62,1,62,1,64,1,63]
}
Or, more compacted onto one line:
{"t":1, "ts":65889070, "s":[0,62,1,62,1,64,1,63]}
Expanded into a table, this data would look as follows:
Timestamp (Seconds) | Value |
---|---|
65889070 | 62 |
65889071 | 62 |
65889072 | 64 |
65889073 | 63 |
We can, of course, apply increment types and multipliers to this data but let's not confuse things right now.
Types of Human Biometrics
Engage provides the following biometrics:
Type | Value | Range | JSON Object Name | Detail |
---|---|---|---|---|
Heart Rate | 1 | 0-255 | heartRate | Beats per minute |
Skin Temperature | 2 | 0-255 | skinTemp | Celcius |
Core Temperature | 3 | 0-255 | coreTemp | Celcius |
Hydration Percentage | 4 | 0-100 | hydration | Percentage |
Blood Oxygenation Percentage | 5 | 0-100 | bloodOxygenation | Percentage |
Fatigue Level | 6 | 0-10 | fatigueLevel | 0 = low fatigue, 10 = maximum fatigue |
Task Effectiveness Level | 7 | 0-10 | taskEffectiveness | 0 = minimal effectiveness, 10 = maximum effectiveness |
These can be combined into more complex arrays of objects. For example:
[
{"t":1,"ts":1234567,"s":[0,62,1,63,1,64,1,67]},
{"t":2,"ts":1234567,"s":[0,37,1,36,1,37,1,39]},
{"t":3,"ts":1234567,"s":[0,34,1,34,1,34,1,34]},
{"t":4,"ts":1234567,"s":[0,82,1,82,1,82,1,81]},
{"t":5,"ts":1234567,"s":[0,97,1,98,1,96,1,96]},
{"t":6,"ts":1234567,"s":[0,1,1,2,1,1,1,3]},
{"t":7,"ts":1234567,"s":[0,9,1,9,1,8,1,9]}
]
[
{"t":1,"ts":1234567,"s":[0,62,1,63,1,64,1,67]},
{"t":7,"ts":1234567,"s":[0,9,1,9,1,8,1,9]}
]
[
{"t":1,"ts":1234567,"s":[0,62,1,63,1,64,1,67]},
{"t":1,"ts":2218766,"s":[0,71,1,71,1,78,1,92,1,93,1,93,1,88]},
]