Skip to content

Commit 5cefc26

Browse files
Moved Python code.
0 parents  commit 5cefc26

18 files changed

+1449
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
__pycache__
2+
_local

.vscode/settings.json

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
{
2+
"cSpell.words": [
3+
"AAAGGGLLLLLLLLLL",
4+
"Acti",
5+
"Activ",
6+
"Arvidsson",
7+
"Borazio",
8+
"Brønd",
9+
"DWORD",
10+
"Dowd",
11+
"ENMO",
12+
"Esliger",
13+
"Eston",
14+
"GENEA",
15+
"Hees",
16+
"Kearney",
17+
"Kozarski",
18+
"Kyung",
19+
"Kücükyildiz",
20+
"Laerhoven",
21+
"MMDDDD",
22+
"PAEE",
23+
"Rennie",
24+
"Renstr",
25+
"Renström",
26+
"Schaefer",
27+
"Scholl",
28+
"Verisense",
29+
"YYYYYYMM",
30+
"astype",
31+
"csvm",
32+
"cwtv",
33+
"dtype",
34+
"eezzzzzz",
35+
"hhhhmmmm",
36+
"iloc",
37+
"isdigit",
38+
"kyildiz",
39+
"ldjson",
40+
"loadtxt",
41+
"mmssssss",
42+
"nditer",
43+
"numpy",
44+
"omconvert",
45+
"resampling",
46+
"struct",
47+
"tscsv",
48+
"yyyyyyxx",
49+
"zzzzyyyy"
50+
]
51+
}

LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Copyright (c) 2009-2021, Newcastle University, UK.
2+
All rights reserved.
3+
4+
Redistribution and use in source and binary forms, with or without
5+
modification, are permitted provided that the following conditions are met:
6+
1. Redistributions of source code must retain the above copyright notice,
7+
this list of conditions and the following disclaimer.
8+
2. Redistributions in binary form must reproduce the above copyright notice,
9+
this list of conditions and the following disclaimer in the documentation
10+
and/or other materials provided with the distribution.
11+
12+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
13+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
16+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
18+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
19+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
20+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
21+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
22+
POSSIBILITY OF SUCH DAMAGE.

README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Open Movement Python Code
2+
3+
<!--
4+
```
5+
python -m pip install -e "git+https://github.com/digitalinteraction/openmovement-python.git#egg=openmovement"
6+
```
7+
-->
8+
9+
10+
11+
## omconvert wrapper
12+
13+
This is a Python wrapper for the `omconvert` binary, and Python implementations of some of the `omconvert` algorithms. The `omconvert` program will process `.cwa` and `.omx` binary files and produce calculated outputs, such as SVM and WTV (wear-time validation). It can also be used to output raw accelerometer `.csv` files (these will be very large), and they can be run through the Python versions of the analysis algorithms (slowly).
14+
15+
* [omconvert.py](openmovement/omconvert.py) - the Python wrapper containing the `OmConvert` class.
16+
17+
* [run_omconvert.py](openmovement/run_omconvert.py) - example code using the `OmConvert` class.
18+
19+
The example code exports the SVM and WTV files.
20+
21+
*IMPORTANT:* You will need the `omconvert` binary either in your `PATH`, in the current working directory, or in the same directory as the `omconvert.py` file (or, on Windows, if you have *OmGui* installed in the default location). On Windows you can use the `bin/build-omconvert.bat` script, or on macOS/Linux you can use the `bin/build-omconvert.sh` script, or see [omconvert](https://github.com/digitalinteraction/omconvert#open-movement-file-converter) for further instructions.
22+
23+
24+
## Iterable time series CSV loader
25+
26+
Note: This is quite slow for large amounts of data, and a `numpy`/`np.loadtxt()`, or `pandas`/`pd.readcsv()` would be faster if it was OK to load all of the data to memory.
27+
28+
* [timeseries_csv.py](openmovement/timeseries_csv.py) - An iterable CSV file reader. The first row can contain column headers. The first column must contain a timestamp. If the timestamp is numeric, the 'time_zero' option may be added. If the timestamp is an ISO-ish date/time, it is parsed as a time in seconds since the 1970 epoch date. In either case, no timezone information is known, so treat as a UTC time to correctly recover date/time of day. All other values must be numeric (a global scaling factor may be applied to these).
29+
30+
For files using a zero-based numeric timestamp, a helper `csv_time_from_filename()` has been provided to set the `"time_zero"` option in cases where the filename starts with the timestamp for the `0` time.
31+
32+
For files using raw data units, a helper `csv_scale_from_filename()` has been provided to set the `"global_scale"` option in cases where the base of the filename ends with a suffix that indicates the data type, from which the scaling may be derived.
33+
34+
35+
## Python implementations of some omconvert algorithms
36+
37+
Note: These iteration-based versions are quite slow for large amounts of data, and would probably benefit from a `numpy` version that operates from already-loaded data.
38+
39+
### SVM
40+
41+
* [calc_svm.py](openmovement/calc_svm.py) - Calculates (as an iterator) the mean *abs(SVM-1)* value for an epoch (default 60 seconds) given an iterator yielding `[time_seconds, x, y, z]`.
42+
43+
* [run_svm.py](openmovement/run_svm.py) - Example showing how to run the SVM calculation from a source `.csv` file to an output `.csvm.csv` file.
44+
45+
### WTV
46+
47+
* [calc_wtv.py](openmovement/calc_svm.py) - Calculates (as an iterator) the WTV (wear-time validation) value (30 minute epochs) given an iterator yielding `[time_seconds, x, y, z]`.
48+
49+
* [run_wtv.py](openmovement/run_wtv.py) - Example showing how to run the WTV calculation from a source `.csv` file to an output `.cwtv.csv` file.
50+

bin/.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
build-omconvert.sh text=auto eol=lf

bin/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/omconvert.build
2+
/omconvert
3+
/omconvert.exe

bin/build-omconvert.bat

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
@echo off
2+
cd /d "%~dp0"
3+
if not exist "..\..\..\src\omconvert\build.cmd" goto download_build
4+
call "..\..\..\src\omconvert\build.cmd"
5+
copy /y "..\..\..\src\omconvert\omconvert.exe" .
6+
goto end
7+
8+
:download_build
9+
powershell -Command "& {Invoke-WebRequest https://github.com/digitalinteraction/omconvert/archive/master.zip -o omconvert.build.zip ; Expand-Archive omconvert.build.zip ; del omconvert.build.zip ; omconvert.build/omconvert-master/src/omconvert/build.cmd ; copy omconvert.build/omconvert-master/src/omconvert/omconvert.exe . }"
10+
goto end
11+
12+
:end

bin/build-omconvert.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/bash
2+
set -e
3+
cd $(cd -P -- "$(dirname -- "$0")" && pwd -P)
4+
BUILD_DIR=../../../src/omconvert
5+
if [ ! -f "$BUILD_DIR/Makefile" ]; then
6+
mkdir -p omconvert.build
7+
curl -L https://github.com/digitalinteraction/omconvert/archive/master.zip -o omconvert.build/master.zip
8+
unzip -o omconvert.build/master.zip -d omconvert.build
9+
BUILD_DIR=omconvert.build/omconvert-master/src/omconvert
10+
fi
11+
make -C "$BUILD_DIR"
12+
cp "$BUILD_DIR/omconvert" .

openmovement/__init__.py

Whitespace-only changes.

openmovement/calc_svm.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
from math import sqrt
2+
3+
class CalcSvm:
4+
"""
5+
An iterator to calculate the SVM value for a given iterator yielding [time_seconds, x, y, z].
6+
options['epoch_size'] # seconds per epoch
7+
options['alignment'] # offset to align epoch; None=align to start of data; 0=align to wall-clock time
8+
"""
9+
10+
def __init__(self, input, options):
11+
self.input = input
12+
self.options = options
13+
14+
# Epoch size (default 1 minute)
15+
self.epoch_size = self.options.get('epoch_size', 60)
16+
17+
# Epoch alignment offset, e.g. 0=Align epochs since start; None=Align from start of data
18+
self.alignment = self.options.get('alignment', None)
19+
20+
self.current_epoch_id = None
21+
self.current_epoch_time = None
22+
self.ended = False
23+
24+
# Status
25+
self.count = 0
26+
self.sum = 0
27+
28+
29+
# Iterate on self
30+
def __iter__(self):
31+
return self
32+
33+
def __next__(self):
34+
while True:
35+
time = None
36+
if not self.ended:
37+
try:
38+
[time, x, y, z, *_] = next(self.input)
39+
except StopIteration:
40+
self.ended = True
41+
42+
# If epoch alignment is None, align to start of data stream
43+
if self.alignment is None and time is not None:
44+
self.alignment = -time
45+
46+
# Determine which epoch we are in
47+
next_epoch_id = None
48+
next_epoch_time = None
49+
if time is not None:
50+
next_epoch_id = (time + self.alignment) // self.epoch_size
51+
next_epoch_time = (next_epoch_id * self.epoch_size) - self.alignment
52+
53+
# If the epoch has changed, emit the previous result
54+
result = None
55+
if next_epoch_id != self.current_epoch_id:
56+
if self.count > 0:
57+
# Return mean SVM
58+
value = self.sum / self.count
59+
result = (self.current_epoch_time, value)
60+
self.sum = 0
61+
self.count = 0
62+
self.current_epoch_id = next_epoch_id
63+
self.current_epoch_time = next_epoch_time
64+
65+
# Calculate SVM and add to current epoch
66+
if time is not None:
67+
en = sqrt((x * x) + (y * y) + (z * z))
68+
enmo = en - 1
69+
svm = abs(enmo)
70+
self.sum += svm
71+
self.count += 1
72+
73+
# Return result
74+
if result is not None:
75+
return result
76+
77+
if time is None:
78+
raise StopIteration
79+

0 commit comments

Comments
 (0)