Sleep IMU Example

This example illustrates how to import data from inertial measurement units (IMUs) collected during sleep and compute sleep endpoints.

Note: An inertial measurement unit (IMU) is a sensor that measures a body’s acceleration (using accelerometers) and angular rate (using gyroscopes). In medical and psychological applications IMUs are commonly used for activity monitoring, movement analysis, and many more.

Setup and Helper Functions

[1]:
from pathlib import Path

import pandas as pd
import numpy as np

from fau_colors import cmaps
import biopsykit as bp

import matplotlib.pyplot as plt
import seaborn as sns

%matplotlib inline
%load_ext autoreload
%autoreload 2
[2]:
plt.close("all")

palette = sns.color_palette(cmaps.faculties)
sns.set_theme(context="notebook", style="ticks", font="sans-serif", palette=palette)

plt.rcParams["figure.figsize"] = (8, 4)
plt.rcParams["pdf.fonttype"] = 42
plt.rcParams["mathtext.default"] = "regular"

palette
[2]:
[3]:
def display_dict_structure(dict_to_display):
    _display_dict_recursive(dict_to_display)


def _display_dict_recursive(dict_to_display):
    if isinstance(dict_to_display, dict):
        display(dict_to_display.keys())
        _display_dict_recursive(list(dict_to_display.values())[0])
    else:
        display("Dataframe shape: {}".format(dict_to_display.shape))
        display(dict_to_display.head())

Load Dataset

[4]:
# Example dataset
data, fs = bp.example_data.get_sleep_imu_example()

### Alternatively: Load your own dataset
# data, fs = bp.io.nilspod.load_dataset_nilspod("<path-to-imu-file>") # or any other way to load a file containing IMU data
[5]:
data.head()
[5]:
gyr_x gyr_y gyr_z acc_x acc_y acc_z
time
2019-09-03 01:01:12.001953+02:00 -0.488281 0.305176 0.122070 -7.855664 -5.757627 0.129331
2019-09-03 01:01:12.006836+02:00 -0.610352 0.000000 -0.366211 -7.817344 -5.829478 0.148491
2019-09-03 01:01:12.011718+02:00 -0.610352 -0.061035 0.061035 -7.826924 -5.920488 0.225132
2019-09-03 01:01:12.016601+02:00 -0.915527 0.122070 0.183105 -7.769443 -5.848638 0.177231
2019-09-03 01:01:12.021484+02:00 -0.488281 0.000000 0.366211 -7.721543 -5.858218 0.162861

Plot IMU Data

[6]:
fig, ax = bp.sleep.plotting.sleep_imu_plot(data, downsample_factor=5 * fs)
../../_images/examples__notebooks_Sleep_IMU_Example_11_0.svg

Compute Sleep Endpoints

The Sleep Processing Pipeline (which is performed in sleep_processing_pipeline.predict_pipeline_acceleration() consists of the following steps:

  1. Activity Count Conversion: Convert (3-axis) raw acceleration data into activity counts. Most sleep/wake detection algorithms use activity counts (as typically provided by Actigraphs) as input data.

  2. Wear Detection: Detect wear and non-wear periods. Afterwards, cut data to longest continuous wear block.

  3. Rest Periods: Detect rest periods, i.e., periods with large physical inactivity. The longest continuous rest period (Major Rest Period) is used to determine the Bed Interval, i.e., the period spent in bed.

  4. Sleep/Wake Detection: Apply sleep/wake detection to classify phases of sleep and wake.

  5. Sleep Endpoint Computation: Compute Sleep Endpoints from sleep/wake detection results and bed interval. The following sleep endpoints are supported:

    • date: Date of the sleep recording. Note: By convention, this field will return the previous day if the Bed Interval started after 12 a.m., i.e. the subject went to bed after midnight. By this convention, one always night always spans two days.

    • sleep_onset: Sleep Onset, i.e., time of falling asleep (when first sleep phase started), in absolute time

    • wake_onset: Wake Onset, i.e., time of awakening (last sleep phase ended), in absolute time

    • total_sleep_duration: Total duration spent sleeping, i.e., the duration between Sleep Onset and Wake Onset, in minutes

    • net_sleep_duration: Net duration spent sleeping, in minutes

    • bed_interval_start: Bed Interval Start, i.e., time when subject went to bed, in absolute time

    • bed_interval_end: Bed Interval End, i.e., time when subject left bed, in absolute time

    • sleep_efficiency: Ratio of net_sleep_duration, i.e., the time actually spent sleeping and total_sleep_duration, i.e., the total time between Sleep Onset and Wake Onset, in percent

    • sleep_onset_latency: Sleep Onset Latency, i.e., time in bed needed to fall asleep (difference between Sleep Onset and Bed Interval Start), in minutes

    • getup_latency: Getup Latency, i.e., time in bed after awakening until getting up (difference between Bed Interval End and Wake Onset), in minutes

    • wake_after_sleep_onset: Wake After Sleep Onset (WASO), i.e., total duration awake after falling asleep (after Sleep Onset and before Wake Onset), in minutes

    • sleep_bouts: List with start and end times of sleep bouts

    • wake_bouts: List with start and end times of wake bouts

    • number_wake_bouts: Total number of wake bouts

The results are stored in a dictionary:

[7]:
sleep_results = bp.sleep.sleep_processing_pipeline.predict_pipeline_acceleration(
    data, sampling_rate=fs, epoch_length=60
)
sleep_endpoints = sleep_results["sleep_endpoints"]
[8]:
sleep_endpoints.keys()
[8]:
dict_keys(['date', 'sleep_onset', 'wake_onset', 'total_sleep_duration', 'net_sleep_duration', 'bed_interval_start', 'bed_interval_end', 'sleep_efficiency', 'sleep_onset_latency', 'getup_latency', 'wake_after_sleep_onset', 'sleep_bouts', 'wake_bouts', 'number_wake_bouts'])

Plot IMU Data with Sleep Endpoints

Cut Data to Wear Period

For nicer visualization the IMU data are cut to the longest wear period before plotting:

[9]:
wear_detection = bp.signals.imu.wear_detection.WearDetection(sampling_rate=fs)
data = wear_detection.cut_to_wear_block(data, sleep_results["major_wear_block"])
[10]:
df = bp.sleep.sleep_endpoints.endpoints_as_df(sleep_endpoints)
df
[10]:
sleep_onset wake_onset total_sleep_duration net_sleep_duration bed_interval_start bed_interval_end sleep_efficiency sleep_onset_latency getup_latency wake_after_sleep_onset number_wake_bouts sleep_bouts wake_bouts
date
2019-09-02 00:00:00+02:00 2019-09-03 01:06:12+02:00 2019-09-03 07:08:12+02:00 375 243 2019-09-03 01:01:22.001953024+02:00 2019-09-03 07:17:07.001953024+02:00 64.8 5 9 120 12 [(2019-09-03 01:06:12+02:00, 2019-09-03 01:57:... [(2019-09-03 01:57:12+02:00, 2019-09-03 02:04:...

Note: See Documentation for wear_detection.WearDetection() and sleep_endpoints.endpoints_as_df() for further information of the used functions.

Plot Sleep Data

[11]:
fig, ax = bp.sleep.plotting.sleep_imu_plot(data, sleep_endpoints=sleep_endpoints, downsample_factor=5 * fs)
../../_images/examples__notebooks_Sleep_IMU_Example_24_0.svg

Note: See Documentation for sleep.plotting.sleep_imu_plot() for further information of the used functions.

Export Sleep Endpoints

[12]:
# bp.io.sleep.save_sleep_endpoints("../example_data/sleep_endpoints.csv", df)

Note: See Documentation for save_sleep_endpoints() for further information of the used functions.

[ ]:

Download Notebook
(Right-Click -> Save Link As...)