Since the Aidlab SDK 1.0.3, we opened up the possibility to start playing with raw motion data (such as acceleration) from Aidlab Chest Strap. This tutorial will cover all the necessary details to connect, read, and analyze data, ending with creating a basic Sleep Detector.
- Create an empty directory with a
basic-sleep-detector.py
file. - Install the Aidlab Python SDK.
Receiving data
To connect with Aidlab, all you have to do is to invoke the connect
function from the Aidlab
module, and set the receiver's callback:
# basic-sleep-detector.py
import Aidlab
from Aidlab.Signal import Signal
from time import sleep, time
from datetime import datetime
class MainManager(Aidlab.Aidlab):
def __init__(self):
super().__init__()
self.startTimeOfSleepingPosition = 0
self.isInSleepingPosition = False
def did_connect(self, aidlab):
print("Connected to:", aidlab.address)
def did_disconnect(self, aidlab):
print("Disconnected from:", aidlab.address)
def did_receive_quaternion(self, aidlab, timestamp, qw, qx, qy, qz):
self.naiveSleepDetector([qw, qx, qy, qz])
if __name__ == '__main__':
signals = [Signal.orientation]
main_manager = MainManager()
main_manager.connect(signals)
while True:
pass
At this point, you are ready to listen for an upcoming stream of data from the 9-axis Inertial Motion Unit (IMU) sensor, at a 30Hz rate.
Getting the user's vertical orientation
Our sleep detection algorithm will use the user’s position to determine whether they are lying on the bed or not. To do so, we have to estimate their vertical orientation, e.g.: check whether the chest is parallel to the floor or not. Possible vertical orientations are:
Up
- when the user is lying on his backDown
- the user is lying on his belly (or is doing push-ups)Front
- the user is standing, walking, sitting, etc.
First, let's define a function giving us sleep detection based on a naive method which takes the user's vertical position:
def did_receive_quaternion(self, aidlab, timestamp, qw, qx, qy, qz):
self.naiveSleepDetector([qw, qx, qy, qz])
def naiveSleepDetector(self, value):
quaternion = value[0:4]
verticalOrientation = self.determineVerticalOrientation(
quaternion[0], quaternion[1], quaternion[2], quaternion[3])
# Sleep detection heuristic
self.basicSleepDetector(verticalOrientation)
To determine the vertical orientation, we will use the given formula:
Quaternion x UpVector
having the Z
from the normal, we might say:
- if
Z >= 0.5
then the vertical orientation isUp
- if
Z <= -0.5
, then the vertical orientation isDown
- else, the vertical orientation is
Front
Coding such logic:
def determineVerticalOrientation(self, qW, qX, qY, qZ):
normalVec = self.normalVectorToUp(qW, qX, qY, qZ)
if normalVec[2] >= 0.5:
return "OrientationDown"
elif normalVec[2] <= -0.5:
return "OrientationUp"
else:
return "OrientationFront"
The multiplication of quaternion and vector is represented as follows:
V' = Q * V * conjugate(Q)
where the vector V
is being treated as a quaternion with w=0
:
def normalVectorToUp(self, qW, qX, qY, qZ):
quat = self.multQuat(qW, qX, qY, qZ, 0, 0, 0, 1)
quat = self.multQuat(quat[0], quat[1], quat[2], quat[3], qW, -qX, -qY, -qZ)
return [quat[1], quat[2], quat[3]]
def multQuat(self, w, x, y, z, qW, qX, qY, qZ):
newW = w * qW - x * qX - y * qY - z * qZ
newX = w * qX + x * qW + y * qZ - z * qY
newY = w * qY + y * qW + z * qX - x * qZ
newZ = w * qZ + z * qW + x * qY - y * qX
return [newW, newX, newY, newZ]
Basic Sleep Detector
We have the verticalOrientation
, so we could build the Basic Sleep Detector that will be based on the time period when we are in a sleeping position (OrientationDown
or OrientationUp
) for more than 10 minutes. The basic heuristic goes as follows: if a user is in a sleeping position for more than 10 minutes, then he or she is sleeping:
def __init__(self):
super().__init__()
self.startTimeOfSleepingPosition = 0
self.isInSleepingPosition = False
def basicSleepDetector(self, verticalOrientation):
if (verticalOrientation == 'OrientationUp' or verticalOrientation == 'OrientationDown') and self.isInSleepingPosition == False:
self.isInSleepingPosition = True
self.startTimeOfSleepingPosition = time()
elif verticalOrientation == 'OrientationFront' and self.isInSleepingPosition:
self.startTimeOfSleepingPosition = 0
self.isInSleepingPosition = False
# Sleep detection heuristic:
# We are sleeping if we are in sleeping position for longer than 10 minutes
if self.isInSleepingPosition and (time() - self.startTimeOfSleepingPosition > 10 * 60):
print("I am sleeping")
Turn on Aidlab and start the script:
python basic-sleep-detector.py
Of course, the algorithm will be fooled in situations when the user is laying on his side (we could simply overcome this by using the RPY axes instead), but the main purpose for this article is to present the whole process, starting with connecting to Aidlab, through collecting raw data and creating the necessary math behind calculating the vertical orientation, to building the basic sleep detector. We encourage you to experiment by yourself to get the desired result and improvements in the sleep detection method. Using other signals such as heart rate, respiration, or even the slight changes of the skin temperature, will highly improve the quality of your sleep detector.
The full source code is available on our GitHub (see example_basic_sleep_detector.py
file).
Cover image from Vecteezy.