Skip to content

Instantly share code, notes, and snippets.

@andrewjbennett
Created October 6, 2024 05:05
Show Gist options
  • Select an option

  • Save andrewjbennett/1fd5c98640b48d2c1ac022709d0f3fb8 to your computer and use it in GitHub Desktop.

Select an option

Save andrewjbennett/1fd5c98640b48d2c1ac022709d0f3fb8 to your computer and use it in GitHub Desktop.
Convert the accelerometer data from the Polar H10 to the format generated by Somnopose, to import into OSCAR.
#!/usr/bin/python3
#
# Usage:
# ./convert-h10-acc-xyz-to-somnopose.py Polar_H10_9ED9422D_20241005_024048_ACC.txt > output-2024-10-05.csv
#
# OSCAR can import somnopose data, so we convert the Polar H10 data to the format generated by somnopose.
#
# Example in OSCAR (also with data from a Checkme O2 Max): https://i.imgur.com/SDLQJEY.png
from typing import NamedTuple, List
from datetime import datetime
import sys
import math
"""
$ head -5 Polar_H10_9ED9422D_20241005_024048_ACC.txt
Phone timestamp;sensor timestamp [ns];X [mg];Y [mg];Z [mg]
2024-10-05T02:40:51.687;599616285252552704;-757;106;640
2024-10-05T02:40:51.727;599616285292552704;-757;107;639
2024-10-05T02:40:51.767;599616285332552704;-757;107;641
2024-10-05T02:40:51.807;599616285372552704;-757;112;641
"""
class Data(NamedTuple):
phone_timestamp: str
sensor_timestamp_nanos: int
dt: datetime
X: int
Y: int
Z: int
pitch: float
roll: float
def main():
filename = sys.argv[1]
data = load_data(filename)
print_data(data)
def print_data(data):
prev_ts = 0
print("Timestamp,Orientation,Inclination")
for d in data:
ts_secs = int(d.dt.timestamp()) - 978307200 # convert unix epoch time to "iOS time"
if prev_ts == ts_secs:
continue # only output one value per second
prev_ts = ts_secs
print(f"{ts_secs},{d.roll:.2f},{d.pitch:.2f}")
def load_data(filename):
data: List[Data] = []
with open(filename) as fin:
for line in fin:
parts = line.split(";")
if len(parts) != 5:
print(f"line doesn't match expected format! got: {line}, {parts}", file=sys.stderr)
continue
if parts[0][0] != "2":
print(f"skipping non-date line: {parts}", file=sys.stderr)
continue
# Phone timestamp;sensor timestamp [ns];X [mg];Y [mg];Z [mg]
# 2024-10-05T02:40:51.687;599616285252552704;-757;106;640
phone_ts = parts[0].split(".")[0] # 2024-10-05T02:40:51
sensor_ts_nanos = int(parts[1]) # 599616285252552704 (not actually used)
X, Y, Z = int(parts[2]), int(parts[3]), int(parts[4]) # -757;106;640
pitch, roll = calculate(X, Y, Z)
dt = datetime.strptime(phone_ts, "%Y-%m-%dT%H:%M:%S")
d = Data(phone_ts, sensor_ts_nanos, dt, X, Y, Z, pitch, roll)
data.append(d)
return data
def calculate(X, Y, Z):
# from https://stackoverflow.com/a/10320532
pitch = math.atan2(-X, math.sqrt(Y*Y + Z*Z)) * 180/math.pi
roll = math.atan2(Y, Z) * 180 / math.pi
return (pitch, roll)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment