(* Basic integration. [k] is a gain; [x0] is the initial position; *)
(* [u] the input to integrate. *)
let hybrid int(k, x0, u) = x where rec der x = k *. u init x0

(* the same but with [x0] and [u], two floatting point vectors of size [n] *)
let hybrid vint(n)(x0, u) = x where
  rec forall i in 0 .. (n - 1), x0i in x0, ui in u, xi out x do
        der xi = ui init x0i done

(* the same as [vint] but with a call to the integration function [int] *)
let hybrid vint2(n)(x0, u) = x where
  rec forall i in 0 .. (n - 1), x0i in x0, ui in u, xi out x do
        xi = int(1.0, x0i, ui) done

(* The integration with reset. Useless as it can be programmed from *)
(* the regular integrator surrended by a reset/every. There is no difference *)
(* with the discrete-time case except that [res] must be an event. *)
(* let hybrid reset_int(k, x0, res, u) = (x, last x) where
  rec reset
        der x = k *. u init x0
      every res *)

let hybrid reset_int(k, x0, res, u) = (x, x) where
  rec der x = k *. u init x0 reset res -> x0

(* Integration with limit *)
(* let hybrid limit_int(k, y0, upper, lower, r, u) = (y, sat) where
  rec reset
	init y = y0
      and
        automaton
        | Between ->
            (* regular mode. Integrate the signal *)
	    do der y = k *. u and sat = Dint.Between
	    unless up(y -. upper) then Upper
	    else up(-. (y -. lower)) then Lower
        | Upper ->
            (* when the input [u] is negative *)
            do y = upper and sat = Dint.Upper unless up(-. u) then Between
        | Lower ->
            (* when the input [u] is positive *)
	    do y = lower and sat = Dint.Lower unless up(u) then Between
        end
      every r
      *)

let hybrid limit_int(k, y0, upper, lower, r, u) = (y, sat) where
  rec reset
	init y = y0
      and
        automaton
        | Between ->
            (* regular mode. Integrate the signal *)
	    do der y = k *. u and sat = Dint.Between
	    unless up(last y -. upper) then Upper
	    else up(-. (last y -. lower)) then Lower
        | Upper ->
            (* when the input [u] is negative *)
            do y = upper and sat = Dint.Upper unless up(-. u) then Between
        | Lower ->
            (* when the input [u] is positive *)
	    do y = lower and sat = Dint.Lower unless up(u) then Between
        end
      every r

(* a linear filter *)
let hybrid filter(n)(k, u) = udot where
   rec udot = n *. (u -. f)
   and f = int (k, 0.0, udot)