Mixing time-discrete and time-continuous systems in a simulation

Hello all!

Does anyone what’s currently the best way in the Julia ecosystem to mix time-continuous and time-discrete systems in one simulation? (e.g. I want to simulate a continuous system regulated by time-discrete controller). I managed to implement it using DifferentialEquations.jl and Callbacks that modify the parameter struct that is passed to the equation.
However it is not the most efficient way (in terms of implementation effort) and I was wondering if there are better ways to do that.

Thanks in advance!

2 Likes

DiffEq+Callbacks is what it would all lower to. The easier way to do it would be ModelingToolkit.jl, but the capability is still quite fresh and not too documented right now (also still a bit buggy). That will definitely be the future, but I would probably still recommend manual writing of callbacks for now unless you’re looking for an adventure.

2 Likes

Thank you for the quick response!

Ah, I’m looking forward when this is implemented in ModelingToolkit; then I can hopefully drop MATLAB/Simulink for good.

Some discussion here DiffEqs: Hybrid (continuous+discrete) system / periodic callback - #39 by Ronis_BR

1 Like

Hi @tqml !

I wrote two tutorials about how we are doing this:

https://ronanarraes.com/tutorials/julia/ordinarydiffeq-simulating-continuous-discrete-systems/

https://ronanarraes.com/tutorials/julia/extending-ode-solutions-custom-data-arrays/

This idea is being used in the AOCS simulator of the Amazonia-1, a satellite built by the National Institute of Space Research (INPE). The data obtained after launch showed that the accuracy is superb, and the execution time is amazingly small given how many things are simulated.

3 Likes

Is it a stochastic or deterministic system?

its deterministic

For each timestep of my discrete controller I run one continues time simulation. See: KiteViewer/RTSim.jl at main · ufechner7/KiteViewer · GitHub
I tried with callbacks, but when I tried that it was way too slow, might be different nowadays…

DiscreteCallbacks should have no overhead in that case. It would be good to get an MWE if that isn’t the case. ContinuousCallbacks on the other hand have a lot more to calculate of course.

1 Like

But would you expect any disadvantage of not using callbacks and running

 step!(integrator, dt, true)

on every time step of the discrete controller as I do it?

The adjoint won’t be defined using the integrator interface, and that won’t compose with automated ensemble parallelism. Otherwise it’s fine.

What is the meaning of “adjoint” in this context?

Thanks for the nice examples, they really help!

For now I solved it by modifying the integrator parameter struct, and using it to keep track of the time-discrete control state (which is in turn modified each PeriodicCallback Interval).

Are there any (obvious or non-obvious) problems with this approach, which might lead to wrong results (e.g. like not using full_cache)? I currently see a slight discrepancy between the result I get in Simulink and the one I get in Julia (where the Julia solution has more noise/variation around the steady state).

A little bit more details about the problem: The continuous system is actuated via a PWM where the duty cycle is controlled via time-discrete controller. The PWM therefore produces a discontinuity at each iteration and to make sure, that the solver doesn’t skip it, I use a fixed step size of 1/512 of the switching period.

1 Like

The continuous adjoint of the ODE, used in reverse mode AD. See

It’s always the same adjoint, just used for different things.

This kind of behavior seems more likely related to the solver configurations in Simulink. AFAIK, MATLAB uses by default some automatic algorithm for absolute or relative tolerances. Did you configure MATLAB with the same parameters and solver you used in Julia?