knitr::opts_chunk$set( collapse = TRUE, comment = "#>" )
library(psydiff)
psydiff is an R package for modeling latent stochastic differential equations based on the unscented Kalman filter described by Sarkka, S. (2007). On Unscented Kalman Filtering for State Estimation of Continuous-Time Nonlinear Systems. IEEE Transactions on Automatic Control, 52(9), 1631–1641. https://doi.org/10.1109/TAC.2007.904453. The package implements the square root version of the continuous discrete unscented Kalman filter.
$$ \begin{align} \text{d}x(t) &= f(x(t), t)\text{d}t + L\text{d}W(t)\ y_u &= h(x(t_u),t_u) + r_u \end{align} $$
where
The measurement error is assumed to be normally distributed with $r \sim N(0, R)$. The naming of the matrices is closely oriented at Sarkka (2007).
To fit the model, the initial state $m0$ (i.e., $x(0)$) and the Cholesky of the initial covariance matrix of the latent process $A0$ are required. If the model is fitted for a single individual, only one of those elements can be estimated. If the model is fitted to multiple individuals, both $m0$ and $A0$ can be estimated.
A model is generated with the newPsydiff function. The function requires at least:
Furthermore, a grouping function and additional elements can be passed to the function (see below).
The data set has to be in long format. It must be provided as list with the following fields:
The equations are specified as strings. Here is an example:
latentEquations <- " dx[0] = x[0]*(alpha - beta*x[1]); dx[1] = -x[1]*(gamma - delta*x[0]); "
There are a few important things to note:
As we are writing C++ code here, you can also incorporate quite complex models using, for instance, the Armadillo library which used by psydiff for most mathematical operations. For instance, assume that one of the "parameters" is a matrix called A. For whatever reason, we decide to use the matrix exponential in the latent equation. Then we can do this by:
latentEquations <- " arma::mat expOfA = arma::expm(A); dx[0] = x[0]*(alpha - beta*x[1]); dx[1] = -x[1]*(gamma - delta*x[0]); "
Note that we have to specify the class of the resulting variable (here: arma::mat).
The manifest equations work similarly to the latent equations. Here an example:
manifestEquations <- " y[0] = 1*x[0]; y[1] = a1*x[0]; y[2] = 1*x[1]; y[3] = a2*x[1]; "
Note that there are 4 manifest variables. Again, indexing starts at 0. a1 and a2 are loading parameters which we will have to specify in the parameters list.
The Cholesky of the diffusion matrix has to be specified as follows:
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.