Getting started
Requirements
Unity 2021.3 LTS or newer. No other packages required.
Installation
Three ways to add the package to your project:
- Local UPM package (recommended) —
Window > Package Manager > + > Add package from disk…and select the package’spackage.json. - Embedded package — copy the
com.kephstudio.gps-sensor-fusionfolder into your project’sPackages/folder. - Classic import — copy the
Runtime/scripts intoAssets/(you lose assembly-definition isolation).
Overview
GPS Sensor Fusion fuses GPS (low rate, position + velocity) with an optional AHRS/IMU (high rate, heading + turn rate) into a smooth, high-rate estimate of position, velocity and heading. Two filters are provided: a 6-state linear Kalman filter, and an 8-state Extended Kalman Filter (CTRV) that adds heading and turn rate and ingests AHRS measurements between GPS fixes.
What’s included
| KalmanFilter | 6-state linear filter (constant velocity) — simple and fast, GPS only. |
| ExtendedKalmanFilter | 8-state CTRV filter — best quality, fuses GPS + AHRS through turns. |
| HeadingFilter | Adaptive heading smoother (EMA + rate limit + stationary dead-zone). |
| GPSMovementState | CTRV dead-reckoning predictor between fixes. |
| NMEAGenerator / NmeaParser | Standard NMEA 0183 generation and parsing into a GpsFix. |
| GeoUtils | Geodesy: haversine, bearing, unit conversions, lat/lon → local ENU. |
| IGpsSource | Pluggable input: NMEA push, Unity LocationService, CSV replay. |
| SfMatrix | Zero-allocation dense matrix backing the filters. |
Coordinate conventions
All filters operate in Unity world meters: X = East, Y = Up, Z = North. Heading is in radians, 0 = North (+Z), increasing clockwise. Convert GPS latitude/longitude to a local metric frame around an origin before feeding the filter — GeoUtils.GpsCoordTo3D(refLat, refLon, refAlt, lat, lon, alt).
Quick start
using UnityEngine;
using KephStudio.SensorFusion;
public class Example : MonoBehaviour
{
private ExtendedKalmanFilter _ekf;
void Start()
{
// processNoise, measurementNoise, headingNoise, turnRateNoise
_ekf = new ExtendedKalmanFilter(1f, 3f, 0.1f, 0.1f);
_ekf.Reset(transform.position, Vector3.zero, heading: 0f, turnRate: 0f);
}
public void OnImu(float headingRad, float turnRate, float dt) // ~50 Hz
{
_ekf.Predict(dt);
_ekf.UpdateAHRS(headingRad, turnRate, 0.05f, 0.05f);
}
public void OnGps(Vector3 worldPos, Vector3 worldVel) // ~10 Hz
=> _ekf.UpdateGPS(worldPos, worldVel, 1f, 1f);
void Update()
{
transform.position = _ekf.GetPosition();
transform.rotation = Quaternion.Euler(0f, _ekf.GetHeading() * Mathf.Rad2Deg, 0f);
}
}
Call Predict once per elapsed dt, then apply whichever measurement arrived — GPS and AHRS updates are independent and run at their own rates.
Tuning
| Estimate lags real motion | Lower measurementNoise, or raise processNoise. |
| Estimate is jittery | Raise measurementNoise, or lower processNoise. |
| Overshoots in turns (EKF) | Raise turnRateProcessNoise and feed AHRS turn rate. |
| Poor fixes should count less | Pass larger position/velocity uncertainty (e.g. scale by HDOP). |
Samples
Import samples from the Package Manager (Samples tab).
- Synthetic Track Demo — Noisy GPS track → EKF → plots truth / noisy / filtered with LineRenderers. No hardware.
Support & license
Distributed under the Unity Asset Store EULA. Questions, bugs and feature requests are handled directly by the studio — contact@kephstudio.ch.