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 |
Compute Sleep Endpoints¶
The Sleep Processing Pipeline (which is performed in sleep_processing_pipeline.predict_pipeline_acceleration() consists of the following steps:
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.
Wear Detection: Detect wear and non-wear periods. Afterwards, cut data to longest continuous wear block.
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.
Sleep/Wake Detection: Apply sleep/wake detection to classify phases of sleep and wake.
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 timewake_onset
: Wake Onset, i.e., time of awakening (last sleep phase ended), in absolute timetotal_sleep_duration
: Total duration spent sleeping, i.e., the duration between Sleep Onset and Wake Onset, in minutesnet_sleep_duration
: Net duration spent sleeping, in minutesbed_interval_start
: Bed Interval Start, i.e., time when subject went to bed, in absolute timebed_interval_end
: Bed Interval End, i.e., time when subject left bed, in absolute timesleep_efficiency
: Ratio ofnet_sleep_duration
, i.e., the time actually spent sleeping andtotal_sleep_duration
, i.e., the total time between Sleep Onset and Wake Onset, in percentsleep_onset_latency
: Sleep Onset Latency, i.e., time in bed needed to fall asleep (difference between Sleep Onset and Bed Interval Start), in minutesgetup_latency
: Getup Latency, i.e., time in bed after awakening until getting up (difference between Bed Interval End and Wake Onset), in minuteswake_after_sleep_onset
: Wake After Sleep Onset (WASO), i.e., total duration awake after falling asleep (after Sleep Onset and before Wake Onset), in minutessleep_bouts
: List with start and end times of sleep boutswake_bouts
: List with start and end times of wake boutsnumber_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)
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.
[ ]: