Class: RoadToRubykaigi::CalibrationResult
- Inherits:
-
Data
- Object
- Data
- RoadToRubykaigi::CalibrationResult
- Defined in:
- lib/road_to_rubykaigi/calibration_result.rb
Instance Attribute Summary collapse
-
#continuation_threshold ⇒ Object
readonly
Returns the value of attribute continuation_threshold.
-
#gravity_vector ⇒ Object
readonly
Returns the value of attribute gravity_vector.
-
#jump_sample_count ⇒ Object
readonly
Returns the value of attribute jump_sample_count.
-
#jump_v_max ⇒ Object
readonly
Returns the value of attribute jump_v_max.
-
#start_threshold ⇒ Object
readonly
Returns the value of attribute start_threshold.
-
#static_sample_count ⇒ Object
readonly
Returns the value of attribute static_sample_count.
-
#walk_cadence ⇒ Object
readonly
Returns the value of attribute walk_cadence.
-
#walk_cadence_sample_count ⇒ Object
readonly
Returns the value of attribute walk_cadence_sample_count.
-
#walk_intensity ⇒ Object
readonly
Returns the value of attribute walk_intensity.
Class Method Summary collapse
-
.from_samples(static:, walk:, jump:) ⇒ Object
Derives calibrated values from per-phase collected samples.
-
.max_vertical_acceleration(samples, gravity) ⇒ Object
Max upward acceleration (in g, gravity subtracted) observed across jump samples.
-
.mean_vector(samples) ⇒ Object
Averaged [x, y, z] of the resting accelerometer, used as the gravity reference.
- .median(values) ⇒ Object
Instance Method Summary collapse
Instance Attribute Details
#continuation_threshold ⇒ Object (readonly)
Returns the value of attribute continuation_threshold
2 3 4 |
# File 'lib/road_to_rubykaigi/calibration_result.rb', line 2 def continuation_threshold @continuation_threshold end |
#gravity_vector ⇒ Object (readonly)
Returns the value of attribute gravity_vector
2 3 4 |
# File 'lib/road_to_rubykaigi/calibration_result.rb', line 2 def gravity_vector @gravity_vector end |
#jump_sample_count ⇒ Object (readonly)
Returns the value of attribute jump_sample_count
2 3 4 |
# File 'lib/road_to_rubykaigi/calibration_result.rb', line 2 def jump_sample_count @jump_sample_count end |
#jump_v_max ⇒ Object (readonly)
Returns the value of attribute jump_v_max
2 3 4 |
# File 'lib/road_to_rubykaigi/calibration_result.rb', line 2 def jump_v_max @jump_v_max end |
#start_threshold ⇒ Object (readonly)
Returns the value of attribute start_threshold
2 3 4 |
# File 'lib/road_to_rubykaigi/calibration_result.rb', line 2 def start_threshold @start_threshold end |
#static_sample_count ⇒ Object (readonly)
Returns the value of attribute static_sample_count
2 3 4 |
# File 'lib/road_to_rubykaigi/calibration_result.rb', line 2 def static_sample_count @static_sample_count end |
#walk_cadence ⇒ Object (readonly)
Returns the value of attribute walk_cadence
2 3 4 |
# File 'lib/road_to_rubykaigi/calibration_result.rb', line 2 def walk_cadence @walk_cadence end |
#walk_cadence_sample_count ⇒ Object (readonly)
Returns the value of attribute walk_cadence_sample_count
2 3 4 |
# File 'lib/road_to_rubykaigi/calibration_result.rb', line 2 def walk_cadence_sample_count @walk_cadence_sample_count end |
#walk_intensity ⇒ Object (readonly)
Returns the value of attribute walk_intensity
2 3 4 |
# File 'lib/road_to_rubykaigi/calibration_result.rb', line 2 def walk_intensity @walk_intensity end |
Class Method Details
.from_samples(static:, walk:, jump:) ⇒ Object
Derives calibrated values from per-phase collected samples.
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/road_to_rubykaigi/calibration_result.rb', line 14 def self.from_samples(static:, walk:, jump:) # Use p95 rather than max so a single stray spike during "still" doesn't # inflate every downstream threshold. sorted_static = static[:intensities].sort noise_ceiling = sorted_static[(sorted_static.size * 0.95).floor] || 0.0 # Noise ceiling * 2.5 as the threshold separating noise from walking. # Stays above noise even in short-window valleys between steps. # 2.5 is an empirical factor derived from real calibration data. start_threshold = noise_ceiling * 2.5 # Continuation uses a short window (fast stop detection) which is noise-sensitive, # so use a higher threshold for noise tolerance. continuation_threshold = noise_ceiling * 5.0 gravity_vector = mean_vector(static[:raw_samples]) new( start_threshold:, continuation_threshold:, walk_cadence: median(walk[:cadences]), # Median walking step cadence in Hz, representing individual step frequency. walk_intensity: median(walk[:intensities]), # Used by the intensity-boost path that lifts in-place running (elevated intensity, walk-level cadence). gravity_vector:, jump_v_max: max_vertical_acceleration(jump[:raw_samples], gravity_vector), static_sample_count: static[:intensities].size, walk_cadence_sample_count: walk[:cadences].size, jump_sample_count: jump[:raw_samples].size, ) end |
.max_vertical_acceleration(samples, gravity) ⇒ Object
Max upward acceleration (in g, gravity subtracted) observed across jump samples.
52 53 54 55 56 57 |
# File 'lib/road_to_rubykaigi/calibration_result.rb', line 52 def self.max_vertical_acceleration(samples, gravity) gravity_magnitude = Math.sqrt(gravity[0] ** 2 + gravity[1] ** 2 + gravity[2] ** 2) samples.map { |sample| (sample[0] * gravity[0] + sample[1] * gravity[1] + sample[2] * gravity[2]) / gravity_magnitude - gravity_magnitude }.max || 0.0 end |
.mean_vector(samples) ⇒ Object
Averaged [x, y, z] of the resting accelerometer, used as the gravity reference.
47 48 49 |
# File 'lib/road_to_rubykaigi/calibration_result.rb', line 47 def self.mean_vector(samples) samples.transpose.map { |values| values.sum / values.size } end |
.median(values) ⇒ Object
41 42 43 44 |
# File 'lib/road_to_rubykaigi/calibration_result.rb', line 41 def self.median(values) sorted = values.sort sorted[sorted.size / 2] || 0.0 end |
Instance Method Details
#save ⇒ Object
59 60 61 62 63 64 65 66 67 68 |
# File 'lib/road_to_rubykaigi/calibration_result.rb', line 59 def save Config.save_calibration( start_threshold: start_threshold.round(6), continuation_threshold: continuation_threshold.round(6), walk_cadence: walk_cadence.round(6), walk_intensity: walk_intensity.round(6), gravity_vector: gravity_vector.map { |value| value.round(6) }, jump_v_max: jump_v_max.round(6), ) end |