As you sleep, the motion of the heart beat and resulting surges of blood around the body cause the body and bed to shake. Just a bit, but enough to detect with a MEMs accelerometer like the orientation sensor in your phone as well as in step counting fitness trackers. A good paper on the subject is here: NIH paper
You can use this effect to detect heart rate, respiration rate, heart rate variance (a good measure of stress) as well as sleep/wake times; all while you sleep without needing to wear a device. This is key since to collect sleep data over months/years, it is important that the process be transparent to the user; just tape the sensor to the edge of the mattress and forget about it.
This approach has been studied for 100 years and has been made practical by emergence of cheap, sensitive technologies like MEMs. Joonas Paalasmaa’s (co-founder of Beddit – acquired by Apple) paper on the subject “unobtrusive online monitoring of sleep at home” is here on Pubmed
Heart rate, respiration rate and HRV can all be used to determine sleep stage in the circadian rhythm (wake – REM – light1 – light2 – deep). The ratios of time in these stages is a measure of sleep quality and over the long term trends in these parameters can show signs such as the onset of sickness or the menstrual cycle stage.
The autonomic nervous system is divided into the sympathetic (SNS) and parasympathetic (PNS) systems. SNS is dominant during flight/flight whereas PNS during rest-digest while the body is recovering. In the frequency domain, the ratio between high and low frequency HRV is a good measure of stress/relaxation; we can also use this for sleep stage detection.
I found a Murata MEMs sensor that I interfaced into a Raspberry Pi using a UART-USB converter, wrote some Python drivers which logged the data and dumped it every morning onto Dropbox.
Here’s a typical night. Top graph heart rate (blue) vs HRV (orange). Bottom graph heart rate (blue) versus signal strength (orange).
Sleep cycles are quite visible in the HRV traces. Signal strength correlates highly with movement and shows well getting in to bed, getting up and restless periods during the night. Heart rate varies substantially as you move between the various levels of sleep (REM, level 1-3 etc. You can read more about that here) and is of course highly correlated with respiration rate and HRV.
Reliably detecting sleep stages is difficult. Here is a good IEEE paper on PubMed. I have an ongoing project to accumulate a year of sleep data and see if a simple neural net can be used to classify sleep stages as well as sleep/wake times. A Stanford paper by a former neighbor on that subject here.
Hardware set up
The Murata sensor is the SCA10H which uses the SCA61T inclinometer and a TI MSP430 MCU. This is actually part of the larger SCA11 product that includes WiFi and a WebServer interface etc. However I just wanted too hack the basic sensor board and plumb the data into Raspberry Pi.
The Murata device and binary interface specs are here
The sensor has an internal RTOS that samples at 1Khz. Data is issued over the UART at 1Hz so all the Python script needs to do is set up the UART comms channel, read the data, parse the bit fields into values and dump the file onto DropBox in the morning. Some simple post-processing gets rid of outlier values and cleans up signals a bit.
The pinout of the Murata device is like this (top view looking down onto chip):
Relevant connections to make:
- Pad 51: Tx (to USB UART out of Murata)
- Pad 52: Rx (from USB UART into Murata)
- Pad 18: Vcc. 9v. Careful. The sensor requires 9v, the rest of the system uses 3v3 signaling.
- Pad 19: GND. Many of these around the board. The more grounds connected, the better.
Communication with the module is serial over a UART.
I used a USB to UART converter dongle from Amazon to interface to the Raspberry Pi. Set up was like this:
Once working, I taped the sensor robustly onto my mattress…
My Python on GitHub is here
The serial comms protocol is described here but in summary:
- Header: 0xFE 1 byte
- Length: 1 byte
- Type: 1 byte
- ID: 1 byte
- Payload: multiple bytes according to data
- Checksum: 1 byte
You can send commands to the module. For example, to get the serial number:
[FE, 00, 01, 02, 0C, F1]
- Header: 0xFE
- Length: 0x00
- Type: 0x01
- ID: 0x20C
- Checksum: 0xF1
- Header: 0xFE
- Length: 0x0D
- Type: 0x01
- ID: 0x820C
- Payload: ASCII serial number
A BCG vital sign packet looks like this:
- Header: 0xFE
- Length: 0x28
- Type: 0x00
- ID: 0x00
- Payload: Data in fields as follows
- The data fields (all signed 32bits)
Timestamp: in seconds
- HR: heart rate
- RR: respiration rate
- SV: heart stroke volume
- HRV: heart rate variability
- Signal: signal strength
- Status: module status
- B2B: beat to beat interval mS