Created
October 6, 2024 05:05
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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() |
Author
andrewjbennett
commented
Jan 12, 2026
via email
I used an Android app, I think it was "Polar Sensor Logger"
(com.j_ware.polarsensorlogger). The only problem was that sometimes the
recording would cut out, I think potentially I needed to leave the screen
on, or leave the app in the foreground, maybe? Sorry, it's been a few years
and I can't remember 100%.
…On Sun, 11 Jan 2026 at 14:46, AJolly ***@***.***> wrote:
***@***.**** commented on this gist.
------------------------------
What are you using to record data off the h10 in the first place?
—
Reply to this email directly, view it on GitHub
<https://gist.github.com/andrewjbennett/1fd5c98640b48d2c1ac022709d0f3fb8#gistcomment-5937045>
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAGS7CSOROH7WXQ6PCIQ7PD4GHBRFBFKMF2HI4TJMJ2XIZLTSOBKK5TBNR2WLJJZGE2DSM5ENZQW2ZNIMFRXI33SL5UWJAVFOZQWY5LFUR2HE5LFURXGC3LFXN2GQ4TFMFSF64DBOJ2GSY3JOBQW45C7MFRXI2LWNF2HTAVFOZQWY5LFURTWS43UURXGC3LFVN2GQ4TFMFSF65DZOBS2Y43VMJVGKY3UL52HS4DFVNDWS43UINXW23LFNZ2KM5DPOBUWG44RQKSHI6LQMWSGO2LTOSSXMYLMOVS2SMJTGMYTMMRYGI2KO5DSNFTWOZLSUZRXEZLBORSQ>
.
You are receiving this email because you authored the thread.
Triage notifications on the go with GitHub Mobile for iOS
<https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675>
or Android
<https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub>
.
Got it thanks! Yeah that logger i've found is flaky, ive never gotten it to send data. https://github.com/Boelensman1/PolarRecorder this one works but its a different file format, but im sure i can get it converted.
Thanks!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment