Tips for Estimating Non-linear Latent SDE

I was hoping to use Turing.jl alongside DifferentialEquations.jl to estimate a partially observable SDE via quasi-likelihood methods. Being new to continuous-time models, I was hoping to get some suggestions on the most efficient way to proceed.

In the model below, z(t), π(t), and r(t) are assumed to be observed at discrete time-intervals without measurement error. While zg(t) and zπ(t) are not observed by the statistician, and thus are referred to as “latent factors”. These latent factors impact the drift of g(t) and π(t) respectively, and non-linearly impact the effect of g(t) and π(t) on D(r(t)). Lastly, note that the diffusion matrix is assumed to be diagonal, and all variables have constant drift with the exception of r(t), whose diffusion coefficient is proportional to sqrt(r(t)), resembling a Cox-Ingeroll-Ross interest rate model.

My guess is this kind of estimation requires an extended Kalman filter or a particle filter in order to compute the likliehood function, but I am not sure which is more suitable to my problem and easiest to implement in the SciML and Turing frameworks.

EDIT: After coming upon this (https://www.sas.upenn.edu/~jesusfv/hmc_dssm.pdf), maybe HMC is the way to go while sampling the latent states as part of the estimation.

using ModelingToolkit
using StochasticDiffEq
using Plots
using NaNMath

@variables t g(t) π(t) r(t) zg(t) zπ(t)
@parameters α_g α_π α_r κ_g κ_π κ_r κ_zg κ_zπ ϕ_g ϕ_π ζ_0g ζ_1g ζ_2g ζ_0π ζ_1π ζ_2π ζ_gπ σ_g σ_π σ_r σ_zg σ_zπ

D = Differential(t)

eqs = [D(g) ~ α_g + zg - κ_g * g - ϕ_g * r + ϕ_g * π, 
       D(π) ~ α_π + zπ - κ_π * π + ϕ_π * g,
       D(r) ~ α_r - κ_r * r + (ζ_0g + ζ_1g * zg + ζ_2g * zg^2) * g + 
                 (ζ_0π + ζ_1π * zπ + ζ_2π * zπ^2) * π + ζ_gπ * zg * zπ,
       D(zg) ~ - κ_zg * zg,
       D(zπ) ~ - κ_zπ * zπ
    ]

noiseeqs = [σ_g,
            σ_π,
            σ_r * NaNMath.sqrt(r),
            σ_zg,
            σ_zπ
    ]

@named macro_mdl = SDESystem(eqs, noiseeqs, t, [g, π, r, zg, zπ], [α_g, α_π, α_r, κ_g, κ_π, κ_r, κ_zg, κ_zπ, ϕ_g, ϕ_π, ζ_0g, ζ_1g, ζ_2g, ζ_0π, ζ_1π, ζ_2π, ζ_gπ, σ_g, σ_π, σ_r, σ_zg, σ_zπ])

u0map = [g => 0.0, π => 0.0075, r => 0.02, zg => 0.0, zπ => 0.0]
parammap = [α_g => 0.005, α_π => 0.005, α_r => 0.01, κ_g => 0.5, κ_π => 0.5, κ_r => 0.5, κ_zg => 0.5, κ_zπ => 0.5, ϕ_g => 0.5, ϕ_π => 0.5, ζ_0g => 0.01, ζ_1g => 0.1, ζ_2g => 0.2, ζ_0π => 0.0, ζ_1π => 0.3, ζ_2π => 0.2, ζ_gπ => 0.1, σ_g => 0.01, σ_π => 0.01, σ_r => 0.01, σ_zg => 0.01, σ_zπ => 0.01]

prob = SDEProblem(macro_mdl, u0map, (0.0,10000.0), parammap)
sol = solve(prob, SOSRI())
plot(sol)

Yes, I would suggest HMC as a good way to do this. Doing one solve of the SDE as the likelihood is an unbiased estimate of the likelihood, so doing HMC over that is a quasi-likelihood formulation that is fast and pretty robust.