Hi,
I am using MTK to set up a hierarchical dynamical system. As the input to the (otherwise ODE) system can also be random uniform noise, I need to set up SDESystem (instead of ODESystem). However, I cannot find out how to define uniformly distributed noise with MTK, only the Brownian noise, by using the macro @brownian.
TLTR; Is it possible to do it and if someone has an example of how to do it, I would really greatly appreciate it. Thank you.
A longer description of what I have tried:
i) Simulation with DifferentialEquations.jl to have the ground truth. (Although, interestingly, the simulation also works with the ODEProblem definition here, not necessarily the SDEProblem)
Code and output for simulating with DifferentialEquations.jl
using DifferentialEquations
using Plots
using Interpolations
# Sigmoid function
function sigmoid(V, e0, r, θ)
return 2 * e0 / (1 + exp(r * (θ - V)))
end
# Jansen-Rit equations
function jansen_rit!(du, u, p, t)
A0, a0, A1, a1, A2, a2, C1, C2, C3, C4, e0, r, v0, I_ext = p
du[1] = u[4]
du[2] = u[5]
du[3] = u[6]
du[4] = A0 * a0 * sigmoid(u[2] - u[3], e0, r, v0) - 2 * a0 * u[4] - a0^2 * u[1]
du[5] = A1 * a1 * (I_ext(t) + C2 * sigmoid(C1 * u[1], e0, r, v0)) - 2 * a1 * u[5] - a1^2 * u[2]
du[6] = A2 * a2 * (C4 * sigmoid(C3 * u[1], e0, r, v0)) - 2 * a2 * u[6] - a2^2 * u[3]
end
function noise!(du, u, p, t)
du[1] = 0.
du[2] = 0.
du[3] = 0.
du[4] = 0.
du[5] = 0.
du[6] = 0.
end
# Simulation settings
A0, a0, A1, a1, A2, a2 = 3.25, 100.0, 3.25, 100.0, 22., 50.0
C1, e0, r, v0 = 135.0, 5., 0.56, 6.0
C2, C3, C4 = 0.8 * C1, 0.25 * C1, 0.25 * C1
u0 = [0.39057, -204.28131, -3.88133, -0.11387, -7.68439, -253.32597]
tspan = (0.0, 10.0)
dts = 1e-2
dt = 1e-4
# noise settings 1
time_vals = 0:dts:tspan[2] |> collect
noise_vals = rand(length(time_vals)) .* 320
I_ext = LinearInterpolation(time_vals, noise_vals, extrapolation_bc=Line())
p = [A0, a0, A1, a1, A2, a2, C1, C2, C3, C4, e0, r, v0, I_ext]
# Solve the ODE problem
prob = SDEProblem(jansen_rit!, noise!, u0, tspan, p)
sol = solve(prob, EM(), dt=dt, saveat=dts)
plot(sol[1, :])
ii) Simulation with MTK by having a placeholder for noise inside SDESystem, but then putting the true uniform noise (via NoiseGrid) only inside SDEProblem. This doesn’t work - the noise argument inside SDEProblem is completely disregarded, regardless of the values I put in.
Code and output for ii)
using ModelingToolkit
using ModelingToolkit: t_nounits as t, D_nounits as D
using DifferentialEquations
using Plots
# Model
function sigmoid(V, e0, r, θ)
return 2 * e0 / (1 + exp(r * (θ - V)))
end
params = @parameters A0 a0 A1 a1 A2 a2 C1 C2 C3 C4 e0 r v0
vars = @variables (u(t))[1:6]
eqs = [D(u[1]) ~ u[4],
D(u[2]) ~ u[5],
D(u[3]) ~ u[6],
D(u[4]) ~ A0 * a0 * sigmoid(u[2] - u[3], e0, r, v0) - 2 * a0 * u[4] - a0^2 * u[1],
D(u[5]) ~ A1 * a1 * (C2 * sigmoid(C1 * u[1], e0, r, v0)) - 2 * a1 * u[5] - a1^2 * u[2],
D(u[6]) ~ A2 * a2 * (C4 * sigmoid(C3 * u[1], e0, r, v0)) - 2 * a2 * u[6] - a2^2 * u[3]
]
noiseeqs = [0., 0., 0., 0., 1. , 0.]
# Simulation settings
params_map = Dict(A0 => 3.25, a0 => 100.0, A1 => 3.25, a1 => 100.0,
A2 => 22.0, a2 => 50.0, C1 => 135.0, C2 => 33.75,
C3 => 33.75, C4 => 108.0, e0 => 5.0, r => 0.56, v0 => 6.0)
inits = [0.39057, -204.28131, -3.88133, -0.11387, -7.68439, -253.32597]
tspan = (0.0, 10.0)
dts = 1e-2
dt = 1e-4
sys = structural_simplify(SDESystem(eqs, noiseeqs, t, vars, params; name=Symbol("JR")))
# Noise definition
time_vals = 0:dts:tspan[2] |> collect
noise_vals = rand(6, length(time_vals)) .* 320
noisegrid = NoiseGrid(time_vals, [noise_vals[:,i] for i in 1:size(noise_vals)[2]])
prob = SDEProblem(sys, inits, tspan, params_map; noise=noisegrid)
sol = solve(prob, EM(), dt=dt, saveat=dts)
plot(sol[1, :])
iii) Simulation with MTK using Brownian distribution. It somehow works, but I cannot get the same output as with ground truth, it is only an approximation. If there is a better way, it would be great.
Code and output for iii)
using ModelingToolkit
using ModelingToolkit: t_nounits as t, D_nounits as D
using DifferentialEquations
using Plots
function sigmoid(V, e0, r, θ)
return 2 * e0 / (1 + exp(r * (θ - V)))
end
params = @parameters A0 a0 A1 a1 A2 a2 C1 C2 C3 C4 e0 r v0
vars = @variables (u(t))[1:6]
eqs = [D(u[1]) ~ u[4],
D(u[2]) ~ u[5],
D(u[3]) ~ u[6],
D(u[4]) ~ A0 * a0 * sigmoid(u[2] - u[3], e0, r, v0) - 2 * a0 * u[4] - a0^2 * u[1],
D(u[5]) ~ A1 * a1 * (C2 * sigmoid(C1 * u[1], e0, r, v0)) - 2 * a1 * u[5] - a1^2 * u[2],
D(u[6]) ~ A2 * a2 * (C4 * sigmoid(C3 * u[1], e0, r, v0)) - 2 * a2 * u[6] - a2^2 * u[3]
]
noiseeqs = [0., 0., 0., 0., 102400. , 0.]
# Parameters
params_map = Dict(A0 => 3.25, a0 => 100.0, A1 => 3.25, a1 => 100.0,
A2 => 22.0, a2 => 50.0, C1 => 135.0, C2 => 33.75,
C3 => 33.75, C4 => 108.0, e0 => 5.0, r => 0.56, v0 => 6.0)
inits = [0.39057, -204.28131, -3.88133, -0.11387, -7.68439, -253.32597]
tspan = (0.0, 10.0)
dts = 1e-2
dt = 1e-4
sys = structural_simplify(SDESystem(eqs, noiseeqs, t, vars, params; name=Symbol("JR")))
prob = SDEProblem(sys, inits, tspan, params_map) # noise=noisegrid)
sol = solve(prob, EM(), dt=dt, saveat=dts)
plot(sol[1, :])
I anyone has some ideas and would be willing to help, would be great. Thank you!