Class: PostRunner::HRV_Analyzer

Inherits:
Object
  • Object
show all
Defined in:
lib/postrunner/HRV_Analyzer.rb

Overview

This class analyzes the heart rate variablity based on the R-R intervals in the given FIT file. It can compute RMSSD and a HRV score if the data quality is good enough.

Constant Summary collapse

LN_RMSSD_MIN =

According to Nunan et. al. 2010 (www.qeeg.co.uk/HRV/NUNAN-2010-A%20Quantitative%20Systematic%20Review%20of%20Normal%20Values%20for.pdf) rMSSD (ms) are expected to be in the rage of 19 to 75 in healthy, adult humans. Typical ln(rMSSD) (ms) values for healthy, adult humans are between 2.94 and 4.32. We use a slighly broader interval. We’ll add a bit of padding for our limits here.

2.9
LN_RMSSD_MAX =
4.4

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(arg) ⇒ HRV_Analyzer

Create a new HRV_Analyzer object.

Parameters:

  • arg (Activity, Array<Float>)

    R-R (or NN) time delta in seconds.



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/postrunner/HRV_Analyzer.rb', line 35

def initialize(arg)
  if arg.is_a?(Array)
    rr_intervals = arg
  else
    activity = arg
    # Gather the RR interval list from the activity. Note that HRV data
    # still gets recorded after the activity has been stoped until the
    # activity gets saved.
    # Each Fit4Ruby::HRV object has an Array called 'time' that contains up
    # to 5 R-R interval durations. If less than 5 values are present the
    # remaining are filled with nil entries.
    rr_intervals = activity.fit_activity.hrv.map do |hrv|
      hrv.time.compact
    end.flatten
  end
  #$stderr.puts rr_intervals.inspect

  cleanup_rr_intervals(rr_intervals)
end

Instance Attribute Details

#durationObject (readonly)

Returns the value of attribute duration.



22
23
24
# File 'lib/postrunner/HRV_Analyzer.rb', line 22

def duration
  @duration
end

#errorsObject (readonly)

Returns the value of attribute errors.



22
23
24
# File 'lib/postrunner/HRV_Analyzer.rb', line 22

def errors
  @errors
end

#hrvObject (readonly)

Returns the value of attribute hrv.



22
23
24
# File 'lib/postrunner/HRV_Analyzer.rb', line 22

def hrv
  @hrv
end

#timestampsObject (readonly)

Returns the value of attribute timestamps.



22
23
24
# File 'lib/postrunner/HRV_Analyzer.rb', line 22

def timestamps
  @timestamps
end

Instance Method Details

#data_qualityObject



62
63
64
# File 'lib/postrunner/HRV_Analyzer.rb', line 62

def data_quality
  (@hrv.size - @errors).to_f / @hrv.size * 100.0
end

#has_hrv_data?Boolean

The method can be used to check if we have valid HRV data. The FIT file must have HRV data and the measurement duration must be at least 30 seconds.

Returns:

  • (Boolean)


58
59
60
# File 'lib/postrunner/HRV_Analyzer.rb', line 58

def has_hrv_data?
  @hrv && !@hrv.empty? && total_duration > 30.0
end

#hrv_score(start_time = 0.0, duration = nil) ⇒ Object

The ln_rmssd values are hard to interpret. Since we know the expected range we’ll transform it into a value in the range 0 - 100. If the HRV is measured early in the morning while standing upright and with a regular 3s in/3s out breathing pattern the HRV Score is a performance indicator. The higher it is, the better the performance condition.



125
126
127
128
129
130
131
# File 'lib/postrunner/HRV_Analyzer.rb', line 125

def hrv_score(start_time = 0.0, duration = nil)
  ssd = ln_rmssd(start_time, duration)
  ssd = LN_RMSSD_MIN if ssd < LN_RMSSD_MIN
  ssd = LN_RMSSD_MAX if ssd > LN_RMSSD_MAX

  (ssd - LN_RMSSD_MIN) * (100.0 / (LN_RMSSD_MAX - LN_RMSSD_MIN))
end

#ln_rmssd(start_time = 0.0, duration = nil) ⇒ Object

The natural logarithm of rMSSD.

Parameters:

  • start_time (Float) (defaults to: 0.0)

    Determines at what time mark (in seconds) the computation should start.

  • duration (Float) (defaults to: nil)

    The duration of the total inteval in seconds to be considered for the computation. This value should be larger then 30 seconds to produce meaningful values.



116
117
118
# File 'lib/postrunner/HRV_Analyzer.rb', line 116

def ln_rmssd(start_time = 0.0, duration = nil)
  Math.log(rmssd(start_time, duration))
end

#rmssd(start_time = 0.0, duration = nil) ⇒ Object

Compute the root mean square of successive differences.

Parameters:

  • start_time (Float) (defaults to: 0.0)

    Determines at what time mark (in seconds) the computation should start.

  • duration (Float) (defaults to: nil)

    The duration of the total inteval in seconds to be considered for the computation. This value should be larger then 30 seconds to produce meaningful values.



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/postrunner/HRV_Analyzer.rb', line 77

def rmssd(start_time = 0.0, duration = nil)
  # Find the start index based on the requested interval start time.
  start_idx = 0
  @timestamps.each do |ts|
    break if ts >= start_time
    start_idx += 1
  end
  # Find the end index based on the requested interval duration.
  if duration
    end_time = start_time + duration
    end_idx = start_idx
    while end_idx < (@timestamps.length - 1) &&
          @timestamps[end_idx] < end_time
      end_idx += 1
    end
  else
    end_idx = -1
  end

  sum = 0.0
  cnt = 0
  @hrv[start_idx..end_idx].each do |i|
    if i
      # Input values are in seconds, but rmssd is usually computed from
      # milisecond values.
      sum += (i * 1000) ** 2.0
      cnt += 1
    end
  end

  Math.sqrt(sum / cnt)
end

#total_durationObject

Return the total duration of all measured intervals in seconds.



67
68
69
# File 'lib/postrunner/HRV_Analyzer.rb', line 67

def total_duration
  @timestamps[-1]
end