Krok po kroku wykorzystujemy dane z Aidlaba, aby rozpoznać, kiedy użytkownik leży wystarczająco długo, aby uznać to za sen.
Od wersji Aidlab SDK 1.0.3 możesz korzystać z surowych danych ruchowych, takich jak przyspieszenie, pochodzących z pasa piersiowego Aidlab. W tym poradniku przejdziemy przez wszystkie kroki: nawiązanie połączenia, odczyt i analizę danych oraz stworzenie prostego detektora snu.
- Utwórz pusty katalog, a w nim plik
basic-sleep-detector.py. - Zainstaluj Aidlab Python SDK.
Odbieranie danych
Aby połączyć się z Aidlabem, wyszukaj urządzenia w pobliżu za pomocą AidlabManager, nawiąż połączenie z delegatem DeviceDelegate, a po jego ustanowieniu rozpocznij zbieranie danych o orientacji:
import asyncio
from time import time
from aidlab import AidlabManager, DataType, DeviceDelegate, DisconnectReason
class MainManager(DeviceDelegate):
def __init__(self):
self.startTimeOfSleepingPosition = 0
self.isInSleepingPosition = False
async def run(self):
devices = await AidlabManager().scan()
if len(devices) > 0:
print("Connecting to:", devices[0].address)
await devices[0].connect(self)
while True:
await asyncio.sleep(1)
def did_connect(self, device):
print("Connected to:", device.address)
asyncio.create_task(device.collect([DataType.ORIENTATION], []))
def did_disconnect(self, device, reason: DisconnectReason):
print("Disconnected from:", device.address, reason)
def did_receive_quaternion(self, device, timestamp, qw, qx, qy, qz):
self.naiveSleepDetector([qw, qx, qy, qz])
if __name__ == '__main__':
asyncio.run(MainManager().run())
Możesz teraz odbierać strumień danych z dziewięcioosiowego czujnika inercyjnego (IMU) z częstotliwością 30 Hz.
Określanie ułożenia ciała względem pionu
Nasz algorytm wykrywania snu będzie na podstawie pozycji użytkownika określał, czy leży on w łóżku. Musimy więc ustalić ułożenie jego ciała względem pionu, na przykład sprawdzić, czy klatka piersiowa jest równoległa do podłogi. Rozróżnimy trzy pozycje:
Up— użytkownik leży na plecach,Down— użytkownik leży na brzuchu lub robi pompki,Front— użytkownik stoi, chodzi, siedzi itp.
Najpierw zdefiniujmy funkcję, która wykorzysta ułożenie ciała do wykrywania snu prostą metodą:
def did_receive_quaternion(self, device, 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)
Do określenia ułożenia ciała wykorzystamy następującą operację:
Quaternion x UpVector
Znając składową Z wektora normalnego, możemy przyjąć:
- jeśli
Z >= 0.5, pozycja toUp, - jeśli
Z <= -0.5, pozycja toDown, - w pozostałych przypadkach pozycja to
Front.
Zapiszmy tę logikę w kodzie:
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"
Obrót wektora za pomocą kwaternionu zapisujemy następująco:
V' = Q * V * conjugate(Q)
Wektor V traktujemy tu jako kwaternion, w którym 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]
Prosty detektor snu
Mamy już verticalOrientation, możemy więc zbudować prosty detektor snu. Będzie on sprawdzał, jak długo użytkownik pozostaje w pozycji leżącej (OrientationDown lub OrientationUp). Przyjmujemy prostą heurystykę: jeśli trwa to dłużej niż 10 minut, algorytm uznaje, że użytkownik śpi:
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")
Włącz Aidlaba i uruchom skrypt:
python basic-sleep-detector.py
Algorytm nie zadziała poprawnie, gdy użytkownik leży na boku. Można to rozwiązać, korzystając z kątów RPY (roll, pitch, yaw). Celem tego artykułu jest jednak pokazanie całego procesu: od połączenia z Aidlabem, przez zbieranie surowych danych i obliczanie ułożenia ciała, aż po stworzenie prostego detektora snu. Zachęcamy do własnych eksperymentów i udoskonalania tej metody. Wykorzystanie dodatkowych sygnałów, takich jak tętno, oddech czy nawet niewielkie zmiany temperatury skóry, może znacznie poprawić jakość wykrywania snu.
Ilustracja tytułowa: Vecteezy.







