Published on June 20, 2026 • Written by Marcus Chen (Co-Founder & Engineering)
When we set out to build Velo, our main technical challenge was eliminating the sluggish updates common to mobile GPS speedometers. In most navigation applications, the current speed updates roughly once per second, resulting in a visible delay during accelerating or braking. In this technical article, we will dissect how Velo achieves a responsive 10Hz sampling frequency on iOS using CoreLocation and Swift.
To acquire high-frequency speed updates, the location engine must request location data with the highest accuracy setting and set the distance filter to zero. This ensures that every coordinate change registers as a delegate event, regardless of distance traveled.
let locationManager = CLLocationManager()
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.pausesLocationUpdatesAutomatically = false
locationManager.allowsBackgroundLocationUpdates = true
High-frequency coordinates bring increased noise. When stationary or driving under bridges, signal reflections can cause coordinate bounce, falsely displaying a speed when the vehicle is stopped. To fix this, Velo applies a low-pass noise filter that validates the horizontal accuracy (in meters) and timestamps of each coordinate update:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let latestLocation = locations.last else { return }
// Ignore inaccurate points (horizontal accuracy threshold = 15m)
guard latestLocation.horizontalAccuracy >= 0 && latestLocation.horizontalAccuracy <= 15 else { return }
// Filter speed values. Ignore negative fallback values (-1.0)
let rawSpeed = latestLocation.speed
let filteredSpeed = rawSpeed > 0 ? rawSpeed : 0.0
// Convert meters/sec to kilometers/hour
let kmhSpeed = filteredSpeed * 3.6
DispatchQueue.main.async {
self.updateSpeedometerGauge(speed: kmhSpeed)
}
}
Simply updating the UI with raw GPS values at 10Hz can still cause jittery movements. To smooth the needle transition, Velo utilizes CoreAnimation. Instead of jumping to the new rotation, we animate the needle path using a quick ease-out curve matching a duration of 0.15 seconds, creating a dial experience that matches physical speedometers.