13.3 Solving a System of Linear ODEs using a Matrix Exponential
The solution to \(\frac{d}{dt} y = ay\) is \(y = y_0e^{at}\), where the constant \(y_0\) is determined by boundary conditions. We can extend this solution to the vector case:
\[ \frac{d}{dt}y = A y \] id:ode.linODEs
where \(y\) is now a vector of length \(n\) and \(A\) is an \(n\) by \(n\) matrix. The solution is then given by:
\[ y = e^{tA}y_0 \] id:ode.linOEs.sln
where the matrix exponential is formally defined by the convergent power series:
\[ e^{tA} = \sum_{n=0}^{\infty} \dfrac{tA^n}{n!} = I + tA + \frac{t^2A^2}{2!} + ... \] id:ode.matrix_exp.def
We can apply this technique to the simple harmonic oscillator example, by setting
\[ y = \left[\begin{array}{c} y_1 \\ y_2 \\ \end{array}\right] \ \ \ \ \ A = \left[\begin{array}{cc} 0 & 1 \\ -1 & -\theta \\ \end{array}\right] \] id:ode.sho_matrix
The Stan model to simulate noisy observations using a matrix exponential function
is given below. Because we are performing matrix
operations, we declare y0 and y_hat as vectors, instead of using arrays,
as in the previous example code.
In general, computing a matrix exponential will be more efficient than using a numerical solver. We can however only apply this technique to systems of ODEs.
data {
int<lower=1> T;
vector[2] y0;
real ts[T];
real theta[1];
}
model {
}
generated quantities {
vector[2] y_hat[T];
matrix[2, 2] A = [[ 0, 1],
[-1, -theta[1]]]
for (t in 1:T)
y_hat[t] = matrix_exp((t - 1) * A) * y0;
// add measurement error
for (t in 1:T) {
y_hat[t, 1] += normal_rng(0, 0.1);
y_hat[t, 2] += normal_rng(0, 0.1);
}
}
id:sho-sim-me.figure
This Stan program simulates noisy measurements from a simple harmonic
oscillator. The system of linear differential equations is coded as a
matrix. The system parameters theta and initial state y0 are read
in as data along observation times ts. The generated quantities
block is used to solve the ODE for the specified times and then add
random measurement error, producing observations y_hat. Because the
ODEs are linear, we can use the matrix_exp function to solve the
system.