lqml/examples/wear-os-gps/lisp/kalman.lisp

50 lines
1.5 KiB
Common Lisp

;;; A 'Kalman' filter is a much more sophisticated filter than a simple
;;; 'low-pass' filter.
;;;
;;; It takes a theoretically well founded approach, which means: it makes an
;;; 'educated guess' of the next position to be expected, and 'corrects' it
;;; with actual GPS data, considering the accuracy and the speed of current raw
;;; GPS data.
;;;
;;; For most use cases this is already sufficiently precise.
;;;
;;; If you need more precision, you would need to integrate e.g. accelerometer
;;; data into the Kalman filter.
(defpackage :kalman
(:use :cl)
(:nicknames :kal)
(:export
#:*lat*
#:*lon*
#:*timestamp*
#:*variance*
#:filter
#:reset))
(in-package :kal)
(defvar *lat* nil)
(defvar *lon* nil)
(defvar *timestamp* nil)
(defvar *variance* nil)
(defun reset ()
(setf *variance* nil))
(defun filter (lat lon accuracy speed)
(when (and lat lon accuracy speed)
(setf accuracy (max 1 accuracy))
(let ((timestamp (get-internal-real-time)))
(if *variance*
(let ((time-inc (- timestamp *timestamp*)))
(incf *variance* (/ (* time-inc (expt speed 2)) 1000))
(setf *timestamp* timestamp)
(let ((k (/ *variance* (+ *variance* (expt accuracy 2)))))
(incf *lat* (* k (- lat *lat*)))
(incf *lon* (* k (- lon *lon*)))
(setf *variance* (* (- 1 k) *variance*))))
(setf *lat* lat
*lon* lon
*timestamp* timestamp
*variance* (expt accuracy 2))))))