/*
* File: KalmanFilter.java
* Authors: Kevin R. Dixon
* Company: Sandia National Laboratories
* Project: Cognitive Foundry
*
* Copyright Oct 21, 2009, Sandia Corporation.
* Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
* license for use of this work by or on behalf of the U.S. Government.
* Export of this program may require a license from the United States
* Government. See CopyrightHistory.txt for complete details.
*
*/
package gov.sandia.cognition.statistics.bayesian;
import gov.sandia.cognition.annotation.PublicationReference;
import gov.sandia.cognition.annotation.PublicationReferences;
import gov.sandia.cognition.annotation.PublicationType;
import gov.sandia.cognition.math.matrix.Matrix;
import gov.sandia.cognition.math.matrix.MatrixFactory;
import gov.sandia.cognition.math.matrix.Vector;
import gov.sandia.cognition.math.matrix.VectorFactory;
import gov.sandia.cognition.math.signals.LinearDynamicalSystem;
import gov.sandia.cognition.statistics.distribution.MultivariateGaussian;
import gov.sandia.cognition.util.ObjectUtil;
/**
* A Kalman filter estimates the state of a dynamical system corrupted with
* white Gaussian noise with observations that are corrupted with white
* Gaussian noise.
* @author Kevin R. Dixon
* @since 3.0
*/
@PublicationReferences(
references={
@PublicationReference(
author="Wikipedia",
title="Kalman filter",
type=PublicationType.WebPage,
year=2009,
url="http://en.wikipedia.org/wiki/Kalman_filter"
)
}
)
public class KalmanFilter
extends AbstractKalmanFilter
{
/**
* Default autonomous dimension, {@value}.
*/
public static final int DEFAULT_DIMENSION = 1;
/**
* Motion model of the underlying system.
*/
protected LinearDynamicalSystem model;
/**
* Creates a new instance of KalmanFilter
*/
public KalmanFilter()
{
this( DEFAULT_DIMENSION );
}
/**
* Creates an autonomous, fully observable linear dynamical system
* with the given dimensionality
* @param dim
* Dimensionality of the LDS
*/
public KalmanFilter(
int dim )
{
// Autonomous Dynamical System:
// xn+1 = A*xn
// yn+1 = xn+1
// Also, we're using an identity for the model covariance and
// the measurement covariance
this( new LinearDynamicalSystem(
MatrixFactory.getDefault().createIdentity(dim,dim),
MatrixFactory.getDefault().createMatrix(dim,dim),
MatrixFactory.getDefault().createIdentity(dim, dim) ),
MatrixFactory.getDefault().createIdentity(dim, dim),
MatrixFactory.getDefault().createIdentity(dim, dim) );
}
/**
* Creates a new instance of LinearUpdater
* @param model
* Motion model of the underlying system.
* @param modelCovariance
* Covariance associated with the system's model.
* @param measurementCovariance
* Covariance associated with the measurements.
*/
public KalmanFilter(
LinearDynamicalSystem model,
Matrix modelCovariance,
Matrix measurementCovariance )
{
super( VectorFactory.getDefault().createVector(
model.getInputDimensionality() ),
modelCovariance,
measurementCovariance );
this.setModel(model);
}
@Override
public KalmanFilter clone()
{
KalmanFilter clone = (KalmanFilter) super.clone();
clone.setModel( ObjectUtil.cloneSafe( this.getModel() ) );
return clone;
}
public MultivariateGaussian createInitialLearnedObject()
{
return new MultivariateGaussian(
this.model.getState(), this.getModelCovariance() );
}
/**
* Getter for model
* @return
* Motion model of the underlying system.
*/
public LinearDynamicalSystem getModel()
{
return this.model;
}
/**
* Setter for model
* @param model
* Motion model of the underlying system.
*/
public void setModel(
LinearDynamicalSystem model)
{
this.model = model;
}
public void predict(
MultivariateGaussian belief)
{
// Load the belief into the model and then predict the next state
this.getModel().evaluate( this.currentInput, belief.getMean() );
Vector xpred = this.model.getState();
// Calculate the covariance, which will increase due to the
// inherent uncertainty of the model.
Matrix P = this.computePredictionCovariance(
this.model.getA(), belief.getCovariance() );
// Load the updated belief
belief.setMean( xpred );
belief.setCovariance( P );
}
public void measure(
MultivariateGaussian belief,
Vector observation)
{
final Matrix C = this.model.getC();
// Figure out what the model says the observation should be
Vector xpred = belief.getMean();
Vector ypred = C.times( xpred );
// Update step... compute the difference between the observation
// and what the model says.
// Then compute the Kalman gain, which essentially indicates
// how much to believe the observation, and how much to believe model
Vector innovation = observation.minus( ypred );
this.computeMeasurementBelief(belief, innovation, C);
}
}