(* Discontinuous blocks in discrete time *) (* Coulomb and Viscous Friction *) let discrete sgn(x) = if x > 0.0 then 1.0 else if x < 0.0 then -1.0 else 0.0 let discrete coulomb(gain, offset, x) = y where rec y = sgn(x) *. (gain *. abs_float (x) +. offset) let discrete coulomb_scalar_input(n)(gain, offset, x) = y where rec g = gain *. abs_float (x) and forall i in 0 .. (n - 1), offseti in offset, yi out y do yi = sgn(x) *. (g +. offseti) done let discrete coulomb_vectors(n)(gain, offset, x) = y where rec forall i in 0 .. (n - 1), xi in x, offseti in offset, yi out y do yi = sgn(xi) *. (gain *. abs_float (xi) +. offseti) done (* Quantizer. Produce a staircase function *) let discrete quantizer(q, u) = y where y = q *. floor(u /. q) (* Saturation block. *) let saturation(upper, lower, u) = min (max lower u) upper (* Relay *) let node relay(son, soff, von, voff, u) = r where rec automaton | On -> do r = von unless (soff -. u > 0.) then Off | Off -> do r = voff unless (u -. son > 0.) then On end (* Rising edge. *) (* forbids two consecutive hits, e.g., x(n-2) < 0.0, x(n-1) = 0.0, x(n) > 0.0 *) let node rising x = let rec hit = false -> if x > 0.0 then pre(x) <= 0.0 && not (pre hit) else if x = 0.0 then pre x < 0.0 else false in hit let node falling x = let rec hit = false -> if x < 0.0 then pre x >= 0.0 && not (pre hit) else if x = 0.0 then pre x > 0.0 else false in hit let node either x = let rec hit = false -> if x > 0.0 then pre x <= 0.0 else if x = 0.0 then pre x < 0.0 else if x < 0.0 then pre x >= 0.0 else false in hit let node dead_zone(ll, ul, u) = y where y = if u <= ll then u -. ll else if u >= ul then u -. ul else 0.0 let node wrap_to_zero(threshold, u) = y where y = if u > threshold then 0.0 else u let node backlash (width, y0, (u, u')) = y where rec half_width = width /. 2.0 and init y = y0 and automaton | Disengaged -> do unless (u -. (last y +. half_width) >= 0.) then Engaged_positive else (u -. (last y -. half_width) <= 0.) then Engaged_negative | Engaged_positive -> do y = u -. half_width unless (u' < 0.) then Disengaged | Engaged_negative -> do y = u +. half_width unless (u' > 0.) then Disengaged end let node memory(i, x) = i fby x