(in-package #:common-lisp) (defpackage #:moving-average (:use #:common-lisp) (:export #:moving-average #:add-sample #:average)) (in-package #:moving-average) (defclass moving-average () ((sample-count :accessor sample-count :initform 0 :type (mod #.array-dimension-limit)) (index :accessor index :initform 0 :type (mod #.array-dimension-limit)) (samples :accessor samples :type simple-vector))) (defmethod initialize-instance :after ((m moving-average) &key maximum-samples) (check-type maximum-samples (mod #.array-dimension-limit)) (setf (samples m) (make-array maximum-samples)) (values)) (defmethod add-sample ((m moving-average) value) (check-type value number) (with-slots (sample-count index samples) m (let ((maximum-samples (length samples))) (setf (aref samples index) value) (setf index (mod (1+ index) maximum-samples)) (when (< sample-count maximum-samples) (incf sample-count)))) (values)) (defmethod average ((m moving-average)) (with-slots (sample-count samples) m (when (zerop sample-count) (error "no samples to average")) (loop repeat sample-count for sample across samples summing sample into total finally (return (/ total sample-count)))))