apps: heart: Implement a debug mode to copy out raw data
Signed-off-by: Daniel Thompson <daniel@redfelineninja.org.uk>
This commit is contained in:
parent
3bbd808115
commit
92812e5ad2
2 changed files with 57 additions and 1 deletions
|
@ -8,6 +8,28 @@ A graphing heart rate monitor using a PPG sensor.
|
||||||
|
|
||||||
.. figure:: res/HeartApp.png
|
.. figure:: res/HeartApp.png
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
|
This program also implements some (entirely optional) debug features to
|
||||||
|
store the raw heart data to the filesystem so that the samples can be used
|
||||||
|
to further refine the heart rate detection algorithm.
|
||||||
|
|
||||||
|
To enable the logging feature select the heart rate application using the
|
||||||
|
watch UI and then run the following command via wasptool:
|
||||||
|
|
||||||
|
.. code-block:: sh
|
||||||
|
|
||||||
|
./tools/wasptool --eval 'wasp.system.app.debug = True'
|
||||||
|
|
||||||
|
Once debug has been enabled then the watch will automatically log heart
|
||||||
|
rate data whenever the heart rate application is running (and only
|
||||||
|
when it is running). Setting the debug flag to False will disable the
|
||||||
|
logging when the heart rate monitor next exits.
|
||||||
|
|
||||||
|
Finally to download the logs for analysis try:
|
||||||
|
|
||||||
|
.. code-block:: sh
|
||||||
|
|
||||||
|
./tools/wasptool --pull hrs.data
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import wasp
|
import wasp
|
||||||
|
@ -18,6 +40,10 @@ class HeartApp():
|
||||||
"""Heart rate monitor application."""
|
"""Heart rate monitor application."""
|
||||||
NAME = 'Heart'
|
NAME = 'Heart'
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._debug = False
|
||||||
|
self._hrdata = None
|
||||||
|
|
||||||
def foreground(self):
|
def foreground(self):
|
||||||
"""Activate the application."""
|
"""Activate the application."""
|
||||||
wasp.watch.hrs.enable()
|
wasp.watch.hrs.enable()
|
||||||
|
@ -32,11 +58,13 @@ class HeartApp():
|
||||||
wasp.system.request_tick(1000 // 8)
|
wasp.system.request_tick(1000 // 8)
|
||||||
|
|
||||||
self._hrdata = ppg.PPG(wasp.watch.hrs.read_hrs())
|
self._hrdata = ppg.PPG(wasp.watch.hrs.read_hrs())
|
||||||
|
if self._debug:
|
||||||
|
self._hrdata.enable_debug()
|
||||||
self._x = 0
|
self._x = 0
|
||||||
|
|
||||||
def background(self):
|
def background(self):
|
||||||
wasp.watch.hrs.disable()
|
wasp.watch.hrs.disable()
|
||||||
del self._hrdata
|
self._hrdata = None
|
||||||
|
|
||||||
def _subtick(self, ticks):
|
def _subtick(self, ticks):
|
||||||
"""Notify the application that its periodic tick is due."""
|
"""Notify the application that its periodic tick is due."""
|
||||||
|
@ -87,3 +115,13 @@ class HeartApp():
|
||||||
|
|
||||||
t.stop()
|
t.stop()
|
||||||
del t
|
del t
|
||||||
|
|
||||||
|
@property
|
||||||
|
def debug(self):
|
||||||
|
return self._debug
|
||||||
|
|
||||||
|
@debug.setter
|
||||||
|
def debug(self, value):
|
||||||
|
self._debug = value
|
||||||
|
if value and self._hrdata:
|
||||||
|
self._hrdata.enable_debug()
|
||||||
|
|
18
wasp/ppg.py
18
wasp/ppg.py
|
@ -10,6 +10,7 @@ raw PPG signals into something useful.
|
||||||
|
|
||||||
import array
|
import array
|
||||||
import micropython
|
import micropython
|
||||||
|
import watch
|
||||||
|
|
||||||
@micropython.viper
|
@micropython.viper
|
||||||
def _compare(d1, d2, count: int, shift: int) -> int:
|
def _compare(d1, d2, count: int, shift: int) -> int:
|
||||||
|
@ -94,6 +95,7 @@ class PPG():
|
||||||
def __init__(self, spl):
|
def __init__(self, spl):
|
||||||
self._offset = spl
|
self._offset = spl
|
||||||
self.data = array.array('b')
|
self.data = array.array('b')
|
||||||
|
self.debug = None
|
||||||
|
|
||||||
self._hpf = Biquad(0.87033078, -1.74066156, 0.87033078,
|
self._hpf = Biquad(0.87033078, -1.74066156, 0.87033078,
|
||||||
-1.72377617, 0.75754694)
|
-1.72377617, 0.75754694)
|
||||||
|
@ -106,6 +108,8 @@ class PPG():
|
||||||
|
|
||||||
Must be called at 24Hz for accurate heart rate calculations.
|
Must be called at 24Hz for accurate heart rate calculations.
|
||||||
"""
|
"""
|
||||||
|
if self.debug != None:
|
||||||
|
self.debug.append(spl)
|
||||||
spl -= self._offset
|
spl -= self._offset
|
||||||
spl = self._hpf.step(spl)
|
spl = self._hpf.step(spl)
|
||||||
spl = self._agc.step(spl)
|
spl = self._agc.step(spl)
|
||||||
|
@ -167,4 +171,18 @@ class PPG():
|
||||||
# Clear out the accumulated data
|
# Clear out the accumulated data
|
||||||
self.data = array.array('b')
|
self.data = array.array('b')
|
||||||
|
|
||||||
|
# Dump the debug data
|
||||||
|
if self.debug:
|
||||||
|
with open('hrs.data', 'ab') as f:
|
||||||
|
# Re-sync marker
|
||||||
|
f.write(b'\xff\xff')
|
||||||
|
now = watch.rtc.get_localtime()
|
||||||
|
f.write(array.array('H', now[:6]))
|
||||||
|
f.write(self.debug)
|
||||||
|
self.debug = array.array('H')
|
||||||
|
|
||||||
return hr
|
return hr
|
||||||
|
|
||||||
|
def enable_debug(self):
|
||||||
|
if self.debug == None:
|
||||||
|
self.debug = array.array('H')
|
||||||
|
|
Loading…
Reference in a new issue