summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorChris Schlaeger <chris@linux.com>2016-09-23 22:11:30 +0200
committerChris Schlaeger <chris@linux.com>2016-09-23 22:11:30 +0200
commit883b38096eab0b824a56f4540f422caa49a84769 (patch)
treebfd2209b1ae925de552da290362456b0b24ff2e1 /lib
parent16820f68986df788698c174c161ae579d2bebcb4 (diff)
downloadpostrunner-883b38096eab0b824a56f4540f422caa49a84769.zip
Fix: Find sleep cycles even with noisy HR data.
Recent firmware updates for the Fenix3 produce much more noisy HR data. The original sleep cycle detector could not handle this well. This improved version uses minimum cycle times to detect the cycles more accurately.
Diffstat (limited to 'lib')
-rw-r--r--lib/postrunner/DailySleepAnalyzer.rb28
1 files changed, 19 insertions, 9 deletions
diff --git a/lib/postrunner/DailySleepAnalyzer.rb b/lib/postrunner/DailySleepAnalyzer.rb
index 05875e3..856c6b1 100644
--- a/lib/postrunner/DailySleepAnalyzer.rb
+++ b/lib/postrunner/DailySleepAnalyzer.rb
@@ -277,7 +277,13 @@ module PostRunner
# During the nightly sleep the heart rate is alternating between a high
# and a low frequency. The actual frequencies vary so that we need to look
- # for the transitions to classify each sample as high or low.
+ # for the transitions to classify each sample as high or low. Research has
+ # shown that sleep cycles are roughly 90 minutes long. The early cycles
+ # have a lot more deep sleep (low HR) and less REM (high HR) while with
+ # every cycle the deep sleep phase shortens and the REM phase gets longer.
+ # We assume that a normalized half-phase is at least 25 minutes long and
+ # the weight shifts by 4 minutes towards the high HR (REM) phase with
+ # every phase.
def categorize_sleep_heart_rate
@sleep_heart_rate_classification = Array.new(TIME_WINDOW_MINUTES, nil)
@@ -301,10 +307,12 @@ module PostRunner
if current_category == :high_hr
if last_heart_rate > @heart_rate[i]
# High/low transition found
- current_category = :low_hr
- transitions += 1
- last_transition_delta = last_heart_rate - @heart_rate[i]
- last_transition_index = i
+ if i - last_transition_index >= 25 - 2 * transitions
+ current_category = :low_hr
+ transitions += 1
+ last_transition_delta = last_heart_rate - @heart_rate[i]
+ last_transition_index = i
+ end
elsif last_heart_rate < @heart_rate[i] &&
last_transition_delta < @heart_rate[i] - last_heart_rate
# The previously found high segment was wrongly categorized as
@@ -320,10 +328,12 @@ module PostRunner
else
if last_heart_rate < @heart_rate[i]
# Low/High transition found.
- current_category = :high_hr
- transitions += 1
- last_transition_delta = @heart_rate[i] - last_heart_rate
- last_transition_index = i
+ if i - last_transition_index >= 25 + 2 * transitions
+ current_category = :high_hr
+ transitions += 1
+ last_transition_delta = @heart_rate[i] - last_heart_rate
+ last_transition_index = i
+ end
elsif last_heart_rate > @heart_rate[i] &&
last_transition_delta < last_heart_rate - @heart_rate[i]
# The previously found low segment was wrongly categorized as