I am currently working on a complex system where I would like to (for the lack of a better description) reset (part) of the system for a certain period.

Say I five ODE's: x'[t], y1'[t], y2'[t], z1'[t] and z2'[t], with initial conditions x[0]=1, y1[0]=0, y2[0]=0, z1[0]=0, z2[0]=0

What I'm aiming for is that part if this system (x, y1 and y2) is reset at set intervals (for example 50 days (time steps are in days) and kept in that state for a certain period (10 days), while z1'[t] and z2'[t] are not being reset.

One of my attempts was to use a separate function to test if the system should be reset: resetSystem[t, period, duty] := -1*UnitBox[Mod[t/period, 1]/(2 duty)] + 1, called with the following parameters: resetSystem[t, 60, 50/60] will return the needed information: output of resetSystem[]

Using NDSolve with a WhenEvent part works only partly:

NDSolve[{dxdt, dy1dt, dy2dt, dz1dt, dz2dt, x[0]==1, y1[0]==0, y2[0]==0, z1[0]==0, z2[0]==0, WhenEvent[resetSystem[t, 60, 50/60] == 1, {x[t], y1[t], y2[t]} -> {1, 0, 0}]}, {x, y1,y2,z1,z2}, {t, 0, tmax}];

This works only partly, the system is correctly reset at the first event trigger, however it fails to keep the system in the reset state for the prolonged period (10 days):

output of x[t]

This is probably due to the fact that the events are too close together for Mathematica to pick up, but I don't know how to get around this...

So my question is: is there a way to do this or should I fall back to a programming approach where I keep track of time and call the different functions / do the resetting myself?


I can only imagine doing this with two controlling events, one to turn the system off (and reset) and one to turn the system back on. I made up a simple example, which I hope you can adapt to whatever your code is. The basic idea of the example is a harmonic oscillator system which can have damping turned on or off and which will reset when the energy reaches a preset level. I introduce two variables, switch and timer, and specify that they are DiscreteVariables, which means they don't change value except when explictly set through WhenEvent. When the energy dissipates to the level where the system is reset, damping is turned off by setting switch[t] -> 0 and the timer is set with timer[t] -> t (the first WhenEvent). When the time t is 10 seconds greater than the value of timer[t], damping is turned back on by setting switch[t] -> 1 (the second WhenEvent).

energy[x_, v_, k_] := (k x^2 + v^2)/2;
tmax = 80;
offdelay = 10;
damping = 1/6;
spring = 7;
foo = NDSolve[{
    x''[t] + damping*switch[t] x'[t] + spring*x[t] == 0,
    {x[0], x'[0]} == {10, 0},
    switch[0] == 1, timer[0] == tmax,
    WhenEvent[energy[x[t], x'[t], spring] == 10,
     {x[t], x'[t], switch[t], timer[t]} -> {10, 0, 0, t}],
    WhenEvent[timer[t] < t - offdelay, {switch[t] -> 1}]},
   x, {t, 0, tmax},
   DiscreteVariables -> {switch, timer}];

Plot[x[t] /. foo // Evaluate, {t, 0, tmax}]

Mathematica graphics

I think the key to solving your problem is introducing a variable like timer.

  • $\begingroup$ Very good example, does exactly what I was looking for! Indeed the key is using the double WhenEvent with the timer variable, I didn't think of that! With only minimal adjustments could I implement it in my own code. $\endgroup$
    – El_kingo
    Nov 5 '14 at 10:49
  • $\begingroup$ @ciao: you might want to reward this short but useful answer :) $\endgroup$
    – anderstood
    Feb 21 '17 at 15:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.