13.3 Solving a System of Linear ODEs using a Matrix Exponential
The solution to ddty=ay is y=y0eat, where the constant y0 is determined by boundary conditions. We can extend this solution to the vector case:
ddty=Ay 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=etAy0 id:ode.linOEs.sln
where the matrix exponential is formally defined by the convergent power series:
etA=∞∑n=0tAnn!=I+tA+t2A22!+... id:ode.matrix_exp.def
We can apply this technique to the simple harmonic oscillator example, by setting
y=[y1y2] A=[01−1−θ] 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.