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]},
   ]