Module: PostRunner::HRZoneDetector
- Defined in:
- lib/postrunner/HRZoneDetector.rb
Constant Summary collapse
- GARMIN_ZONES =
Number of heart rate zones supported by Garmin devices.
5
- MAX_HR =
Maximum heart rate that can be stored in FIT files.
255
Class Method Summary collapse
Class Method Details
.detect_zones(fit_records, secs_in_zones) ⇒ Object
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/postrunner/HRZoneDetector.rb', line 22 def HRZoneDetector::detect_zones(fit_records, secs_in_zones) if fit_records.empty? raise RuntimeError, "records must not be empty" end if secs_in_zones.size != GARMIN_ZONES + 1 raise RuntimeError, "secs_in_zones must have #{GARMIN_ZONES + 1} " + "elements" end # We generate a histogram of the time spent at each integer heart rate. histogram = Array.new(MAX_HR + 1, 0) = nil fit_records.each do |record| next unless record.heart_rate if # We ignore all intervals that are larger than 10 seconds. This # potentially conflicts with smart recording, but I can't see how a # larger sampling interval can yield usable results. if (delta_t = record. - ) <= 10 histogram[record.heart_rate] += delta_t end end = record. end # We'll process zones 5 downto 1. zone = GARMIN_ZONES hr_mins = Array.new(GARMIN_ZONES) # Sum of time spent in current zone. secs_in_current_zone = 0 # We process the histogramm from highest to smallest HR value. Whenever # we have accumulated the provided amount of time we have found a HR # zone boundary. We complete the current zone and continue with the next # one. MAX_HR.downto(0) do |i| secs_in_current_zone += histogram[i] if secs_in_current_zone > secs_in_zones[zone] # In case we have collected more time than was specified for the # zone we carry the delta over to the next zone. secs_in_current_zone -= secs_in_zones[zone] # puts "Zone #{zone}: #{secs_in_current_zone} #{secs_in_zones[zone]}" break if (zone -= 1) < 0 end hr_mins[zone] = i end hr_mins end |