Kalman Filter
| This documentation was generated with the assistance of AI. Please report any inaccuracies. |
The Kalman filter is a recursive estimator for the state of a discrete-time linear system from a sequence of
noisy measurements. It was introduced in Kalman, 1960, and is implemented as
KalmanFilter in the com.irurueta.numerical.signal.processing package. The class’s own Javadoc states that
"the source code, notation and formulae… are borrowed from the JKalman tutorial [Welch95]," referencing
Welch and Bishop, 1995 directly by URL — its notation for the state transition
matrix , control matrix , measurement matrix , and noise covariances /
is exactly the notation this class’s API uses.
System model
The filter assumes the true state evolves linearly, and is observed only through a linear, noisy measurement:
where is the (unobserved) state at step , is an optional external control input, is the measurement actually taken, and and are independent, zero-mean Gaussian process and measurement noise. Neither noise term is observed directly — only their covariances and are assumed known (typically is estimated from real sensor data by Measurement Noise Covariance Estimation, while is chosen intuitively to reflect how much unmodeled dynamics the filter should tolerate).
Predict and correct
Each step alternates between two phases. Predict (time update) projects the previous state forward using only the system model, before any new measurement is available:
Correct (measurement update) then folds in the new measurement , weighted by the Kalman gain :
is the innovation — the discrepancy between the actual measurement and what the model
predicted it would be. The gain balances how much to trust that discrepancy against how much to
trust the prediction: a large (noisy sensor) shrinks , leaning on the model; a large
(uncertain prediction) grows , leaning on the measurement. KalmanFilter.correct(Matrix)
solves for via Utils.solve on rather than
forming the matrix inverse explicitly, which is the more numerically stable way to reach the same result.
Library implementation
KalmanFilter(dynamParams, measureParams, controlParams) allocates all matrices for a system with dynamParams
state dimensions (dp) and measureParams measurement dimensions (mp); controlParams (cp) may be 0
(no control input, no B matrix) or omitted entirely via the two-argument constructor.
-
predict()/predict(Matrix control)— runs the time update, storing the result instatePre/errorCovPreand returningstatePre. -
correct(Matrix measurement)— runs the measurement update, storing the result instatePost/errorCovPost/gainand returningstatePost. -
Matrix accessors mirror the equations above directly:
getTransitionMatrix()/setTransitionMatrix(Matrix)( ,dp×dp),getControlMatrix()/setControlMatrix(Matrix)( ,dp×cp),getMeasurementMatrix()/setMeasurementMatrix(Matrix)( ,mp×dp),getProcessNoiseCov()/setProcessNoiseCov(Matrix)( ,dp×dp, must be symmetric),getMeasurementNoiseCov()/setMeasurementNoiseCov(Matrix)( ,mp×mp, must be symmetric),getErrorCovPre()/getErrorCovPost()( / ), andgetGain()( ). -
getStatePre()/setStatePre(Matrix)andgetStatePost()/setStatePost(Matrix)expose the state vectors directly, letting a caller seed the filter’s initial state before the firstpredict()/correct()call. -
Defaults:
transitionMatrixanderrorCovPoststart as identity,processNoiseCovasDEFAULT_PROCESS_NOISE_VARIANCE(1e-6) times identity, andmeasurementNoiseCovasDEFAULT_MEASUREMENT_NOISE_VARIANCE(1e-1) times identity — all meant to be overridden once the actual system’s dynamics and sensor noise are known.
A lower makes the filter trust its own model more, producing a smoother but slower-to-react state
estimate; a higher lets it follow the true state more quickly at the cost of noisier output — the same
trade-off applies to , in the opposite direction, since a KalmanFilter weighs prediction against
measurement purely through the ratio between the two.
|
Example
Estimating a constant scalar value ( , , no control) from repeated noisy measurements — the simplest possible instance of the model, and the introductory example used by Welch and Bishop, 1995 themselves:
final var filter = new KalmanFilter(1, 1);
filter.setStatePost(new Matrix(1, 1)); // initial guess: 0.0
final var processNoise = new Matrix(1, 1);
processNoise.setElementAtIndex(0, 1e-5); // small: the true value does not change
filter.setProcessNoiseCov(processNoise);
final var measurementNoise = new Matrix(1, 1);
measurementNoise.setElementAtIndex(0, 0.01); // from the sensor's known noise variance
filter.setMeasurementNoiseCov(measurementNoise);
for (final var z : measurements) { // measurements: double[] of noisy readings
filter.predict();
final var measurement = new Matrix(1, 1);
measurement.setElementAtIndex(0, z);
filter.correct(measurement);
}
final var estimate = filter.getStatePost().getElementAtIndex(0);