Class: PostRunner::SleepCycle
- Inherits:
-
Object
- Object
- PostRunner::SleepCycle
- Defined in:
- lib/postrunner/SleepCycle.rb
Overview
A sleep cycle consists of several sleep phases. This class is used to gather and store the relevant data of a sleep cycle. Data is analzyed and stored with a one minute granularity. Time values are stored as minutes past the zero_idx_time.
Instance Attribute Summary collapse
-
#end_idx ⇒ Object
Returns the value of attribute end_idx.
-
#high_low_trans_idx ⇒ Object
Returns the value of attribute high_low_trans_idx.
-
#low_high_trans_idx ⇒ Object
Returns the value of attribute low_high_trans_idx.
-
#next_cycle ⇒ Object
Returns the value of attribute next_cycle.
-
#prev_cycle ⇒ Object
Returns the value of attribute prev_cycle.
-
#start_idx ⇒ Object
Returns the value of attribute start_idx.
-
#total_seconds ⇒ Object
readonly
Returns the value of attribute total_seconds.
-
#totals ⇒ Object
readonly
Returns the value of attribute totals.
Instance Method Summary collapse
-
#adjust_cycle_boundaries(phases) ⇒ Object
Initially, we use the high/low heart rate transition to mark the end of the cycle.
-
#detect_phases(phases) ⇒ Object
Gather a list of SleepPhase objects that describe the sequence of sleep phases in the provided Array.
-
#from_time ⇒ Time
The start time of the cycle as Time object.
-
#has_deep_sleep_phase? ⇒ Boolean
Check if the cycle has a deep sleep phase.
-
#has_leading_deep_sleep_phase? ⇒ Boolean
Check if any of the previous cycles that are directly attached have a deep sleep cycle.
-
#has_trailing_deep_sleep_phase? ⇒ Boolean
Check if any of the trailing cycles that are directly attached have a deep sleep cycle.
-
#initialize(zero_idx_time, start_idx, prev_cycle = nil) ⇒ SleepCycle
constructor
Create a new SleepCycle record.
-
#is_wake_cycle? ⇒ Boolean
Check if this cycle is really a sleep cycle or not.
-
#to_time ⇒ Time
The end time of the cycle as Time object.
-
#unlink ⇒ Object
Remove this cycle from the cycle chain.
Constructor Details
#initialize(zero_idx_time, start_idx, prev_cycle = nil) ⇒ SleepCycle
Create a new SleepCycle record.
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/postrunner/SleepCycle.rb', line 57 def initialize(zero_idx_time, start_idx, prev_cycle = nil) @zero_idx_time = zero_idx_time @start_idx = start_idx # These values will be determined later. @end_idx = nil # Every sleep cycle has at most one high/low heart rate transition and # one low/high transition. These variables store the time of these # transitions or nil if the transition does not exist. Every cycle must # have at least one of these transitions to be a valid cycle. @high_low_trans_idx = @low_high_trans_idx = nil @prev_cycle = prev_cycle # Register this cycle as successor of the previous cycle. prev_cycle.next_cycle = self if prev_cycle @next_cycle = nil # Array holding the sleep phases of this cycle @phases = [] # A hash with the total durations (in secods) of the various sleep # phases. @total_seconds = Hash.new(0) end |
Instance Attribute Details
#end_idx ⇒ Object
Returns the value of attribute end_idx.
46 47 48 |
# File 'lib/postrunner/SleepCycle.rb', line 46 def end_idx @end_idx end |
#high_low_trans_idx ⇒ Object
Returns the value of attribute high_low_trans_idx.
46 47 48 |
# File 'lib/postrunner/SleepCycle.rb', line 46 def high_low_trans_idx @high_low_trans_idx end |
#low_high_trans_idx ⇒ Object
Returns the value of attribute low_high_trans_idx.
46 47 48 |
# File 'lib/postrunner/SleepCycle.rb', line 46 def low_high_trans_idx @low_high_trans_idx end |
#next_cycle ⇒ Object
Returns the value of attribute next_cycle.
46 47 48 |
# File 'lib/postrunner/SleepCycle.rb', line 46 def next_cycle @next_cycle end |
#prev_cycle ⇒ Object
Returns the value of attribute prev_cycle.
46 47 48 |
# File 'lib/postrunner/SleepCycle.rb', line 46 def prev_cycle @prev_cycle end |
#start_idx ⇒ Object
Returns the value of attribute start_idx.
46 47 48 |
# File 'lib/postrunner/SleepCycle.rb', line 46 def start_idx @start_idx end |
#total_seconds ⇒ Object (readonly)
Returns the value of attribute total_seconds.
45 46 47 |
# File 'lib/postrunner/SleepCycle.rb', line 45 def total_seconds @total_seconds end |
#totals ⇒ Object (readonly)
Returns the value of attribute totals.
45 46 47 |
# File 'lib/postrunner/SleepCycle.rb', line 45 def totals @totals end |
Instance Method Details
#adjust_cycle_boundaries(phases) ⇒ Object
Initially, we use the high/low heart rate transition to mark the end of the cycle. But it’s really the end of the REM phase that marks the end of a sleep cycle. If we find a REM phase, we use its end to adjust the sleep cycle boundaries.
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/postrunner/SleepCycle.rb', line 102 def adjust_cycle_boundaries(phases) end_of_rem_phase_idx = nil @start_idx.upto(@end_idx) do |i| end_of_rem_phase_idx = i if phases[i] == :rem end if end_of_rem_phase_idx # We have found a REM phase. Adjust the end_idx of this cycle # accordingly. @end_idx = end_of_rem_phase_idx if @next_cycle # If we have a successor phase, we also adjust the start. @next_cycle.start_idx = end_of_rem_phase_idx + 1 end end end |
#detect_phases(phases) ⇒ Object
Gather a list of SleepPhase objects that describe the sequence of sleep phases in the provided Array.
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/postrunner/SleepCycle.rb', line 122 def detect_phases(phases) @phases = [] current_phase = phases[0] current_phase_start = @start_idx @start_idx.upto(@end_idx) do |i| if (current_phase && current_phase != phases[i]) || i == @end_idx # We found a transition in the sequence. Create a SleepPhase object # that describes the prepvious segment and add it to the @phases # list. @phases << (p = SleepPhase.new(idx_to_time(current_phase_start), idx_to_time(i == @end_idx ? i + 1 : i), current_phase)) # Add the duration of the phase to the corresponding sum in the # @total_seconds Hash. @total_seconds[current_phase] += p.duration # Update the variables that track the start and kind of the # currently read phase. current_phase_start = i current_phase = phases[i] end end end |
#from_time ⇒ Time
The start time of the cycle as Time object
80 81 82 |
# File 'lib/postrunner/SleepCycle.rb', line 80 def from_time idx_to_time(@start_idx) end |
#has_deep_sleep_phase? ⇒ Boolean
Check if the cycle has a deep sleep phase.
160 161 162 163 164 165 166 167 |
# File 'lib/postrunner/SleepCycle.rb', line 160 def has_deep_sleep_phase? # A real deep sleep phase must be at least 10 minutes long. @phases.each do |p| return true if p.phase == :nrem3 && p.duration > 10 * 60 end false end |
#has_leading_deep_sleep_phase? ⇒ Boolean
Check if any of the previous cycles that are directly attached have a deep sleep cycle.
172 173 174 175 176 177 |
# File 'lib/postrunner/SleepCycle.rb', line 172 def has_leading_deep_sleep_phase? return false if @prev_cycle.nil? || @start_idx != @prev_cycle.end_idx + 1 @prev_cycle.has_deep_sleep_phase? || @prev_cycle.has_leading_deep_sleep_phase? end |
#has_trailing_deep_sleep_phase? ⇒ Boolean
Check if any of the trailing cycles that are directly attached have a deep sleep cycle.
182 183 184 185 186 187 |
# File 'lib/postrunner/SleepCycle.rb', line 182 def has_trailing_deep_sleep_phase? return false if @next_cycle.nil? || @end_idx + 1 != @next_cycle.start_idx @next_cycle.has_deep_sleep_phase? || @next_cycle.has_trailing_deep_sleep_phase? end |
#is_wake_cycle? ⇒ Boolean
Check if this cycle is really a sleep cycle or not. A sleep cycle must have at least one deep sleep phase or must be part of a directly attached series of cycles that contain a deep sleep phase.
151 152 153 154 |
# File 'lib/postrunner/SleepCycle.rb', line 151 def is_wake_cycle? !has_deep_sleep_phase? && !has_leading_deep_sleep_phase? && !has_trailing_deep_sleep_phase? end |
#to_time ⇒ Time
The end time of the cycle as Time object.
86 87 88 |
# File 'lib/postrunner/SleepCycle.rb', line 86 def to_time idx_to_time(@end_idx + 1) end |
#unlink ⇒ Object
Remove this cycle from the cycle chain.
91 92 93 94 |
# File 'lib/postrunner/SleepCycle.rb', line 91 def unlink @prev_cycle.next_cycle = @next_cycle if @prev_cycle @next_cycle.prev_cycle = @prev_cycle if @next_cycle end |