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!

3 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: https://github.com/ufechner7/KiteViewer/blob/main/src/RTSim.jl
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?

@Ronis_BR the links are dead: could you please bring them back to life? I am trying to solve a similar problem and I could not find other relevant material.

Hi @mzaffalon !

Sorry for the delay. I removed the tutorials because they use a feature that is now deprecated and I am not sure it is still working.

OK, thank you for your reply.
Would you have a suggestion on how to tackle the problem?

What stops you from using the integrator interface?

Yes! If you need to simulate a dual system (discrete / continuous), my suggestion is to use the following recipe (we are using this exactly design in our satellite simulator):

  1. Identify all the continuous variables and integrate them in the dynamics function.
  2. Use discrete callbacks to call the discrete part of the system. Those functions will perform some calculations and save the output inside a mutable variable that must be passed using the parameter argument of the solver.
  3. In the dynamics part, use the information in the parameters that were modified inside the callback to modify the continuous part.

So, let’s say you have a system that controls the position of a car. In this system, the acceleration control is performed in a discrete system.

  1. The dynamics part will have the integration of the velocity and position using the acceleration value inside the parameter vector.
  2. The discrete callback will be called every sampling step. It will read the current position and velocity and obtain the correct acceleration to control the car position.
  3. The acceleration computed in the last step will be saved in the parameter vector, which will then be used in the dynamics part.

Please, let me know if you need more details!

2 Likes