package ride import "time" const MovingTimeAlgorithmVersion = "v1" // movingTimeMinSpeedMps is the minimum implied speed between two consecutive // track points for the interval to count as moving (0.4 km/h). const movingTimeMinSpeedMps = 0.4 / 3.6 // movingTimeMaxGap is the maximum time gap between consecutive track points // that can count as moving. Longer gaps are pauses (stops, lost signal). const movingTimeMaxGap = 120 * time.Second // Bench (356 rides, `-backtest`): // absMean 2.5%, bias -1.3, p50 0.8, p75 2.9, p90 6.0, p95 9.3, p99 26.2. func MovingTime(r Ride) time.Duration { return movingTime(r, movingTimeMinSpeedMps, movingTimeMaxGap) } func movingTime(r Ride, minSpeedMps float64, maxGap time.Duration) time.Duration { var moving time.Duration for i := 1; i < r.Len(); i++ { dt := r.Timestamp(i).Sub(r.Timestamp(i - 1)) if dt <= 0 || dt > maxGap { continue } dd := r.DistanceM(i) - r.DistanceM(i-1) if dd/dt.Seconds() > minSpeedMps { moving += dt } } return moving }