# NDSolve with WhenEvent, resetting system for a prolonged period

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:

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):

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}]


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

• 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. – El_kingo Nov 5 '14 at 10:49
• @ciao: you might want to reward this short but useful answer :) – anderstood Feb 21 '17 at 15:40