I have a discontinuous function ($u(t)$, a square wave) and I would like WhenEvent to trigger when the signal goes high/low, i.e. when the value of $u(t)$ changes. I was hoping to use the derivative of $u(t)$ to determine this.

squareWave[t_, period_, duty_] := UnitBox[Mod[t/period, 1.]/(2. duty)]

system =  {x'[t] == u[t], WhenEvent[Mod[t, 0.5 τ], 
    u[t] -> squareWave[t, 2 τ, 0.2]], x[0] == 0, u[0] == 1, 
    WhenEvent[D[u[t]] > 0, Print[t]]};
params = {τ -> 1};
sol = NDSolve[system /. params, {x, u}, {t, 0, 10}, 
   DiscreteVariables -> u];
Plot[Evaluate[{x[t], u[t], u'[t]} /. sol], {t, 0, 10}, 
   PlotLegends -> {"x(t)", "u(t)", "u'[t]"}]

Unfortunately this does not seem to work? The output is:


  • $\begingroup$ for me with 9.0.1 this gives the error "NDSolve::disder: Cannot take the derivative of discrete variable u." which seems quite self explaining. Other than that it seems to work, although as the squareWave only depends on time you wouldn't really need a WhenEvent. Which version/OS are you using? $\endgroup$ Jul 30, 2013 at 9:05
  • $\begingroup$ I was using 9.0.0 on OS X, but updated to 9.0.1 and now I also see the proper error message. I'll update the question. $\endgroup$
    – Gerrit
    Jul 30, 2013 at 15:37
  • $\begingroup$ @Nasser Isn't the derivative of a square wave a series of dirac delta functions, each positioned where the amplitude changes? $\endgroup$
    – Gerrit
    Jul 31, 2013 at 11:40
  • $\begingroup$ @Nasser Good point! I've replaced UnitBox with HeavisidePi, but it still doesn't work. $\endgroup$
    – Gerrit
    Jul 31, 2013 at 12:04

1 Answer 1


The reason why D[u[t]]>0 doesn't work is that the derivative at the changing point doesn't exist. You can verify this by:

D[UnitBox[x], x]

$\begin{array}{cc} \{ & \begin{array}{cc} \text{Indeterminate} & x=\frac{1}{2}\lor x=-\frac{1}{2} \\ 0 & \text{True} \\ \end{array} \\ \end{array}$

So the predicate in WhenEvent never come true.

If you refer to the documentation, in the details and options of WhenEvent, you may pay great attention to this

pred the predicate pred becomes True
f==0&&pred f crosses zero and pred is True

In the first case, your action in WhenEvent is evaluated only when pred jump from false to true. While in the second case, action is evaluated when pred keeps true and f crosses zero.

So for your purpose, you may change the WhenEvent part to this

WhenEvent[{u[t] == 0, u[t] == 1}, Print[t]]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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