Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EKF #32

Closed
wants to merge 7 commits into from
Closed

EKF #32

wants to merge 7 commits into from

Conversation

FredericWantiez
Copy link
Member

No description provided.

@THargreaves
Copy link
Collaborator

THargreaves commented Feb 2, 2024

What do you think about this as a way to generalise the interface?

abstract type GaussianSSM end

struct PendulumModel <: GaussianSSM
    x0::Float64
    dt::Float64
    Q::Matrix{Float64}
    R::Matrix{Float64}
end

function f(x::Vector{Float64}, model::PendulumModel)
    return [x[1] + x[2] * dt, x[2] - g * sin(x[1]) * model.dt]
end

# Pre-defined methods need to expect a covariance matrix.
# This could be defined completely differently for different concrete models.
# E.g. the covariance matrix could be an arbitrary function of the step number.
function process_covariance(model::PendulumModel)
    return model.Q
end

# Generic methods for any Gaussian SSM that do not need to
# be specified by the user

# Note, these don't use model.Q since this may not exist.
# Instead `process_covariance`` is called.

# Used to run EKF
function transition!!(model::GaussianSSM, state::Gaussian)
    Jf = ForwardDiff.jacobian(x -> f(x, model), state.μ)
    pred = f(state.μ, model)
    return Gaussian(pred, Jf * state.Σ * Jf' + process_covariance(model))
end

# Used to run particle filter
function transition!!(model::GaussianSSM, x::Vector{Float64})
    return f(x, model) + rand(MvNormal(process_covariance(model)))
end

@THargreaves
Copy link
Collaborator

This approach only has inheritance in one direction.

E.g.
A LinearGaussianModel knows it's a GaussianSSM which knows it's a SSM

Hence a KF, EKF or PF can be used on a LinearGaussianModel.

The reverse is not true. Even if an GaussianSSM has affine f, as far as I can tell, there is no way for the KF to know that. I don't think this is a massive issue though.

end

function ekf_correct(obs, state::Gaussian, model::PendulumModel)
Jf = jacobian(x -> f(x, model), state.μ)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't have to compute the jacobian twice

h(x::Array, model::PendulumModel) = [sin(x[1])]

function transition!!(::AbstractRNG, model::PendulumModel)
return Gaussian(model.x0, zeros(2,2))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[JuliaFormatter] reported by reviewdog 🐶

Suggested change
return Gaussian(model.x0, zeros(2,2))
return Gaussian(model.x0, zeros(2, 2))

@FredericWantiez
Copy link
Member Author

FredericWantiez commented Mar 5, 2024

What do you think about this as a way to generalise the interface?

abstract type GaussianSSM end

struct PendulumModel <: GaussianSSM
    x0::Float64
    dt::Float64
    Q::Matrix{Float64}
    R::Matrix{Float64}
end

function f(x::Vector{Float64}, model::PendulumModel)
    return [x[1] + x[2] * dt, x[2] - g * sin(x[1]) * model.dt]
end

# Pre-defined methods need to expect a covariance matrix.
# This could be defined completely differently for different concrete models.
# E.g. the covariance matrix could be an arbitrary function of the step number.
function process_covariance(model::PendulumModel)
    return model.Q
end

# Generic methods for any Gaussian SSM that do not need to
# be specified by the user

# Note, these don't use model.Q since this may not exist.
# Instead `process_covariance`` is called.

# Used to run EKF
function transition!!(model::GaussianSSM, state::Gaussian)
    Jf = ForwardDiff.jacobian(x -> f(x, model), state.μ)
    pred = f(state.μ, model)
    return Gaussian(pred, Jf * state.Σ * Jf' + process_covariance(model))
end

# Used to run particle filter
function transition!!(model::GaussianSSM, x::Vector{Float64})
    return f(x, model) + rand(MvNormal(process_covariance(model)))
end

In general the API here is really tailored to the particle filter point of view. To implement the unscented kalman filter we would need a few more functions, like your process_covariance as well as emission

@THargreaves
Copy link
Collaborator

In general the API here is really tailored to the particle filter point of view. To implement the unscented kalman filter we would need a few more functions, like your process_covariance as well as emission

I would agree with this as a general sentiment. It feels quite awkward writing these specific models in such a way that they can be generalised to a generic SSM that a particle filter can run on. At least all of this would be hidden from the user.

For the Kalman Filter the burden becomes even greater, you would need to define functions for:

  • state_transition_model
  • observation_matrix
  • process_covariance
  • observation_covariance
  • control_input_model

as listed here.

I question how much benefit is gained from this added complexity.

@yebai yebai closed this Jul 31, 2024
@yebai yebai deleted the fred/ekf branch July 31, 2024 22:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants