within Modelica.Blocks;
package Discrete
  "Library of discrete input/output blocks with fixed sample period"

  extends Modelica.Icons.Package;

  block Sampler "Ideal sampling of continuous signals"
    extends Interfaces.DiscreteSISO(y(start=0, fixed=true));

  equation
    when {sampleTrigger, initial()} then
      y = if time>=startTime then u else pre(y);
    end when;
  end Sampler;

  block ZeroOrderHold "Zero order hold of a sampled-data system"
    extends Interfaces.DiscreteSISO;
    output Real ySample(start=0, fixed=true);

  equation
    when {sampleTrigger, initial()} then
      ySample = if time>=startTime then u else pre(ySample);
    end when;
    /* Define y=ySample with an infinitesimal delay to break potential
       algebraic loops if both the continuous and the discrete part have
       direct feedthrough
    */
    y = pre(ySample);
  end ZeroOrderHold;

  block FirstOrderHold "First order hold of a sampled-data system"
    extends Modelica.Blocks.Interfaces.DiscreteSISO;
  protected
    SI.Time tSample;
    Real uSample;
    Real pre_uSample;
    Real c;
  initial equation
    pre(tSample) = time;
    pre(uSample) = u;
    pre(pre_uSample) = u;
    pre(c) = 0.0;
  equation
    when sampleTrigger then
      tSample = time;
      uSample = u;
      pre_uSample = pre(uSample);
      c = if firstTrigger then 0 else (uSample - pre_uSample)/samplePeriod;
    end when;
    /* Use pre_uSample and pre(c) to break potential algebraic loops by an
       infinitesimal delay if both the continuous and the discrete part
       have direct feedthrough.
    */
    y = pre_uSample + pre(c)*(time - tSample);
  end FirstOrderHold;

  block UnitDelay "Unit Delay Block"
    parameter Real y_start=0 "Initial value of output signal";
    extends Interfaces.DiscreteSISO;

  equation
    when sampleTrigger then
      y = pre(u);
    end when;

  initial equation
      y = y_start;
  end UnitDelay;

  block TransferFunction "Discrete Transfer Function block"
    parameter Real b[:]={1} "Numerator coefficients of transfer function.";
    parameter Real a[:]={1} "Denominator coefficients of transfer function.";
    extends Interfaces.DiscreteSISO;
    output Real x[size(a, 1) - 1](each start=0, each fixed=true)
      "State of transfer function from controller canonical form";
  protected
    parameter Integer nb=size(b, 1) "Size of Numerator of transfer function";
    parameter Integer na=size(a, 1) "Size of Denominator of transfer function";
    Real x1(start=0,fixed=true);
    Real xext[size(a, 1)](each start=0, each fixed=true);

  equation
    when sampleTrigger then
      /* State variables x are defined according to
       controller canonical form. */
      x1 = (u - a[2:size(a, 1)]*pre(x))/a[1];
      xext = vector([x1; pre(x)]);
      x = xext[1:size(x, 1)];
      y = vector([zeros(na - nb, 1); b])*xext;
    end when;
    /* This is a non-sampled equation and above there are two separate
       when-clauses. This breaks feedback loops without direct terms,
       since in that case y will be independent of x1 (and only dependent
       on pre(x)).
    */
    /* Corresponding (simpler) version using when-semantics of Modelica 1.3:
   equation
     when sampleTrigger then
      [x; xn] = [x1; pre(x)];
      [u] = transpose([a])*[x1; pre(x)];
      [y] = transpose([zeros(na - nb, 1); b])*[x1; pre(x)];
     end when;
*/

results in the following transfer function:

     2*z + 4
y = --------- * u
      z + 3

", revisions="

Release Notes:

November 15, 2000
    by Hans Olsson:

    Converted to when-semantics of Modelica 1.4 with special
    care to avoid unnecessary algebraic loops.

June 18, 2000
    by Martin Otter:

    Realized based on a corresponding model of Dieter Moormann
    and Hilding Elmqvist.

"),
      Icon(
      coordinateSystem(preserveAspectRatio=true,
        extent={{-100.0,-100.0},{100.0,100.0}}),
        graphics={
      Line(points={{82.0,0.0},{-84.0,0.0}},
        color={0,0,127}),
      Text(textColor={0,0,127},
        extent={{-92.0,12.0},{86.0,92.0}},
        textString="b(z)"),
      Text(textColor={0,0,127},
        extent={{-90.0,-90.0},{90.0,-12.0}},
        textString="a(z)")}));
  end TransferFunction;

  block StateSpace "Discrete State Space block"
    parameter Real A[:, size(A, 1)]=[1, 0; 0, 1]
      "Matrix A of state space model";
    parameter Real B[size(A, 1), :]=[1; 1] "Matrix B of state space model";
    parameter Real C[:, size(A, 1)]=[1, 1] "Matrix C of state space model";
    parameter Real D[size(C, 1), size(B, 2)]=zeros(size(C, 1), size(B, 2))
      "Matrix D of state space model";

    extends Interfaces.DiscreteMIMO(final nin=size(B, 2), final nout=size(C, 1));
    output Real x[size(A, 1)] "State vector";

  equation
    when sampleTrigger then
      x = A*pre(x) + B*u;
      y = C*pre(x) + D*u;
    end when;
  end StateSpace;

  block TriggeredSampler "Triggered sampling of continuous signals"
    extends Modelica.Blocks.Icons.DiscreteBlock;
    parameter Real y_start=0 "Initial value of output signal";

    Modelica.Blocks.Interfaces.RealInput u "Connector with a Real input signal"
    Modelica.Blocks.Interfaces.RealOutput y
      "Connector with a Real output signal"
    Modelica.Blocks.Interfaces.BooleanInput trigger "Trigger input"
  equation
    when trigger then
      y = u;
    end when;
  initial equation
    y = y_start;
  end TriggeredSampler;

  block TriggeredMax
    "Compute maximum, absolute value of continuous signal at trigger instants"

    extends Modelica.Blocks.Icons.DiscreteBlock;
    Modelica.Blocks.Interfaces.RealInput u "Connector with a Real input signal"
    Modelica.Blocks.Interfaces.RealOutput y
      "Connector with a Real output signal"
    Modelica.Blocks.Interfaces.BooleanInput trigger
  equation
    when trigger then
       y = max(pre(y), abs(u));
    end when;
  initial equation
    y = 0;
  end TriggeredMax;
end Discrete;


within Modelica.Blocks;
package Interaction
  "Library of user interaction blocks to input and to show variables in a diagram animation"
  extends Modelica.Icons.Package;

  package Show "Library of blocks to show variables in a diagram animation"
    extends Modelica.Icons.Package;

    block RealValue
      "Show Real value from numberPort or from number input field in diagram layer dynamically"
      parameter Boolean use_numberPort = true "= true, if numberPort enabled"
      input Real number = 0.0
        "Number to visualize if use_numberPort=false (time varying)"
      parameter Integer significantDigits(min=1) = 2
        "Number of significant digits to be shown";

      Modelica.Blocks.Interfaces.RealInput numberPort if use_numberPort
        "Number to be shown in diagram layer if use_numberPort = true"
       Modelica.Blocks.Interfaces.RealOutput showNumber;
    equation
      if use_numberPort then
         connect(numberPort, showNumber);
      else
         showNumber = number;
      end if;
    end RealValue;

    block IntegerValue
      "Show Integer value from numberPort or from number input field in diagram layer dynamically"
      parameter Boolean use_numberPort = true "= true, if numberPort enabled"
      input Integer number=0
        "Number to visualize if use_numberPort=false (time varying)"
      Modelica.Blocks.Interfaces.IntegerInput numberPort if use_numberPort
        "Number to be shown in diagram layer if use_numberPort = true"
       Modelica.Blocks.Interfaces.IntegerOutput showNumber;
    equation
      if use_numberPort then
         connect(numberPort, showNumber);
      else
         showNumber = number;
      end if;
    end IntegerValue;

    block BooleanValue
      "Show Boolean value from numberPort or from number input field in diagram layer dynamically"
      parameter Boolean use_activePort = true "= true, if activePort enabled"
      input Boolean active=false
        "Boolean variable to visualize if use_activePort=false (time varying)"
      Modelica.Blocks.Interfaces.BooleanInput activePort if use_activePort
        "Boolean variable to be shown in diagram layer if use_activePort = true"

       Modelica.Blocks.Interfaces.BooleanOutput showActive;
    equation
      if use_activePort then
         connect(activePort, showActive);
      else
         showActive = active;
      end if;
    end BooleanValue;
  end Show;
end Interaction;


within Modelica.Blocks;
package Interfaces
  "Library of connectors and partial models for input/output blocks"

  extends Modelica.Icons.InterfacesPackage;

  connector RealInput = input Real "'input Real' as connector"

  connector RealOutput = output Real "'output Real' as connector"

  connector BooleanInput = input Boolean "'input Boolean' as connector"

  connector BooleanOutput = output Boolean "'output Boolean' as connector"

  connector IntegerInput = input Integer "'input Integer' as connector"

  connector IntegerOutput = output Integer "'output Integer' as connector"

  connector RealVectorInput = input Real
    "Real input connector used for vector of connectors"

  connector IntegerVectorInput = input Integer
    "Integer input connector used for vector of connectors"

  connector BooleanVectorInput = input Boolean
    "Boolean input connector used for vector of connectors"

  connector RealVectorOutput = output Real
    "Real output connector used for vector of connectors"

  partial block SO "Single Output continuous control block"
    extends Modelica.Blocks.Icons.Block;

    RealOutput y "Connector of Real output signal"

  end SO;

  partial block MO "Multiple Output continuous control block"
    extends Modelica.Blocks.Icons.Block;

    parameter Integer nout(min=1) = 1 "Number of outputs";
    RealOutput y[nout] "Connector of Real output signals"

  end MO;

  partial block SISO "Single Input Single Output continuous control block"
    extends Modelica.Blocks.Icons.Block;

    RealInput u "Connector of Real input signal"
    RealOutput y "Connector of Real output signal"
  end SISO;

  partial block SI2SO
    "2 Single Input / 1 Single Output continuous control block"
    extends Modelica.Blocks.Icons.Block;

    RealInput u1 "Connector of Real input signal 1"
    RealInput u2 "Connector of Real input signal 2"
    RealOutput y "Connector of Real output signal"

  end SI2SO;

  partial block SIMO "Single Input Multiple Output continuous control block"
    extends Modelica.Blocks.Icons.Block;
    parameter Integer nout=1 "Number of outputs";
    RealInput u "Connector of Real input signal"
    RealOutput y[nout] "Connector of Real output signals"
  end SIMO;

  partial block MISO "Multiple Input Single Output continuous control block"

    extends Modelica.Blocks.Icons.Block;
    parameter Integer nin=1 "Number of inputs";
    RealInput u[nin] "Connector of Real input signals"
    RealOutput y "Connector of Real output signal"
  end MISO;

  partial block PartialRealMISO
    "Partial block with a RealVectorInput and a RealOutput signal"

    parameter Integer significantDigits(min=1) = 3
      "Number of significant digits to be shown in dynamic diagram layer for y"
    parameter Integer nu(min=0) = 0 "Number of input connections"
    Modelica.Blocks.Interfaces.RealVectorInput u[nu]
    Modelica.Blocks.Interfaces.RealOutput y
  end PartialRealMISO;

  partial block MIMO "Multiple Input Multiple Output continuous control block"

    extends Modelica.Blocks.Icons.Block;
    parameter Integer nin=1 "Number of inputs";
    parameter Integer nout=1 "Number of outputs";
    RealInput u[nin] "Connector of Real input signals"
    RealOutput y[nout] "Connector of Real output signals"
  end MIMO;

  partial block MIMOs
    "Multiple Input Multiple Output continuous control block with same number of inputs and outputs"

    extends Modelica.Blocks.Icons.Block;
    parameter Integer n=1 "Number of inputs (= number of outputs)";
    RealInput u[n] "Connector of Real input signals"
    RealOutput y[n] "Connector of Real output signals"
  end MIMOs;

  partial block MI2MO
    "2 Multiple Input / Multiple Output continuous control block"
    extends Modelica.Blocks.Icons.Block;

    parameter Integer n=1 "Dimension of input and output vectors.";

    RealInput u1[n] "Connector 1 of Real input signals"
    RealInput u2[n] "Connector 2 of Real input signals"
    RealOutput y[n] "Connector of Real output signals"

  end MI2MO;

  partial block SignalSource "Base class for continuous signal source"
    extends SO;
    parameter Real offset=0 "Offset of output signal y";
    parameter SI.Time startTime=0 "Output y = offset for time < startTime";
  end SignalSource;

  partial block SVcontrol "Single-Variable continuous controller"
    extends Modelica.Blocks.Icons.Block;

    RealInput u_s "Connector of setpoint input signal"
    RealInput u_m "Connector of measurement input signal"
    RealOutput y "Connector of actuator output signal"
  end SVcontrol;

  partial block MVcontrol "Multi-Variable continuous controller"
    extends Modelica.Blocks.Icons.Block;

    parameter Integer nu_s=1 "Number of setpoint inputs";
    parameter Integer nu_m=1 "Number of measurement inputs";
    parameter Integer ny=1 "Number of actuator outputs";
    RealInput u_s[nu_s] "Connector of setpoint input signals"
    RealInput u_m[nu_m] "Connector of measurement input signals"
    RealOutput y[ny] "Connector of actuator output signals"
  end MVcontrol;

  partial block DiscreteBlock "Base class of discrete control blocks"
    extends Modelica.Blocks.Icons.DiscreteBlock;

    parameter SI.Time samplePeriod(min=100*Modelica.Constants.eps, start=0.1)
      "Sample period of component";
    parameter SI.Time startTime=0 "First sample time instant";
  protected
    output Boolean sampleTrigger "True, if sample time instant";
    output Boolean firstTrigger(start=false, fixed=true)
      "Rising edge signals first sample instant";
  equation
    sampleTrigger = sample(startTime, samplePeriod);
    when sampleTrigger then
      firstTrigger = time <= startTime + samplePeriod/2;
    end when;
  end DiscreteBlock;

  partial block DiscreteSISO
    "Single Input Single Output discrete control block"

    extends DiscreteBlock;

    Modelica.Blocks.Interfaces.RealInput u "Connector of Real input signal"
    Modelica.Blocks.Interfaces.RealOutput y "Connector of Real output signal"
  end DiscreteSISO;

  partial block DiscreteMIMO
    "Multiple Input Multiple Output discrete control block"

    extends DiscreteBlock;
    parameter Integer nin=1 "Number of inputs";
    parameter Integer nout=1 "Number of outputs";

    Modelica.Blocks.Interfaces.RealInput u[nin] "Connector of Real input signals"
    Modelica.Blocks.Interfaces.RealOutput y[nout] "Connector of Real output signals"
  end DiscreteMIMO;

  partial block DiscreteMIMOs
    "Multiple Input Multiple Output discrete control block"
    parameter Integer n=1 "Number of inputs (= number of outputs)";
    extends DiscreteBlock;

    Modelica.Blocks.Interfaces.RealInput u[n] "Connector of Real input signals"
    Modelica.Blocks.Interfaces.RealOutput y[n] "Connector of Real output signals"

  end DiscreteMIMOs;

  partial block SVdiscrete "Discrete Single-Variable controller"
    extends DiscreteBlock;

    Discrete.Sampler sampler_s(final samplePeriod=samplePeriod, final startTime=
         startTime)
    Discrete.Sampler sampler_m(final samplePeriod=samplePeriod, final startTime=
         startTime)
    Modelica.Blocks.Interfaces.RealInput u_s
      "Scalar setpoint input signal"
    Modelica.Blocks.Interfaces.RealInput u_m
      "Scalar measurement input signal"
    Modelica.Blocks.Interfaces.RealOutput y
      "Scalar actuator output signal"
  equation
    connect(u_s, sampler_s.u)
    connect(u_m, sampler_m.u)
  end SVdiscrete;

  partial block MVdiscrete "Discrete Multi-Variable controller"
    extends DiscreteBlock;
    parameter Integer nu_s=1 "Number of setpoint inputs";
    parameter Integer nu_m=1 "Number of measurement inputs";
    parameter Integer ny=1 "Number of actuator outputs";
    Discrete.Sampler sampler_s[nu_s](each final samplePeriod=samplePeriod,
        each final startTime=startTime)
    Discrete.Sampler sampler_m[nu_m](each final samplePeriod=samplePeriod,
        each final startTime=startTime)
    Modelica.Blocks.Interfaces.RealInput u_s[nu_s]
      "Setpoint input signals"
    Modelica.Blocks.Interfaces.RealInput u_m[nu_m]
      "Measurement input signals"
    Modelica.Blocks.Interfaces.RealOutput y[ny]
      "Actuator output signals"
  equation
    connect(u_s, sampler_s.u)
    connect(u_m, sampler_m.u)
  end MVdiscrete;

  partial block BooleanSISO
    "Single Input Single Output control block with signals of type Boolean"

    extends Modelica.Blocks.Icons.BooleanBlock;

  public
    BooleanInput u "Connector of Boolean input signal"
    BooleanOutput y "Connector of Boolean output signal"
  end BooleanSISO;

  partial block BooleanMIMOs
    "Multiple Input Multiple Output continuous control block with same number of inputs and outputs of Boolean type"

    extends Modelica.Blocks.Icons.BooleanBlock;
    parameter Integer n=1 "Number of inputs (= number of outputs)";
    BooleanInput u[n] "Connector of Boolean input signals"
    BooleanOutput y[n] "Connector of Boolean output signals"
  end BooleanMIMOs;

  partial block MI2BooleanMOs
    "2 Multiple Input / Boolean Multiple Output block with same signal lengths"

    extends Modelica.Blocks.Icons.BooleanBlock;
    parameter Integer n=1 "Dimension of input and output vectors.";
    RealInput u1[n] "Connector 1 of Boolean input signals"
    RealInput u2[n] "Connector 2 of Boolean input signals"
    BooleanOutput y[n] "Connector of Boolean output signals"
  end MI2BooleanMOs;

  partial block SI2BooleanSO "2 Single Input / Boolean Single Output block"

    extends Modelica.Blocks.Icons.BooleanBlock;
    BooleanInput u1 "Connector 1 of Boolean input signals"
    BooleanInput u2 "Connector 2 of Boolean input signals"
    BooleanOutput y "Connector of Boolean output signals"

  end SI2BooleanSO;

  partial block BooleanSignalSource "Base class for Boolean signal sources"

    extends Modelica.Blocks.Icons.BooleanBlock;
    BooleanOutput y "Connector of Boolean output signal"

  end BooleanSignalSource;

  partial block IntegerSO "Single Integer Output continuous control block"
    extends Modelica.Blocks.Icons.IntegerBlock;

    IntegerOutput y "Connector of Integer output signal"
  end IntegerSO;

  partial block IntegerMO "Multiple Integer Output continuous control block"
    extends Modelica.Blocks.Icons.IntegerBlock;

    parameter Integer nout(min=1) = 1 "Number of outputs";
    IntegerOutput y[nout] "Connector of Integer output signals"
  end IntegerMO;

  partial block IntegerSignalSource
    "Base class for continuous Integer signal source"
    extends IntegerSO;
    parameter Integer offset=0 "Offset of output signal y";
    parameter SI.Time startTime=0 "Output y = offset for time < startTime";
  end IntegerSignalSource;

  partial block IntegerSIBooleanSO
    "Integer Input Boolean Output continuous control block"

    extends Modelica.Blocks.Icons.BooleanBlock;
    IntegerInput u "Connector of Integer input signal"
    BooleanOutput y "Connector of Boolean output signal"
  end IntegerSIBooleanSO;

  partial block IntegerMIBooleanMOs
    "Multiple Integer Input Multiple Boolean Output continuous control block with same number of inputs and outputs"

    extends Modelica.Blocks.Icons.BooleanBlock;
    parameter Integer n=1 "Number of inputs (= number of outputs)";
    IntegerInput u[n] "Connector of Integer input signals"
    BooleanOutput y[n] "Connector of Boolean output signals"
  end IntegerMIBooleanMOs;

  partial block PartialIntegerSISO
    "Partial block with a IntegerInput and an IntegerOutput signal"

    Modelica.Blocks.Interfaces.IntegerInput u "Integer input signal"
    Modelica.Blocks.Interfaces.IntegerOutput y "Integer output signal"
  end PartialIntegerSISO;

  partial block PartialIntegerMISO
    "Partial block with an IntegerVectorInput and an IntegerOutput signal"

    parameter Integer nu(min=0) = 0 "Number of input connections"
    Modelica.Blocks.Interfaces.IntegerVectorInput u[nu]
      "Vector of Integer input signals"
    Modelica.Blocks.Interfaces.IntegerOutput y "Integer output signal"
  end PartialIntegerMISO;

  partial block partialBooleanSISO
    "Partial block with 1 input and 1 output Boolean signal"
    extends Modelica.Blocks.Icons.PartialBooleanBlock;
    Blocks.Interfaces.BooleanInput u "Connector of Boolean input signal"
    Blocks.Interfaces.BooleanOutput y "Connector of Boolean output signal"

  end partialBooleanSISO;

  partial block partialBooleanSI2SO
    "Partial block with 2 input and 1 output Boolean signal"
    extends Modelica.Blocks.Icons.PartialBooleanBlock;
    Blocks.Interfaces.BooleanInput u1 "Connector of first Boolean input signal"
    Blocks.Interfaces.BooleanInput u2
      "Connector of second Boolean input signal"
    Blocks.Interfaces.BooleanOutput y "Connector of Boolean output signal"

  end partialBooleanSI2SO;

  partial block partialBooleanSI3SO
    "Partial block with 3 input and 1 output Boolean signal"
    extends Modelica.Blocks.Icons.PartialBooleanBlock;
    Blocks.Interfaces.BooleanInput u1 "Connector of first Boolean input signal"
    Blocks.Interfaces.BooleanInput u2
      "Connector of second Boolean input signal"
    Blocks.Interfaces.BooleanInput u3 "Connector of third Boolean input signal"
    Blocks.Interfaces.BooleanOutput y "Connector of Boolean output signal"

  end partialBooleanSI3SO;

  partial block partialBooleanSI "Partial block with 1 input Boolean signal"
    extends Modelica.Blocks.Icons.PartialBooleanBlock;

    Blocks.Interfaces.BooleanInput u "Connector of Boolean input signal"

  end partialBooleanSI;

  partial block partialBooleanSO "Partial block with 1 output Boolean signal"

    Blocks.Interfaces.BooleanOutput y "Connector of Boolean output signal"
    extends Modelica.Blocks.Icons.PartialBooleanBlock;

  end partialBooleanSO;

  partial block partialBooleanSource
    "Partial source block (has 1 output Boolean signal and an appropriate default icon)"
    extends Modelica.Blocks.Icons.PartialBooleanBlock;

    Blocks.Interfaces.BooleanOutput y "Connector of Boolean output signal"

  end partialBooleanSource;

  partial block partialBooleanThresholdComparison
    "Partial block to compare the Real input u with a threshold and provide the result as 1 Boolean output signal"

    parameter Real threshold=0 "Comparison with respect to threshold";

    Blocks.Interfaces.RealInput u "Connector of Real input signal"
    Blocks.Interfaces.BooleanOutput y "Connector of Boolean output signal"

  end partialBooleanThresholdComparison;

  partial block partialBooleanComparison
    "Partial block with 2 Real input and 1 Boolean output signal (the result of a comparison of the two Real inputs)"

    Blocks.Interfaces.RealInput u1 "Connector of first Real input signal"
    Blocks.Interfaces.RealInput u2 "Connector of second Real input signal"
    Blocks.Interfaces.BooleanOutput y "Connector of Boolean output signal"

  end partialBooleanComparison;

  partial block PartialBooleanSISO_small
    "Partial block with a BooleanInput and a BooleanOutput signal and a small block icon"

    Modelica.Blocks.Interfaces.BooleanInput u "Boolean input signal"
    Modelica.Blocks.Interfaces.BooleanOutput y "Boolean output signal"
  end PartialBooleanSISO_small;

  partial block PartialBooleanMISO
    "Partial block with a BooleanVectorInput and a BooleanOutput signal"

    parameter Integer nu(min=0) = 0 "Number of input connections"
    Modelica.Blocks.Interfaces.BooleanVectorInput u[nu]
      "Vector of Boolean input signals"
    Modelica.Blocks.Interfaces.BooleanOutput y "Boolean output signal"
  end PartialBooleanMISO;

  partial block PartialConversionBlock
    "Partial block defining the interface for conversion blocks"

    RealInput u "Connector of Real input signal to be converted"
    RealOutput y
      "Connector of Real output signal containing input signal u in another unit"

  end PartialConversionBlock;

  partial block PartialNoise "Partial noise generator"
    import generator = Modelica.Math.Random.Generators.Xorshift128plus;
    import Modelica.Math.Random.Utilities.automaticLocalSeed;
    extends Modelica.Blocks.Interfaces.SO;

    // Main dialog menu
    parameter SI.Period samplePeriod(start=0.01)
      "Period for sampling the raw random numbers"

    // Advanced dialog menu: Noise generation
    parameter Boolean enableNoise = globalSeed.enableNoise
      "= true: y = noise, otherwise y = y_off"
    parameter Real y_off = 0.0
      "Sets y = y_off if enableNoise=false (or time<startTime, see below)"

    // Advanced dialog menu: Initialization
    parameter Boolean useGlobalSeed = true
      "= true: use global seed, otherwise ignore it"
    parameter Boolean useAutomaticLocalSeed = true
      "= true: use automatic local seed, otherwise use fixedLocalSeed"
    parameter Integer fixedLocalSeed = 1 "Local seed (any Integer number)"
    parameter SI.Time startTime = 0.0
      "Start time for sampling the raw random numbers"
    final parameter Integer localSeed(fixed=false) "The actual localSeed";
  protected
    outer Modelica.Blocks.Noise.GlobalSeed globalSeed
      "Definition of global seed via inner/outer";
    parameter Integer actualGlobalSeed = if useGlobalSeed then globalSeed.seed else 0
      "The global seed, which is actually used";
    parameter Boolean generateNoise = enableNoise and globalSeed.enableNoise
      "= true, if noise shall be generated, otherwise no noise";

    // Declare state and random number variables
    Integer state[generator.nState] "Internal state of random number generator";
    discrete Real r "Random number according to the desired distribution";
    discrete Real r_raw "Uniform random number in the range (0,1]";

  initial equation
     localSeed = if useAutomaticLocalSeed then automaticLocalSeed(getInstanceName()) else fixedLocalSeed;
     pre(state) = generator.initialState(localSeed, actualGlobalSeed);
     r_raw = generator.random(pre(state));

  equation
    // Draw random number at sample times
    when generateNoise and sample(startTime, samplePeriod) then
      (r_raw, state) = generator.random(pre(state));
    end when;

    // Generate noise if requested
    y = if not generateNoise or time < startTime then y_off else r;
  end PartialNoise;

  package Adaptors "Package with adaptors (especially useful for FMUs)"
    extends Modelica.Icons.InterfacesPackage;

    partial model FlowToPotentialAdaptor "Signal adaptor for a connector with flow, 1st derivative of flow, and 2nd derivative of flow as inputs and
  potential, 1st derivative of potential, and 2nd derivative of potential as outputs (especially useful for FMUs)"
      parameter Boolean use_pder=true "Use output for 1st derivative of potential"
      parameter Boolean use_pder2=true "Use output for 2nd derivative of potential (only if 1st derivative is used, too)"
      parameter Boolean use_fder=true "Use input for 1st derivative of flow"
      parameter Boolean use_fder2=true "Use input for 2nd derivative of flow (only if 1st derivative is used, too)"
      Modelica.Blocks.Interfaces.RealOutput p "Output for potential"
      Modelica.Blocks.Interfaces.RealOutput pder if use_pder
        "Optional output for der(potential)"
      Modelica.Blocks.Interfaces.RealOutput pder2 if (use_pder and use_pder2)
        "Optional output for der2(potential)"
      Modelica.Blocks.Interfaces.RealInput f "Input for flow"
      Modelica.Blocks.Interfaces.RealInput fder if use_fder
        "Optional input for der(flow)"
      Modelica.Blocks.Interfaces.RealInput fder2 if (use_fder and use_fder2)
        "Optional input for der2(flow)"
    protected
      parameter String Name_p="p" "Name of potential variable";
      parameter String Name_pder="der(p)" "Name of 1st derivative of potential variable";
      parameter String Name_pder2="der2(p)" "Name of 2nd derivative of potential variable";
      parameter String Name_f="f" "Name of flow variable";
      parameter String Name_fder="der(f)" "Name of 1st derivative of flow variable";
      parameter String Name_fder2="der2(f)" "Name of 2nd derivative of flow variable";
      Real y "Output signal"
      Modelica.Blocks.Interfaces.RealOutput y1 "Optional 1st derivative of output"
      Modelica.Blocks.Interfaces.RealOutput y2 "Optional 2nd derivative of output"
      Real u "Input signal"
      Modelica.Blocks.Interfaces.RealInput u1 "Optional 1st derivative of input"
      Modelica.Blocks.Interfaces.RealInput u2 "Optional 2nd derivative of input"
    equation
      y = p;
      y1 = if use_pder then der(y) else 0;
      y2 = if (use_pder and use_pder2) then der(y1) else 0;
      connect(y1, pder);
      connect(y2, pder2);
      if use_fder then
        connect(fder, u1);
      else
        u1 = 0;
      end if;
      if (use_fder and use_fder2) then
        connect(fder2, u2);
      else
        u2 = 0;
      end if;
      if (use_fder and use_fder2) then
        u = Functions.state2({f, u1, u2}, time);
      elseif (use_fder and not use_fder2) then
        u = Functions.state1({f, u1}, time);
      else
        u = f;
      end if;
    end FlowToPotentialAdaptor;

    partial model PotentialToFlowAdaptor "Signal adaptor for a connector with potential, 1st derivative of potential, and 2nd derivative of potential as inputs and
  flow, 1st derivative of flow, and 2nd derivative of flow as outputs (especially useful for FMUs)"
      parameter Boolean use_pder=true "Use input for 1st derivative of potential"
      parameter Boolean use_pder2=true "Use input for 2nd derivative of potential (only if 1st derivative is used, too)"
      parameter Boolean use_fder=true "Use output for 1st derivative of flow"
      parameter Boolean use_fder2=true "Use output for 2nd derivative of flow (only if 1st derivative is used, too)"
      Modelica.Blocks.Interfaces.RealInput p "Input for potential"
      Modelica.Blocks.Interfaces.RealInput pder if use_pder
        "Optional input for der(potential)"
      Modelica.Blocks.Interfaces.RealInput pder2 if (use_pder and use_pder2)
        "Optional input for der2(potential)"
      Modelica.Blocks.Interfaces.RealOutput f "Output for flow"
      Modelica.Blocks.Interfaces.RealOutput fder if use_fder
        "Optional output for der(flow)"
      Modelica.Blocks.Interfaces.RealOutput fder2 if (use_fder and use_fder2)
        "Optional output for der2(flow)"
    protected
      parameter String Name_p="p" "Name of potential variable";
      parameter String Name_pder="der(p)" "Name of 1st derivative of potential variable";
      parameter String Name_pder2="der2(p)" "Name of 2nd derivative of potential variable";
      parameter String Name_f="f" "Name of flow variable";
      parameter String Name_fder="der(f)" "Name of 1st derivative of flow variable";
      parameter String Name_fder2="der2(f)" "Name of 2nd derivative of flow variable";
      Real y "Output signal"
      Modelica.Blocks.Interfaces.RealOutput y1 "Optional 1st derivative of output"
      Modelica.Blocks.Interfaces.RealOutput y2 "Optional 2nd derivative of output"
      Real u "Input signal"
      Modelica.Blocks.Interfaces.RealInput u1 "Optional 1st derivative of input"
      Modelica.Blocks.Interfaces.RealInput u2 "Optional 2nd derivative of input"
    equation
      y = -f;
      y1 = if use_fder then -der(y) else 0;
      y2 = if (use_fder and use_fder2) then -der(y1) else 0;
      connect(y1, fder);
      connect(y2, fder2);
      if use_pder then
        connect(pder, u1);
      else
        u1 = 0;
      end if;
      if (use_pder and use_pder2) then
        connect(pder2, u2);
      else
        u2 = 0;
      end if;
      if (use_pder and use_pder2) then
        u = Functions.state2({p, u1, u2}, time);
      elseif (use_pder and not use_pder2) then
        u = Functions.state1({p, u1}, time);
      else
        u = p;
      end if;
    end PotentialToFlowAdaptor;

    package Functions "Functions for adaptors"
      extends Modelica.Icons.FunctionsPackage;

      function state1 "Return state (with one derivative)"
        extends Modelica.Icons.Function;
        input Real u[2] "Required values for state and der(s)";
        input Real dummy
          "Just to have one input signal that should be differentiated to avoid possible problems in the Modelica tool (is not used)";
        output Real s;
      algorithm
        s := u[1];
      end state1;

      function state1der1 "Return 1st derivative (der of state1)"
        extends Modelica.Icons.Function;
        input Real u[2] "Required values for state and der(s)";
        input Real dummy
          "Just to have one input signal that should be differentiated to avoid possible problems in the Modelica tool (is not used)";
        input Real dummy_der;
        output Real sder1;
      algorithm
        sder1 := u[2];
      end state1der1;

      function state2 "Return state (with two derivatives)"
        extends Modelica.Icons.Function;
        input Real u[3] "Required values for state and der(s)";
        input Real dummy
          "Just to have one input signal that should be differentiated to avoid possible problems in the Modelica tool (is not used)";
        output Real s;
      algorithm
        s := u[1];
      end state2;

      function state2der1 "Return 1st derivative (der of state2)"
        extends Modelica.Icons.Function;
        input Real u[3] "Required values for state and der(s)";
        input Real dummy
          "Just to have one input signal that should be differentiated to avoid possible problems in the Modelica tool (is not used)";
        input Real dummy_der;
        output Real sder1;
      algorithm
        sder1 := u[2];
      end state2der1;

      function state2der2 "Return 2nd derivative (der of state2der1)"
        extends Modelica.Icons.Function;
        input Real u[3] "Required values for state and der(s)";
        input Real dummy
          "Just to have one input signal that should be differentiated to avoid possible problems in the Modelica tool (is not used)";
        input Real dummy_der;
        input Real dummy_der2;
        output Real sder2;
      algorithm
        sder2 := u[3];
      end state2der2;
    end Functions;
  end Adaptors;
end Interfaces;


within Modelica.Blocks;
package Logical "Library of components with Boolean input and output signals"
  extends Modelica.Icons.Package;

  block And "Logical 'and': y = u1 and u2"
    extends Blocks.Interfaces.partialBooleanSI2SO;
  equation
    y = u1 and u2;
  end And;

  block Or "Logical 'or': y = u1 or u2"
    extends Blocks.Interfaces.partialBooleanSI2SO;
  equation
    y = u1 or u2;
  end Or;

  block Xor "Logical 'xor': y = u1 xor u2"
    extends Blocks.Interfaces.partialBooleanSI2SO;
  equation
    y = not ((u1 and u2) or (not u1 and not u2));
  end Xor;

  block Nor "Logical 'nor': y = not (u1 or u2)"
    extends Blocks.Interfaces.partialBooleanSI2SO;
  equation
    y = not (u1 or u2);
  end Nor;

  block Nand "Logical 'nand': y = not (u1 and u2)"
    extends Blocks.Interfaces.partialBooleanSI2SO;
  equation
    y = not (u1 and u2);
  end Nand;

  block Not "Logical 'not': y = not u"
    extends Blocks.Interfaces.partialBooleanSISO;

  equation
    y = not u;
  end Not;

  block Pre
    "Breaks algebraic loops by an infinitesimal small time delay (y = pre(u): event iteration continues until u = pre(u))"

    parameter Boolean pre_u_start=false "Start value of pre(u) at initial time";
    extends Blocks.Interfaces.partialBooleanSISO;

  initial equation
    pre(u) = pre_u_start;
  equation
    y = pre(u);
  end Pre;

  block Edge "Output y is true, if the input u has a rising edge (y = edge(u))"

    parameter Boolean pre_u_start=false "Start value of pre(u) at initial time";
    extends Blocks.Interfaces.partialBooleanSISO;

  initial equation
    pre(u) = pre_u_start;
  equation
    y = edge(u);
  end Edge;

  block FallingEdge
    "Output y is true, if the input u has a falling edge (y = edge(not u))"

    parameter Boolean pre_u_start=false "Start value of pre(u) at initial time";
    extends Blocks.Interfaces.partialBooleanSISO;

  protected
    Boolean not_u=not u;
  initial equation
    pre(not_u) = not pre_u_start;
  equation
    y = edge(not_u);
  end FallingEdge;

  block Change
    "Output y is true, if the input u has a rising or falling edge (y = change(u))"

    parameter Boolean pre_u_start=false "Start value of pre(u) at initial time";
    extends Blocks.Interfaces.partialBooleanSISO;

  initial equation
    pre(u) = pre_u_start;
  equation
    y = change(u);
  end Change;

  block GreaterThreshold
    "Output y is true, if input u is greater than threshold"
    extends Blocks.Interfaces.partialBooleanThresholdComparison;
  equation
    y = u > threshold;
  end GreaterThreshold;

  block GreaterEqualThreshold
    "Output y is true, if input u is greater or equal than threshold"

    extends Blocks.Interfaces.partialBooleanThresholdComparison;
  equation
    y = u >= threshold;
  end GreaterEqualThreshold;

  block LessThreshold "Output y is true, if input u is less than threshold"

    extends Blocks.Interfaces.partialBooleanThresholdComparison;
  equation
    y = u < threshold;
  end LessThreshold;

  block LessEqualThreshold
    "Output y is true, if input u is less or equal than threshold"
    extends Blocks.Interfaces.partialBooleanThresholdComparison;
  equation
    y = u <= threshold;
  end LessEqualThreshold;

  block Greater "Output y is true, if input u1 is greater than input u2"
    extends Blocks.Interfaces.partialBooleanComparison;

  equation
    y = u1 > u2;
  end Greater;

  block GreaterEqual
    "Output y is true, if input u1 is greater or equal than input u2"
    extends Blocks.Interfaces.partialBooleanComparison;

  equation
    y = u1 >= u2;
  end GreaterEqual;

  block Less "Output y is true, if input u1 is less than input u2"
    extends Blocks.Interfaces.partialBooleanComparison;

  equation
    y = u1 < u2;
  end Less;

  block LessEqual "Output y is true, if input u1 is less or equal than input u2"
    extends Blocks.Interfaces.partialBooleanComparison;

  equation
    y = u1 <= u2;
  end LessEqual;

  block ZeroCrossing "Trigger zero crossing of input u"
    extends Blocks.Interfaces.partialBooleanSO;
    Blocks.Interfaces.RealInput u
    Blocks.Interfaces.BooleanInput enable
      "Zero input crossing is triggered if the enable input signal is true"

  protected
    Boolean disable=not enable;
    Boolean u_pos;
  initial equation
    pre(u_pos) = false;
    pre(enable) = false;
    pre(disable) = not pre(enable);
  equation
    u_pos = enable and u >= 0;
    y = change(u_pos) and not edge(enable) and not edge(disable);
  end ZeroCrossing;

  block LogicalSwitch "Logical Switch"
    extends Blocks.Interfaces.partialBooleanSI3SO;

  equation
    y = if u2 then u1 else u3;
  end LogicalSwitch;

  block Switch "Switch between two Real signals"
    extends Modelica.Blocks.Icons.PartialBooleanBlock;
    Blocks.Interfaces.RealInput u1 "Connector of first Real input signal"
    Blocks.Interfaces.BooleanInput u2 "Connector of Boolean input signal"
    Blocks.Interfaces.RealInput u3 "Connector of second Real input signal"
    Blocks.Interfaces.RealOutput y "Connector of Real output signal"

  equation
    y = if u2 then u1 else u3;
  end Switch;

  block Hysteresis "Transform Real to Boolean signal with Hysteresis"

    extends Modelica.Blocks.Icons.PartialBooleanBlock;
    parameter Real uLow(start=0) "If y=true and u<uLow, switch to y=false";
    parameter Real uHigh(start=1) "If y=false and u>uHigh, switch to y=true";
    parameter Boolean pre_y_start=false "Value of pre(y) at initial time";

    Blocks.Interfaces.RealInput u
    Blocks.Interfaces.BooleanOutput y

  initial equation
    pre(y) = pre_y_start;
  equation
    assert(uHigh > uLow,"Hysteresis limits wrong (uHigh <= uLow)");
    y = not pre(y) and u > uHigh or pre(y) and u >= uLow;
  end Hysteresis;

  block OnOffController "On-off controller"
    extends Modelica.Blocks.Icons.PartialBooleanBlock;
    Blocks.Interfaces.RealInput reference
      "Connector of Real input signal used as reference signal"
    Blocks.Interfaces.RealInput u
      "Connector of Real input signal used as measurement signal"
    Blocks.Interfaces.BooleanOutput y
      "Connector of Real output signal used as actuator signal"

    parameter Real bandwidth(start=0.1) "Bandwidth around reference signal";
    parameter Boolean pre_y_start=false "Value of pre(y) at initial time";

  initial equation
    pre(y) = pre_y_start;
  equation
    y = pre(y) and (u < reference + bandwidth/2) or (u < reference - bandwidth/
      2);
  end OnOffController;

  block TriggeredTrapezoid "Triggered trapezoid generator"
    extends Modelica.Blocks.Icons.PartialBooleanBlock;

    parameter Real amplitude=1 "Amplitude of trapezoid";
    parameter SI.Time rising(final min=0) = 0
      "Rising duration of trapezoid";
    parameter SI.Time falling(final min=0) = rising
      "Falling duration of trapezoid";
    parameter Real offset=0 "Offset of output signal";

    Blocks.Interfaces.BooleanInput u "Connector of Boolean input signal"
    Blocks.Interfaces.RealOutput y "Connector of Real output signal"

  protected
    discrete Real endValue "Value of y at time of recent edge";
    discrete Real rate "Current rising/falling rate";
    discrete SI.Time T
      "Predicted time of output reaching endValue";
  equation
    y = if time < T then endValue - (T - time)*rate else endValue;

    when {initial(),u,not u} then
      endValue = if u then offset + amplitude else offset;
      rate = if u and (rising > 0) then amplitude/rising else if not u and (
        falling > 0) then -amplitude/falling else 0;
      T = if u and not (rising > 0) or not u and not (falling > 0) or not abs(
        amplitude) > 0 or initial() then time else time + (endValue - pre(y))/
        rate;
    end when;
  end TriggeredTrapezoid;

  block Timer
    "Timer measuring the time from the time instant where the Boolean input became true"

    extends Modelica.Blocks.Icons.PartialBooleanBlock;
    Blocks.Interfaces.BooleanInput u "Connector of Boolean input signal"
    Blocks.Interfaces.RealOutput y "Connector of Real output signal"

  protected
    discrete SI.Time entryTime "Time instant when u became true";
  initial equation
    pre(entryTime) = 0;
  equation
    when u then
      entryTime = time;
    end when;
    y = if u then time - entryTime else 0.0;
  end Timer;

  block LogicalDelay "Delay boolean signal"
    extends Blocks.Icons.PartialBooleanBlock;
    parameter SI.Time delayTime(final min=0)=0 "Time delay";
    Blocks.Interfaces.BooleanInput u
    Blocks.Interfaces.BooleanOutput y1
    Blocks.Interfaces.BooleanOutput y2
  protected
    discrete SI.Time tSwitch;
  initial equation
    tSwitch = time - 2*delayTime;
  equation
    when {u, not u} then
      tSwitch = time;
    end when;
    y1 = if u then true else not (time >= tSwitch + delayTime);
    y2 = if not u then false else (time >= tSwitch + delayTime);
  end LogicalDelay;

  block RSFlipFlop "A basic RS Flip Flop"
    extends Modelica.Blocks.Icons.PartialBooleanBlock;
    parameter Boolean Qini=false "Start value of Q at initial time";
    Modelica.Blocks.Interfaces.BooleanOutput Q
    Modelica.Blocks.Interfaces.BooleanOutput QI
    Modelica.Blocks.Logical.Nor nor
    Modelica.Blocks.Logical.Nor nor1
    Modelica.Blocks.Logical.Pre pre(pre_u_start=not (Qini))
    Modelica.Blocks.Interfaces.BooleanInput S
    Modelica.Blocks.Interfaces.BooleanInput R
  equation
    connect(nor1.y, nor.u2)
    connect(nor1.y, Q)
    connect(nor.y, pre.u)
    connect(pre.y, nor1.u1)
    connect(pre.y, QI)
    connect(S, nor.u1)
    connect(R, nor1.u2)
  end RSFlipFlop;

  block AssertCondition "Assert that input u is true"
    extends Modelica.Blocks.Interfaces.partialBooleanSI;
    parameter String message = "Assert block failed"
      "Assertion message to be displayed if the input u is false; please adapt";
    parameter AssertionLevel assertionLevel=AssertionLevel.error
      "Assertion level";
  equation
    assert(u,message,assertionLevel);
  end AssertCondition;

  block TerminateSimulation "Terminate simulation if condition is fulfilled"

    Modelica.Blocks.Interfaces.BooleanOutput condition=false
      "Terminate simulation when condition becomes true"
    parameter String terminationText="... End condition reached"
      "Text that will be displayed when simulation is terminated";

  equation
    when condition then
      terminate(terminationText);
    end when;
  end TerminateSimulation;
end Logical;


within Modelica.Blocks;
package Math "Library of Real mathematical functions as input/output blocks"

  import Modelica.Blocks.Interfaces;
  extends Modelica.Icons.Package;

  encapsulated package UnitConversions
    "Conversion blocks to convert between SI and non-SI unit signals"
    import Modelica;

    import Modelica.Units.NonSI;
    extends Modelica.Icons.Package;

    block To_degC "Convert from Kelvin to degCelsius"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="K"), y(
            unit="degC"));

    equation
      y = Modelica.Units.Conversions.to_degC(u);
    end To_degC;

    block From_degC "Convert from degCelsius to Kelvin"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="degC"),
          y(unit="K"));
    equation
      y = Modelica.Units.Conversions.from_degC(u);
    end From_degC;

    block To_degF "Convert from Kelvin to degFahrenheit"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="K"), y(
            unit="degF"));
    equation
      y = Modelica.Units.Conversions.to_degF(u);
    end To_degF;

    block From_degF "Convert from degFahrenheit to Kelvin"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="degF"),
          y(unit="K"));
    equation
      y = Modelica.Units.Conversions.from_degF(u);
    end From_degF;

    block To_degRk "Convert from Kelvin to degRankine"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="K"), y(
            unit="degRk"));
    equation
      y = Modelica.Units.Conversions.to_degRk(u);
    end To_degRk;

    block From_degRk "Convert from degRankine to Kelvin"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="degRk"),
          y(unit="K"));
    equation
      y = Modelica.Units.Conversions.from_degRk(u);
    end From_degRk;

    block To_deg "Convert from radian to degree"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="rad"),
          y(unit="deg"));
    equation
      y = Modelica.Units.Conversions.to_deg(u);
    end To_deg;

    block From_deg "Convert from degree to radian"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="deg"),
          y(unit="rad"));
    equation
      y = Modelica.Units.Conversions.from_deg(u);
    end From_deg;

    block To_rpm "Convert from radian per second to revolutions per minute"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="rad/s"),
          y(unit="rev/min"));
    equation
      y = Modelica.Units.Conversions.to_rpm(u);
    end To_rpm;

    block From_rpm "Convert from revolutions per minute to radian per second"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="rev/min"),
          y(unit="rad/s"));
    equation
      y = Modelica.Units.Conversions.from_rpm(u);
    end From_rpm;

    block To_kmh "Convert from metre per second to kilometre per hour"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="m/s"),
          y(unit="km/h"));
    equation
      y = Modelica.Units.Conversions.to_kmh(u);
    end To_kmh;

    block From_kmh "Convert from kilometre per hour to metre per second"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="km/h"),
          y(unit="m/s"));
    equation
      y = Modelica.Units.Conversions.from_kmh(u);
    end From_kmh;

    block To_day "Convert from second to day"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="s"), y(
            unit="d"));
    equation
      y = Modelica.Units.Conversions.to_day(u);
    end To_day;

    block From_day "Convert from day to second"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="d"), y(
            unit="s"));
    equation
      y = Modelica.Units.Conversions.from_day(u);
    end From_day;

    block To_hour "Convert from second to hour"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="s"), y(
            unit="h"));
    equation
      y = Modelica.Units.Conversions.to_hour(u);
    end To_hour;

    block From_hour "Convert from hour to second"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="h"), y(
            unit="s"));
    equation
      y = Modelica.Units.Conversions.from_hour(u);
    end From_hour;

    block To_minute "Convert from second to minute"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="s"), y(
            unit="min"));
    equation
      y = Modelica.Units.Conversions.to_minute(u);
    end To_minute;

    block From_minute "Convert from minute to second"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="min"),
          y(unit="s"));
    equation
      y = Modelica.Units.Conversions.from_minute(u);
    end From_minute;

    block To_litre "Convert from cubic metre to litre"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="m3"), y(
            unit="l"));
    equation
      y = Modelica.Units.Conversions.to_litre(u);
    end To_litre;

    block From_litre "Convert from litre to cubic metre"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="l"), y(
            unit="m3"));
    equation
      y = Modelica.Units.Conversions.from_litre(u);
    end From_litre;

    block To_kWh "Convert from Joule to kilo Watt hour"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="J"), y(
            unit="kW.h"));
    equation
      y = Modelica.Units.Conversions.to_kWh(u);
    end To_kWh;

    block From_kWh "Convert from kilo Watt hour to Joule"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="kW.h"),
          y(unit="J"));
    equation
      y = Modelica.Units.Conversions.from_kWh(u);
    end From_kWh;

    block To_bar "Convert from Pascal to bar"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="Pa"), y(
            unit="bar"));
    equation
      y = Modelica.Units.Conversions.to_bar(u);
    end To_bar;

    block From_bar "Convert from bar to Pascal"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="bar"),
          y(unit="Pa"));
    equation
      y = Modelica.Units.Conversions.from_bar(u);
    end From_bar;

    block To_gps "Convert from kilogram per second to gram per second"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="kg/s"),
          y(unit="g/s"));
    equation
      y = Modelica.Units.Conversions.to_gps(u);
    end To_gps;

    block From_gps "Convert from gram per second to kilogram per second"
      extends Modelica.Blocks.Interfaces.PartialConversionBlock(u(unit="g/s"),
          y(unit="kg/s"));
    equation
      y = Modelica.Units.Conversions.from_gps(u);
    end From_gps;
  end UnitConversions;

  block InverseBlockConstraints
    "Construct inverse model by requiring that two inputs and two outputs are identical"

    Modelica.Blocks.Interfaces.RealInput u1 "Input signal 1 (u1 = u2)"
    Modelica.Blocks.Interfaces.RealInput u2 "Input signal 2 (u1 = u2)"
    Modelica.Blocks.Interfaces.RealOutput y1 "Output signal 1 (y1 = y2)"
    Modelica.Blocks.Interfaces.RealOutput y2 "Output signal 2 (y1 = y2)"

  equation
    u1 = u2;
    y1 = y2;
  end InverseBlockConstraints;

  block Gain "Output the product of a gain value with the input signal"

    parameter Real k(start=1)
      "Gain value multiplied with input signal";
  public
    Interfaces.RealInput u "Input signal connector"
    Interfaces.RealOutput y "Output signal connector"

  equation
    y = k*u;
  end Gain;

  block MatrixGain
    "Output the product of a gain matrix with the input signal vector"

    parameter Real K[:, :]=[1, 0; 0, 1]
      "Gain matrix which is multiplied with the input";
    extends Interfaces.MIMO(final nin=size(K, 2), final nout=size(K, 1));
  equation
    y = K*u;
  end MatrixGain;

  block MultiSum "Sum of Reals: y = k[1]*u[1] + k[2]*u[2] + ... + k[n]*u[n]"
    extends Modelica.Blocks.Interfaces.PartialRealMISO;
    parameter Real k[nu]=fill(1, nu) "Input gains";
  equation
    if size(u, 1) > 0 then
      y = k*u;
    else
      y = 0;
    end if;
  end MultiSum;

  block MultiProduct "Product of Reals: y = u[1]*u[2]* ... *u[n]"
    extends Modelica.Blocks.Interfaces.PartialRealMISO;
  equation
    if size(u, 1) > 0 then
      y = product(u);
    else
      y = 0;
    end if;
  end MultiProduct;

  block MultiSwitch
    "Set Real expression that is associated with the first active input signal"

    input Real expr[nu]=fill(0.0, nu)
      "y = if u[i] then expr[i] else y_default (time varying)"
    parameter Real y_default=0.0
      "Default value of output y if all u[i] = false";

    parameter Integer nu(min=0) = 0 "Number of input connections"
    parameter Integer precision(min=0) = 3
      "Number of significant digits to be shown in dynamic diagram layer for y"

    Modelica.Blocks.Interfaces.BooleanVectorInput u[nu]
      "Set y = expr[i], if u[i] = true"
    Modelica.Blocks.Interfaces.RealOutput y "Output depending on expression"

  protected
    Integer firstActiveIndex;
  initial equation
    pre(u) = fill(false, nu);
  equation
    firstActiveIndex = Modelica.Math.BooleanVectors.firstTrueIndex(u);
    y = if firstActiveIndex == 0 then y_default else expr[firstActiveIndex];
  end MultiSwitch;

  block Sum "Output the sum of the elements of the input vector"
    extends Interfaces.MISO;
    parameter Real k[nin]=ones(nin) "Optional: sum coefficients";
  equation
    y = k*u;
  end Sum;

  block Feedback "Output difference between commanded and feedback input"

    Interfaces.RealInput u1 "Commanded input"
    Interfaces.RealInput u2 "Feedback input"
    Interfaces.RealOutput y

  equation
    y = u1 - u2;
  end Feedback;

  block Add "Output the sum of the two inputs"
    extends Interfaces.SI2SO;

    parameter Real k1=+1 "Gain of input signal 1";
    parameter Real k2=+1 "Gain of input signal 2";

  equation
    y = k1*u1 + k2*u2;
  end Add;

  block Add3 "Output the sum of the three inputs"
    extends Modelica.Blocks.Icons.Block;

    parameter Real k1=+1 "Gain of input signal 1";
    parameter Real k2=+1 "Gain of input signal 2";
    parameter Real k3=+1 "Gain of input signal 3";
    Interfaces.RealInput u1 "Connector of Real input signal 1"
    Interfaces.RealInput u2 "Connector of Real input signal 2"
    Interfaces.RealInput u3 "Connector of Real input signal 3"
    Interfaces.RealOutput y "Connector of Real output signal"

  equation
    y = k1*u1 + k2*u2 + k3*u3;
  end Add3;

  block Product "Output product of the two inputs"
    extends Interfaces.SI2SO;

  equation
    y = u1*u2;
  end Product;

  block Division "Output first input divided by second input"
    extends Interfaces.SI2SO;

  equation
    y = u1/u2;
  end Division;

  block Abs "Output the absolute value of the input"
    extends Interfaces.SISO;
    parameter Boolean generateEvent=false
      "Choose whether events shall be generated"
  equation
    //y = abs(u);
    y = if generateEvent then (if u >= 0 then u else -u) else (if noEvent(u >=
      0) then u else -u);

The Boolean parameter generateEvent decides whether Events are generated at zero crossing (Modelica specification before 3) or not.

"));
  end Abs;

  block Sign "Output the sign of the input"
    extends Interfaces.SISO;
    parameter Boolean generateEvent=false
      "Choose whether events shall be generated"
  equation
    //y = sign(u);
    y = if generateEvent then (if u > 0 then 1 elseif u < 0 then -1 else 0)
       else (if noEvent(u > 0) then 1 elseif noEvent(u < 0) then -1 else 0);
  end Sign;

  block Sqrt "Output the square root of the input (input >= 0 required)"
    extends Interfaces.SISO;

  equation
    y = sqrt(u);

The input shall be zero or positive.
Otherwise an error occurs.

"));
  end Sqrt;

  block Sin "Output the sine of the input"
    extends Interfaces.SISO(u(unit="rad"));
  equation
    y = Modelica.Math.sin(u);

"));
  end Sin;

  block Cos "Output the cosine of the input"
    extends Interfaces.SISO(u(unit="rad"));

  equation
    y = Modelica.Math.cos(u);

"));
  end Cos;

  block Tan "Output the tangent of the input"
    extends Interfaces.SISO(u(unit="rad"));

  equation
    y = Modelica.Math.tan(u);

"));
  end Tan;

  block Asin "Output the arc sine of the input"
    extends Interfaces.SISO(y(unit="rad"));

  equation
    y = Modelica.Math.asin(u);

The absolute value of the input u need to
be less or equal to one (abs( u ) <= 1).
Otherwise an error occurs.

"));
  end Asin;

  block Acos "Output the arc cosine of the input"
    extends Interfaces.SISO(y(unit="rad"));
  equation
    y = Modelica.Math.acos(u);

The absolute value of the input u need to
be less or equal to one (abs( u ) <= 1).
Otherwise an error occurs.

"));
  end Acos;

  block Atan "Output the arc tangent of the input"
    extends Interfaces.SISO(y(unit="rad"));
  equation
    y = Modelica.Math.atan(u);

"));
  end Atan;

  block Atan2 "Output atan(u1/u2) of the inputs u1 and u2"
    extends Interfaces.SI2SO(y(unit="rad"));
  equation
    y = Modelica.Math.atan2(u1, u2);

u1 and u2 shall not be zero at the same time instant.
Atan2 uses the sign of u1 and u2 in order to construct
the solution in the range -180 deg ≤ y ≤ 180 deg, whereas
block Atan gives a solution in the range
-90 deg ≤ y ≤ 90 deg.

"));
  end Atan2;

  block Sinh "Output the hyperbolic sine of the input"
    extends Interfaces.SISO;

  equation
    y = Modelica.Math.sinh(u);

"));
  end Sinh;

  block Cosh "Output the hyperbolic cosine of the input"
    extends Interfaces.SISO;
  equation
    y = Modelica.Math.cosh(u);

"));
  end Cosh;

  block Tanh "Output the hyperbolic tangent of the input"
    extends Interfaces.SISO;
  equation
    y = Modelica.Math.tanh(u);

"));
  end Tanh;

  block Exp "Output the exponential (base e) of the input"
    extends Interfaces.SISO;

  equation
    y = Modelica.Math.exp(u);

"));
  end Exp;

  block Power "Output the power to a base of the input"
    extends Interfaces.SISO;
    parameter Real base = Modelica.Constants.e "Base of power"
    parameter Boolean useExp = true "Use exp function in implementation"
  equation
    y = if useExp then Modelica.Math.exp(u*Modelica.Math.log(base)) else base ^ u;
  end Power;

  block Exponentiation "Output the input raised to an exponent"
    extends Interfaces.SISO;
    parameter Real exponent=2 "Exponent of power"
  equation
    y = u^exponent;
  end Exponentiation;

  block Log
    "Output the logarithm (default base e) of the input (input > 0 required)"

    extends Interfaces.SISO;
    parameter Real base = Modelica.Constants.e "Base of logarithm"

  equation
    y = Modelica.Math.log(u)/Modelica.Math.log(base);

An error occurs if the input u is
zero or negative.

"));
  end Log;

  block Log10 "Output the base 10 logarithm of the input (input > 0 required)"

    extends Interfaces.SISO;
  equation
    y = Modelica.Math.log10(u);

An error occurs if the input u is
zero or negative.

"));
  end Log10;

  block WrapAngle "Wrap angle to interval ]-pi,pi] or [0,2*pi["

    extends Interfaces.SISO(u(unit="rad"), y(unit="rad"));
    parameter Boolean positiveRange=false "Use only positive output range, if true";

  equation
    y = Modelica.Math.wrapAngle(u,positiveRange);
  end WrapAngle;

  block RealToInteger "Convert Real to Integer signal"
    extends Modelica.Blocks.Icons.IntegerBlock;
  public
    Interfaces.RealInput u "Connector of Real input signal"
    Interfaces.IntegerOutput y "Connector of Integer output signal"
  equation
    y = if (u > 0) then integer(floor(u + 0.5)) else integer(ceil(u - 0.5));
  end RealToInteger;

  block IntegerToReal "Convert Integer to Real signals"
    extends Modelica.Blocks.Icons.Block;
    Interfaces.IntegerInput u "Connector of Integer input signal"
    Interfaces.RealOutput y "Connector of Real output signal"
  equation
    y = u;
  end IntegerToReal;

  block BooleanToReal "Convert Boolean to Real signal"
    extends Interfaces.partialBooleanSI;
    parameter Real realTrue=1.0 "Output signal for true Boolean input";
    parameter Real realFalse=0.0 "Output signal for false Boolean input";

    Blocks.Interfaces.RealOutput y "Connector of Real output signal"

  equation
    y = if u then realTrue else realFalse;
  end BooleanToReal;

  block BooleanToInteger "Convert Boolean to Integer signal"
    extends Interfaces.partialBooleanSI;
    parameter Integer integerTrue=1 "Output signal for true Boolean input";
    parameter Integer integerFalse=0 "Output signal for false Boolean input";

    Blocks.Interfaces.IntegerOutput y "Connector of Integer output signal"

  equation
    y = if u then integerTrue else integerFalse;
  end BooleanToInteger;

  block RealToBoolean "Convert Real to Boolean signal"

    Blocks.Interfaces.RealInput u "Connector of Real input signal"
    extends Interfaces.partialBooleanSO;
    parameter Real threshold=0.5
      "Output signal y is true, if input u >= threshold";

  equation
    y = u >= threshold;
  end RealToBoolean;

  block IntegerToBoolean "Convert Integer to Boolean signal"

    Blocks.Interfaces.IntegerInput u "Connector of Integer input signal"
    extends Interfaces.partialBooleanSO;
    parameter Integer threshold=1
      "Output signal y is true, if input u >= threshold";

  equation
    y = u >= threshold;
  end IntegerToBoolean;

  block RectangularToPolar
    "Convert rectangular coordinates to polar coordinates"
    extends Modelica.Blocks.Icons.Block;
    Modelica.Blocks.Interfaces.RealInput u_re
      "Real part of rectangular representation"
    Modelica.Blocks.Interfaces.RealInput u_im
      "Imaginary part of rectangular representation"
    Modelica.Blocks.Interfaces.RealOutput y_abs
      "Length of polar representation"
    Modelica.Blocks.Interfaces.RealOutput y_arg(unit="rad") "Angle of polar representation"

  equation
    y_abs = sqrt(u_re*u_re + u_im*u_im);
    y_arg = Modelica.Math.atan2(u_im, u_re);
  end RectangularToPolar;

  block PolarToRectangular
    "Convert polar coordinates to rectangular coordinates"
    extends Modelica.Blocks.Icons.Block;
    Modelica.Blocks.Interfaces.RealInput u_abs "Length of polar representation"
    Modelica.Blocks.Interfaces.RealInput u_arg(unit="rad") "Angle of polar representation"
    Modelica.Blocks.Interfaces.RealOutput y_re
      "Real part of rectangular representation"
    Modelica.Blocks.Interfaces.RealOutput y_im
      "Imaginary part of rectangular representation"

  equation
    y_re = u_abs*Modelica.Math.cos(u_arg);
    y_im = u_abs*Modelica.Math.sin(u_arg);
  end PolarToRectangular;

  block Mean "Calculate mean over period 1/f"
    extends Modelica.Blocks.Interfaces.SISO;
    parameter SI.Frequency f(start=50) "Base frequency";
    parameter Real x0=0 "Start value of integrator state";
    parameter Real y0=0 "Start value of output";
    parameter Boolean yGreaterOrEqualZero=false
      "= true, if output y is guaranteed to be >= 0 for the exact solution"
  protected
    parameter SI.Time t0(fixed=false) "Start time of simulation";
    Real x "Integrator state";
    discrete Real y_last "Last sampled mean value";
  initial equation
    t0 = time;
    x = x0;
    y_last = y0;
  equation
    der(x) = u;
    when sample(t0 + 1/f, 1/f) then
      y_last = if not yGreaterOrEqualZero then f*pre(x) else max(0.0, f*pre(x));
      reinit(x, 0);
    end when;
    y = y_last;
  end Mean;

  block RectifiedMean "Calculate rectified mean over period 1/f"
    extends Modelica.Blocks.Interfaces.SISO;
    parameter SI.Frequency f(start=50) "Base frequency";
    parameter Real x0=0 "Start value of integrator state";
    parameter Real y0(final min=0)=0 "Start value of output";
    Mean mean(final f=f, final x0=x0,
      final y0=y0)
    Blocks.Math.Abs abs1
  equation
    connect(u, abs1.u)
    connect(abs1.y, mean.u)
    connect(mean.y, y)
  end RectifiedMean;

  block ContinuousMean
    "Calculates the empirical expectation (mean) value of its input signal"
    extends Modelica.Blocks.Icons.Block;
    parameter SI.Time t_eps(min= 0)=1e-7
      "Mean value calculation starts at startTime + t_eps"

    Modelica.Blocks.Interfaces.RealInput u "Noisy input signal"
    Modelica.Blocks.Interfaces.RealOutput y
      "Expectation (mean) value of the input signal"
    parameter Real startTime=-Modelica.Constants.inf "Starting point for mean if after simulation start-point";
  protected
    Real mu(start=0, fixed=true) "Internal integrator variable";
    parameter Real t_0(fixed=false) "Start time";
    parameter Real actualStartTime=max(t_0, startTime);
  initial equation
    t_0 = time;
  equation
    der(mu) = if time >= actualStartTime then u else 0;
    y       = noEvent(if time > actualStartTime+t_eps then mu/(time-actualStartTime) else u);
  end ContinuousMean;

  block RootMeanSquare "Calculate root mean square over period 1/f"
    extends Modelica.Blocks.Interfaces.SISO;
    parameter SI.Frequency f(start=50) "Base frequency";
    parameter Real x0=0 "Start value of integrator state";
    parameter Real y0(final min=0)=0 "Start value of output";
    MultiProduct product(nu=2)
    Mean mean(
      final f=f,
      final y0=y0^2,
      final yGreaterOrEqualZero=true,
      final x0=x0)
    Blocks.Math.Sqrt sqrt1
  equation

    connect(product.y, mean.u)
    connect(mean.y, sqrt1.u)
    connect(sqrt1.y, y)
    connect(u, product.u[1])
    connect(u, product.u[2])
  end RootMeanSquare;

  block SignalExtrema "Calculate min and max of a signal"
    extends Modelica.Blocks.Icons.Block;

    parameter SI.Time Ts(start=0.01) "Sample time";
    Modelica.Blocks.Interfaces.RealInput
              u "Connector of Real input signal"
    Modelica.Blocks.Interfaces.RealOutput
              y_min "Min of input signal"
    Modelica.Blocks.Interfaces.RealOutput
              y_max "Max of input signal"
    discrete Real t_min "Sample time of last found minimum";
    discrete Real t_max "Sample time of last found maximum";

  protected
    parameter SI.Time t0(fixed=false) "Start time of simulation";

  initial equation
    t0 = time;
    y_min = u;
    y_max = u;
    t_min = time;
    t_max = time;

  equation
    when sample(t0 + Ts, Ts) then
      y_min = min(u, pre(y_min));
      y_max = max(u, pre(y_max));
      if y_min
pre(y_max) then
        t_max = time;
        t_min=pre(t_min);
      else
        t_min=pre(t_min);
        t_max=pre(t_max);
      end if;
    end when;
  end SignalExtrema;

  block ContinuousSignalExtrema "Store the minimum and maximum values of the input signal"
    extends Modelica.Blocks.Icons.Block;
    parameter Modelica.Units.SI.Time T(min=Modelica.Constants.small)=1e-6 "Derivative time constant";
    Modelica.Blocks.Interfaces.RealInput u
    Modelica.Blocks.Interfaces.RealOutput y_min
    Modelica.Blocks.Interfaces.RealOutput y_max
    output Modelica.Units.SI.Time t_min "Time instant of last found minimum";
    output Modelica.Units.SI.Time t_max "Time instant of last found maximum";
  protected
    Real x "Aux.state";
  initial equation
    x = u;
    y_min = u;
    y_max = u;
    t_min = time;
    t_max = time;
  equation
    //first order approximation of input
    der(x) = (u - x)/T;
    //first order approximation of derivative of input
    when {u<=x, u>=x, terminal()} then
    //detect local extrema at zero derivative, just before and after a step, and at the end of the simulation
      y_min = min({pre(y_min), u, pre(u)});
      y_max = max({pre(y_max), u, pre(u)});
      t_min = if y_min
pre(y_max) then time else pre(t_max);
    end when;
  end ContinuousSignalExtrema;

  block Variance "Calculates the empirical variance of its input signal"
    extends Modelica.Blocks.Icons.Block;
    parameter SI.Time t_eps(min=100*Modelica.Constants.eps)=1e-7
      "Variance calculation starts at startTime + t_eps"

    Modelica.Blocks.Interfaces.RealInput u "Noisy input signal"
    Modelica.Blocks.Interfaces.RealOutput y "Variance of the input signal"
  protected
    Real mu "Mean value (state variable)";
    Real var "Variance (state variable)";
    parameter Real t_0(fixed=false) "Start time";
  initial equation
    t_0 = time;
    mu  = u;
    var = 0;
  equation
    der(mu)  = noEvent(if time >= t_0 + t_eps then (u-mu)/(time-t_0)             else 0);
    der(var) = noEvent(if time >= t_0 + t_eps then ((u-mu)^2 - var)/(time - t_0) else 0);
    y        = noEvent(if time >= t_0 + t_eps then max(var,0)                    else 0);
  end Variance;

  block StandardDeviation
    "Calculates the empirical standard deviation of its input signal"
    extends Modelica.Blocks.Icons.Block;
    parameter SI.Time t_eps(min=100*Modelica.Constants.eps)=1e-7
      "Standard deviation calculation starts at startTime + t_eps"

    Modelica.Blocks.Interfaces.RealInput u "Noisy input signal"
    Modelica.Blocks.Interfaces.RealOutput y
      "Standard deviation of the input signal"

    Modelica.Blocks.Math.Variance variance(t_eps=t_eps)
    Modelica.Blocks.Math.Sqrt sqrt1
  equation
    connect(variance.u, u)
    connect(sqrt1.u, variance.y)
    connect(sqrt1.y, y)
  end StandardDeviation;

  block Harmonic "Calculate harmonic over period 1/f"
    extends Modelica.Blocks.Icons.Block;
    parameter SI.Frequency f(start=50) "Base frequency";
    parameter Integer k(start=1) "Order of harmonic";
    parameter Boolean useConjugateComplex=false
      "Gives conjugate complex result if true"
    parameter Real x0Cos=0 "Start value of cos integrator state";
    parameter Real x0Sin=0 "Start value of sin integrator state";
    parameter Real y0Cos=0 "Start value of cos result";
    parameter Real y0Sin=0 "Start value of sin result";

    Sources.Cosine      sin1(
      final amplitude=sqrt(2),
      final f=k*f,
      final phase=0)
    Blocks.Sources.Sine sin2(
      final amplitude=sqrt(2),
      final phase=0,
      final f=k*f)
    MultiProduct product1(nu=2)
    MultiProduct product2(nu=2)
    Mean mean1(final f=f, final x0=x0Cos,
      final y0=y0Cos)
    Mean mean2(final f=f, final x0=x0Sin,
      final y0=y0Sin)
    Blocks.Interfaces.RealInput u
    Blocks.Interfaces.RealOutput y_rms
      "Root mean square of polar representation"
    Blocks.Interfaces.RealOutput y_arg(unit="rad") "Angle of polar representation"
    Blocks.Math.RectangularToPolar rectangularToPolar
    Gain gain(final k=if useConjugateComplex then -1 else 1)
  equation

    connect(product2.y, mean2.u)
    connect(product1.y, mean1.u)
    connect(mean1.y, rectangularToPolar.u_re)
    connect(mean2.y, rectangularToPolar.u_im)
    connect(rectangularToPolar.y_abs, y_rms)
    connect(sin1.y, product1.u[1])
    connect(u, product1.u[2])
    connect(u, product2.u[1])
    connect(sin2.y, product2.u[2])
    connect(rectangularToPolar.y_arg, gain.u)
    connect(gain.y, y_arg)
  end Harmonic;

  block TotalHarmonicDistortion "Output the total harmonic distortion (THD)"
    extends Interfaces.SISO;
    parameter SI.Frequency f(start=1) "Base frequency";
    parameter Boolean useFirstHarmonic = true "THD with respect to first harmonic, if true; otherwise with respect to total RMS";

    Harmonic harmonic(
      final f=f,
      final k=1,
      final x0Cos=0,
      final x0Sin=0,
      final y0Cos=0,
      final y0Sin=0)
    RootMeanSquare rootMeanSquare(final f=f, final x0=0, final y0=0)
    Logical.GreaterThreshold greaterThreshold
    Interfaces.BooleanOutput valid "True, if output y is valid"
    Division division
    Nonlinear.Limiter limiter(uMin=Modelica.Constants.eps, uMax=Modelica.Constants.inf)
    Pythagoras pythagoras(u1IsHypotenuse=true)
    Logical.And andValid
    Sources.BooleanExpression booleanExpression(final y=not useFirstHarmonic)
    Logical.Switch switch1
  equation
    connect(u, rootMeanSquare.u)
    connect(u, harmonic.u)
    connect(harmonic.y_rms, greaterThreshold.u)
    connect(division.y, y)
    connect(pythagoras.u1, rootMeanSquare.y)
    connect(pythagoras.y, division.u1)
    connect(pythagoras.valid, andValid.u1)
    connect(greaterThreshold.y, andValid.u2)
    connect(andValid.y, valid)
    connect(limiter.y, division.u2)
    connect(harmonic.y_rms, pythagoras.u2)
    connect(switch1.u1, rootMeanSquare.y)
    connect(harmonic.y_rms, switch1.u3)
    connect(booleanExpression.y, switch1.u2)
    connect(switch1.y, limiter.u)
  end TotalHarmonicDistortion;

  block RealFFT "Sampling and FFT of input u"
    extends Modelica.Blocks.Interfaces.DiscreteBlock(final samplePeriod=1/(2*f_res*div(ns, 2)));
    parameter SI.Frequency f_max "Maximum frequency of interest";
    parameter SI.Frequency f_res "Frequency resolution";
    final parameter Integer ns=Modelica.Math.FastFourierTransform.realFFTsamplePoints(f_max, f_res, f_max_factor=5) "Number of samples";
    final parameter Integer nf=max(1,min(integer(ceil(f_max/f_res))+1, div(ns, 2))) "Number of frequency points";
    parameter String resultFileName="realFFT.mat" "Result file: f, abs, arg";
    output Integer info(start=0, fixed=true) "Information flag from FFT computation";
    Modelica.Blocks.Interfaces.RealInput u
  protected
    Real buf[ns](start=zeros(ns), each fixed=true) "Input buffer";
    Real abs[nf](start=zeros(nf), each fixed=true) "FFT amplitudes";
    Real arg[nf](start=zeros(nf), each fixed=true) "FFT phases";
    Integer iTick(start=0, fixed=true) "Sample ticks";
  algorithm
    when {sampleTrigger} then
      iTick :=pre(iTick) + 1;
      if iTick <= ns then
        buf[iTick] :=u;
      end if;
    end when;
    when terminal() then
      if iTick < ns then
        assert(false, "Sampling time not sufficient! stopTime>= "+String(startTime + (ns -1)*samplePeriod));
      else
        (info, abs, arg) :=Modelica.Math.FastFourierTransform.realFFT(buf, nf);
        assert(info==0, "Error in FFT");
        Modelica.Math.FastFourierTransform.realFFTwriteToFile(startTime + (ns - 1)*samplePeriod, resultFileName, f_max, abs, arg);
      end if;
    end when;
  end RealFFT;

  block Pythagoras "Determine the hypotenuse or leg of a right triangle"
    extends Interfaces.SI2SO;
    parameter Boolean u1IsHypotenuse = false "= true, if u1 is the hypotenuse and y is one leg";
    Interfaces.BooleanOutput valid "= true, if y is a valid result"
  protected
    Real y2 "Square of y";
  equation
    if not u1IsHypotenuse then
      y2 = u1^2 + u2^2;
      y = sqrt(y2);
      valid = true;
    else
      y2 = u1^2 - u2^2;
      valid = y2 >= 0;
      y = if noEvent(y2 >= 0) then sqrt(y2) else 0;
    end if;
  end Pythagoras;

  block Max "Pass through the largest signal"
    extends Interfaces.SI2SO;
  equation
    y = max(u1, u2);

"));
  end Max;

  block Min "Pass through the smallest signal"
    extends Interfaces.SI2SO;
  equation
    y = min(u1, u2);

"));
  end Min;

  block MinMax "Output the minimum and the maximum element of the input vector"
    extends Modelica.Blocks.Icons.Block;
    parameter Integer nu(min=0) = 0 "Number of input connections"
    Modelica.Blocks.Interfaces.RealVectorInput u[nu]
    Modelica.Blocks.Interfaces.RealOutput yMax
    Modelica.Blocks.Interfaces.RealOutput yMin
  equation
    yMax = max(u);
    yMin = min(u);
  end MinMax;

  block LinearDependency "Output a linear combination of the two inputs"
    extends Modelica.Blocks.Interfaces.SI2SO;
    parameter Real y0=0 "Initial value";
    parameter Real k1=0 "Gain of u1";
    parameter Real k2=0 "Gain of u2";
  equation
    y = y0 + k1*u1 + k2*u2;
  end LinearDependency;

  block Edge "Indicates rising edge of Boolean signal"
    extends Interfaces.BooleanSISO;
  equation
    y = edge(u);

"));
  end Edge;

  block BooleanChange "Indicates Boolean signal changing"
    extends Interfaces.BooleanSISO;
  equation
    y = change(u);

"));
  end BooleanChange;

  block IntegerChange "Indicates integer signal changing"
    extends Interfaces.IntegerSIBooleanSO;
  equation
    y = change(u);

"));
  end IntegerChange;
end Math;


within Modelica.Blocks;
package MathBoolean
  "Library of Boolean mathematical functions as input/output blocks"
  extends Modelica.Icons.Package;

block MultiSwitch
    "Set Boolean expression that is associated with the first active input signal"

  input Boolean expr[nu]=fill(false, nu)
      "Sets y = if u[i] then expr[i] else y_default (time varying)"
  parameter Boolean use_pre_as_default=true
      "Set true to hold last value as default (y_default = pre(y))"
  parameter Boolean y_default=false
      "Default value of output y if all u[i] = false"

  parameter Integer nu(min=0) = 0 "Number of input connections"

  Modelica.Blocks.Interfaces.BooleanVectorInput u[nu]
      "Set y = expr[i], if u[i] = true"
  Modelica.Blocks.Interfaces.BooleanOutput y "Output depending on expression"

  protected
  Integer firstActiveIndex;
initial equation
  pre(y) = y_default;
equation
    firstActiveIndex =
      Modelica.Math.BooleanVectors.firstTrueIndex(
                                   u);
   y = if firstActiveIndex == 0 then (if use_pre_as_default then pre(y) else y_default) else
                                     expr[firstActiveIndex];
end MultiSwitch;

  block And "Logical 'and': y = u[1] and u[2] and ... and u[nu]"
    extends Modelica.Blocks.Interfaces.PartialBooleanMISO;

  equation
    y = Modelica.Math.BooleanVectors.andTrue(
                              u);
  end And;

  block Or "Logical 'or': y = u[1] or u[2] or ... or u[nu]"
    extends Modelica.Blocks.Interfaces.PartialBooleanMISO;

  equation
    y = Modelica.Math.BooleanVectors.anyTrue(
                              u);
  end Or;

  block Xor
    "Logical 'xor': y = oneTrue(u)  (y is true, if exactly one element of u is true, otherwise it is false)"
    extends Modelica.Blocks.Interfaces.PartialBooleanMISO;

  equation
    y = Modelica.Math.BooleanVectors.oneTrue(
                              u);
  end Xor;

  block Nand "Logical 'nand': y = not ( u[1] and u[2] and ... and u[nu] )"
    extends Modelica.Blocks.Interfaces.PartialBooleanMISO;

  equation
    y = not Modelica.Math.BooleanVectors.andTrue(
                                  u);
  end Nand;

  block Nor "Logical 'nor': y = not ( u[1] or u[2] or ... or u[nu] )"
    extends Modelica.Blocks.Interfaces.PartialBooleanMISO;

  equation
    y = not Modelica.Math.BooleanVectors.anyTrue(
                                  u);
  end Nor;

  block Not "Logical 'not': y = not u"
    extends Modelica.Blocks.Interfaces.PartialBooleanSISO_small;

  equation
    y = not u;
  end Not;

  block RisingEdge
    "Output y is true, if the input u has a rising edge, otherwise it is false (y = edge(u))"
     parameter Boolean pre_u_start = false "Value of pre(u) at initial time";
     extends Modelica.Blocks.Interfaces.PartialBooleanSISO_small;
  initial equation
    pre(u) = pre_u_start;
  equation
    y = edge(u);
  end RisingEdge;

  block FallingEdge
    "Output y is true, if the input u has a falling edge, otherwise it is false (y = edge(not u))"
     parameter Boolean pre_u_start = false "Value of pre(u) at initial time";
     extends Modelica.Blocks.Interfaces.PartialBooleanSISO_small;
  protected
    Boolean not_u = not u
  initial equation
    pre(not_u) = not pre_u_start;
  equation
    y = edge(not_u);
  end FallingEdge;

  block ChangingEdge
    "Output y is true, if the input u has either a rising or a falling edge and otherwise it is false (y=change(u))"
     parameter Boolean pre_u_start = false "Value of pre(u) at initial time";
     extends Modelica.Blocks.Interfaces.PartialBooleanSISO_small;
  initial equation
    pre(u) = pre_u_start;
  equation
    y = change(u);
  end ChangingEdge;

  block OnDelay
    "Delay a rising edge of the input, but do not delay a falling edge."
        extends Modelica.Blocks.Interfaces.PartialBooleanSISO_small;
        parameter SI.Time delayTime "Delay time";

  protected
        Boolean delaySignal(start=false,fixed=true);
        discrete SI.Time t_next;
  initial equation
        pre(u) = false;
        pre(t_next) = time - 1;
  algorithm
        when initial() then
           delaySignal := u;
           t_next := time - 1;
        elsewhen u then
           delaySignal := true;
           t_next := time + delayTime;
        elsewhen not u then
           delaySignal := false;
           t_next := time - 1;
        end when;
  equation
        if delaySignal then
           y = time >= t_next;
        else
           y = false;
        end if;
  end OnDelay;
end MathBoolean;


within Modelica.Blocks;
package MathInteger
  "Library of Integer mathematical functions as input/output blocks"
  extends Modelica.Icons.Package;
block MultiSwitch
    "Set Integer expression that is associated with the first active input signal"

  input Integer expr[nu]=fill(0, nu)
      "y = if u[i] then expr[i] elseif use_pre_as_default then pre(y) else y_default"
  parameter Integer y_default=0
      "Default value of output y if use_pre_as_default=false, as well as pre(y) at initial time";

  parameter Boolean use_pre_as_default=true
      "= true, y holds its last value if all u[i]=false, otherwise y=y_default"
  parameter Integer nu(min=0) = 0 "Number of input connections"

  Modelica.Blocks.Interfaces.BooleanVectorInput u[nu]
      "Set y = expr[i], if u[i] = true"
  Modelica.Blocks.Interfaces.IntegerOutput y "Output depending on expression"

  protected
  Integer firstActiveIndex;
initial equation
  pre(y) = y_default;
equation
  firstActiveIndex = Modelica.Math.BooleanVectors.firstTrueIndex(
                                                  u);
  y = if firstActiveIndex > 0 then expr[firstActiveIndex] else
      if use_pre_as_default then pre(y) else y_default;
end MultiSwitch;

  block Sum "Sum of Integers: y = k[1]*u[1] + k[2]*u[2] + ... + k[n]*u[n]"
     extends Modelica.Blocks.Interfaces.PartialIntegerMISO;
     parameter Integer k[nu] = fill(1,nu) "Input gains";
  equation
    if size(u,1) > 0 then
       y = k*u;
    else
       y = 0;
    end if;
  end Sum;

  block Product "Product of Integer: y = u[1]*u[2]* ... *u[n]"
     extends Modelica.Blocks.Interfaces.PartialIntegerMISO;
  equation
    if size(u,1) > 0 then
       y = product(u);
    else
       y = 0;
    end if;
  end Product;

  block TriggeredAdd
    "Add input to previous value of output, if rising edge of trigger port"
    extends Modelica.Blocks.Interfaces.PartialIntegerSISO;

    parameter Boolean use_reset = false "= true, if reset port enabled"
    parameter Boolean use_set = false
      "= true, if set port enabled and used as default value when reset"
    parameter Integer y_start = 0
      "Initial and reset value of y if set port is not used";

    Modelica.Blocks.Interfaces.BooleanInput trigger
    Modelica.Blocks.Interfaces.BooleanInput reset if use_reset
    Modelica.Blocks.Interfaces.IntegerInput set if use_set
  protected
    Modelica.Blocks.Interfaces.BooleanOutput local_reset
    Modelica.Blocks.Interfaces.IntegerOutput local_set;
  initial equation
    pre(y) = y_start;
  equation
    if use_reset then
       connect(reset, local_reset);
         if use_set then
           connect(set, local_set);
         else
           local_set = y_start;
         end if;
    else
       local_reset = false;
       local_set = 0;
    end if;

    when {trigger, local_reset} then
       y = if local_reset then local_set else pre(y) + u;
    end when;
  end TriggeredAdd;
end MathInteger;


Library of noise blocks

within Modelica.Blocks;
package Noise "Library of noise blocks"
  extends Modelica.Icons.Package;

  model GlobalSeed
    "Defines global settings for the blocks of sublibrary Noise, especially a global seed value is defined"
    parameter Boolean enableNoise = true
      "= true, if noise blocks generate noise as output; = false, if they generate a constant output"
    parameter Boolean useAutomaticSeed = false
      "= true, choose a seed by system time and process id; = false, use fixedSeed"
    parameter Integer fixedSeed = 67867967
      "Fixed global seed for random number generators (if useAutomaticSeed = false)"
    final parameter Integer seed(fixed=false) "Actually used global seed";
    final parameter Integer id_impure(fixed=false)
      "ID for impure random number generators Modelica.Math.Random.Utilities.impureXXX"
  initial equation
    seed = if useAutomaticSeed then Modelica.Math.Random.Utilities.automaticGlobalSeed() else fixedSeed;
    id_impure = Modelica.Math.Random.Utilities.initializeImpureRandom(seed);
  end GlobalSeed;

  block UniformNoise "Noise generator with uniform distribution"
    import distribution = Modelica.Math.Distributions.Uniform.quantile;
    extends Modelica.Blocks.Interfaces.PartialNoise;

    // Main dialog menu
    parameter Real y_min(start=0) "Lower limit of y"
    parameter Real y_max(start=1) "Upper limit of y"

  initial equation
     r = distribution(r_raw, y_min, y_max);

  equation
    // Draw random number at sample times
    when generateNoise and sample(startTime, samplePeriod) then
      r = distribution(r_raw, y_min, y_max);
    end when;
  end UniformNoise;

  block NormalNoise "Noise generator with normal distribution"
    import distribution = Modelica.Math.Distributions.Normal.quantile;
    extends Modelica.Blocks.Interfaces.PartialNoise;

    // Main dialog menu
    parameter Real mu=0 "Expectation (mean) value of the normal distribution"
    parameter Real sigma(start=1)
      "Standard deviation of the normal distribution"

  initial equation
     r = distribution(r_raw, mu, sigma);

  equation
    // Draw random number at sample times
    when generateNoise and sample(startTime, samplePeriod) then
      r = distribution(r_raw, mu, sigma);
    end when;
  end NormalNoise;

  block TruncatedNormalNoise
    "Noise generator with truncated normal distribution"
    import distribution =
      Modelica.Math.Distributions.TruncatedNormal.quantile;
    extends Modelica.Blocks.Interfaces.PartialNoise;

    // Main dialog menu
    parameter Real y_min(start=0) "Lower limit of y"
    parameter Real y_max(start=1) "Upper limit of y"
    parameter Real mu =    (y_max + y_min)/2
      "Expectation (mean) value of the normal distribution"
    parameter Real sigma = (y_max - y_min)/6
      "Standard deviation of the normal distribution"

  initial equation
     r = distribution(r_raw, y_min, y_max, mu, sigma);

  equation
    // Draw random number at sample times
    when generateNoise and sample(startTime, samplePeriod) then
      r = distribution(r_raw, y_min, y_max, mu, sigma);
    end when;
  end TruncatedNormalNoise;

  block BandLimitedWhiteNoise
    "Noise generator to produce band-limited white noise with normal distribution"
    import distribution = Modelica.Math.Distributions.Normal.quantile;
    extends Modelica.Blocks.Interfaces.PartialNoise;

    // Main dialog menu
    parameter Real noisePower = 1 "Power of white noise signal"

  protected
    parameter Real mu=0;
    parameter Real sigma=sqrt(noisePower/samplePeriod);

  initial equation
     r = distribution(r_raw, mu, sigma);

  equation
    // Draw random number at sample times
    when generateNoise and sample(startTime, samplePeriod) then
      r = distribution(r_raw, mu, sigma);
    end when;
  end BandLimitedWhiteNoise;
end Noise;


within Modelica.Blocks;
package Nonlinear
  "Library of discontinuous or non-differentiable algebraic control blocks"
  import Modelica.Blocks.Interfaces;
  extends Modelica.Icons.Package;

      block Limiter "Limit the range of a signal"
        parameter Real uMax(start=1) "Upper limits of input signals";
        parameter Real uMin= -uMax "Lower limits of input signals";
        parameter Boolean strict=false "= true, if strict limits with noEvent(..)"
        parameter Types.LimiterHomotopy homotopyType = Modelica.Blocks.Types.LimiterHomotopy.Linear "Simplified model for homotopy-based initialization"
        extends Interfaces.SISO;
  protected
        Real simplifiedExpr "Simplified expression for homotopy-based initialization";

      equation
        assert(uMax >= uMin, "Limiter: Limits must be consistent. However, uMax (=" + String(uMax) +
                             ") < uMin (=" + String(uMin) + ")");
        simplifiedExpr = (if homotopyType == Types.LimiterHomotopy.Linear then u
                          else if homotopyType == Types.LimiterHomotopy.UpperLimit then uMax
                          else if homotopyType == Types.LimiterHomotopy.LowerLimit then uMin
                          else 0);
        if strict then
          if homotopyType == Types.LimiterHomotopy.NoHomotopy then
            y = smooth(0, noEvent(if u > uMax then uMax else if u < uMin then uMin else u));
          else
            y = homotopy(actual = smooth(0, noEvent(if u > uMax then uMax else if u < uMin then uMin else u)),
                         simplified=simplifiedExpr);
          end if;
        else
          if homotopyType == Types.LimiterHomotopy.NoHomotopy then
            y = smooth(0,if u > uMax then uMax else if u < uMin then uMin else u);
          else
            y = homotopy(actual = smooth(0,if u > uMax then uMax else if u < uMin then uMin else u),
                         simplified=simplifiedExpr);
          end if;
        end if;
      end Limiter;

  block VariableLimiter "Limit the range of a signal with variable limits"
    extends Interfaces.SISO;
    parameter Boolean strict=false "= true, if strict limits with noEvent(..)"
    parameter Types.VariableLimiterHomotopy homotopyType = Modelica.Blocks.Types.VariableLimiterHomotopy.Linear "Simplified model for homotopy-based initialization"
    parameter Real ySimplified = 0 "Fixed value of output in simplified model"
    Interfaces.RealInput limit1
      "Connector of Real input signal used as maximum of input u"
    Interfaces.RealInput limit2
      "Connector of Real input signal used as minimum of input u"
  protected
    Real simplifiedExpr "Simplified expression for homotopy-based initialization";
  equation
    assert(limit1 >= limit2, "Input signals are not consistent: limit1 < limit2");
    simplifiedExpr = (if homotopyType == Types.VariableLimiterHomotopy.Linear then u
                      else if homotopyType == Types.VariableLimiterHomotopy.Fixed then ySimplified
                      else 0);
    if strict then
      if homotopyType == Types.VariableLimiterHomotopy.NoHomotopy then
        y = smooth(0, noEvent(if u > limit1 then limit1 else if u < limit2 then limit2 else u));
      else
        y = homotopy(actual = smooth(0, noEvent(if u > limit1 then limit1 else if u < limit2 then limit2 else u)),
                     simplified=simplifiedExpr);
      end if;
    else
      if homotopyType == Types.VariableLimiterHomotopy.NoHomotopy then
        y = smooth(0,if u > limit1 then limit1 else if u < limit2 then limit2 else u);
      else
        y = homotopy(actual = smooth(0,if u > limit1 then limit1 else if u < limit2 then limit2 else u),
                     simplified=simplifiedExpr);
      end if;
    end if;
  end VariableLimiter;

  block SlewRateLimiter "Limits the slew rate of a signal"
    extends Modelica.Blocks.Interfaces.SISO;
    import Modelica.Constants.small;
    parameter Real Rising( min= small) = 1
      "Maximum rising slew rate [+small..+inf) [1/s]";
    parameter Real Falling(max=-small) = -Rising
      "Maximum falling slew rate (-inf..-small] [1/s]";
    parameter SI.Time Td(min=small) = 0.001
      "Derivative time constant";
    parameter Modelica.Blocks.Types.Init initType=Modelica.Blocks.Types.Init.SteadyState
      "Type of initialization (SteadyState implies y = u)"
    parameter Real y_start=0 "Initial or guess value of output (= state)"
    parameter Boolean strict=false "= true, if strict limits with noEvent(..)"
  protected
    Real val=(u-y)/Td;
  initial equation
    if initType == Modelica.Blocks.Types.Init.SteadyState then
      y = u;
    elseif initType == Modelica.Blocks.Types.Init.InitialState
        or initType == Modelica.Blocks.Types.Init.InitialOutput then
      y = y_start;
    end if;
  equation
    if strict then
      der(y) = smooth(1, (if noEvent(val<Falling) then Falling else if noEvent(val>Rising) then Rising else val));
    else
      der(y) = if val<Falling then Falling else if val>Rising then Rising else val;
    end if;
  end SlewRateLimiter;

      block DeadZone "Provide a region of zero output"
        parameter Real uMax(start=1) "Upper limits of dead zones";
        parameter Real uMin=-uMax "Lower limits of dead zones";
        extends Interfaces.SISO;

      equation
        assert(uMax >= uMin, "DeadZone: Limits must be consistent. However, uMax (=" + String(uMax) +
                             ") < uMin (=" + String(uMin) + ")");

        y = homotopy(actual=smooth(0,if u > uMax then u - uMax else if u < uMin then u - uMin else 0), simplified=u);
      end DeadZone;

  block FixedDelay "Delay block with fixed DelayTime"
    extends Modelica.Blocks.Interfaces.SISO;
    parameter SI.Time delayTime(start=1)
      "Delay time of output with respect to input signal";

  equation
    y = delay(u, delayTime);
  end FixedDelay;

  block PadeDelay
    "Pade approximation of delay block with fixed delayTime (use balance=true; this is not the default to be backwards compatible)"
    extends Modelica.Blocks.Interfaces.SISO;
    parameter SI.Time delayTime(start=1)
      "Delay time of output with respect to input signal";
    parameter Integer n(min=1) = 1 "Order of Pade delay";
    parameter Integer m(min=1,max=n) = n
      "Order of numerator (usually m=n, or m=n-1)";
    parameter Boolean balance=false
      "= true, if state space system is balanced (highly recommended), otherwise textbook version"
    final output Real x[n]
      "State of transfer function from controller canonical form (balance=false), or balanced controller canonical form (balance=true)";

  protected
    parameter Real a1[n]( each fixed=false) "First row of A";
    parameter Real b11(        fixed=false) "= B[1,1]";
    parameter Real c[n](  each fixed=false) "C row matrix";
    parameter Real d(          fixed=false) "D matrix";
    parameter Real s[n-1](each fixed=false) "State scaling";

  function padeCoefficients2
    extends Modelica.Icons.Function;
    input Real T "Delay time";
    input Integer n "Order of denominator";
    input Integer m "Order of numerator";
    input Boolean balance=false;
    output Real a1[n] "First row of A";
    output Real b11 "= B[1,1]";
    output Real c[n] "C row matrix";
    output Real d "D matrix";
    output Real s[n-1] "Scaling such that x[i] = s[i-1]*x[i-1], i > 1";
    protected
    Real b[m + 1] "Numerator coefficients of transfer function";
    Real a[n + 1] "Denominator coefficients of transfer function";
    Real nm;
    Real bb[n + 1];
    Real A[n,n];
    Real B[n,1];
    Real C[1,n];
    Real A2[n,n] = zeros(n,n);
    Real B2[n,1] = zeros(n,1);
    Real C2[1,n] "C matrix";
    Integer nb = m+1;
    Integer na = n+1;
    Real sx[n];
  algorithm
    a[1] := 1;
    b[1] := 1;
    nm := n + m;

    for i in 1:n loop
      a[i + 1] := a[i]*(T*((n - i + 1)/(nm - i + 1))/i);
      if i <= m then
        b[i + 1] := -b[i]*(T*((m - i + 1)/(nm - i + 1))/i);
      end if;
    end for;

    b  := b[m + 1:-1:1];
    a  := a[n + 1:-1:1];
    bb := vector([zeros(n-m, 1); b]);
    d  := bb[1]/a[1];

    if balance then
      A2[1,:] := -a[2:na]/a[1];
      B2[1,1] := 1/a[1];
      for i in 1:n-1 loop
         A2[i+1,i] :=1;
      end for;
      C2[1,:] := bb[2:na] - d*a[2:na];
      (sx,A,B,C) :=Modelica.Math.Matrices.balanceABC(A2,B2,C2);
      for i in 1:n-1 loop
         s[i] := sx[i]/sx[i+1];
      end for;
      a1  := A[1,:];
      b11 := B[1,1];
      c   := vector(C);
    else
       s  := ones(n-1);
      a1  := -a[2:na]/a[1];
      b11 :=  1/a[1];
      c   := bb[2:na] - d*a[2:na];
    end if;
  end padeCoefficients2;

  equation
    der(x[1]) = a1*x + b11*u;
    if n > 1 then
       der(x[2:n]) = s.*x[1:n-1];
    end if;
    y = c*x + d*u;

  initial equation
    (a1,b11,c,d,s) = padeCoefficients2(delayTime, n, m, balance);

    if balance then
       der(x) = zeros(n);
    else
       // In order to be backwards compatible
       x[n] = u;
    end if;
  end PadeDelay;

  block VariableDelay "Delay block with variable DelayTime"
    extends Modelica.Blocks.Interfaces.SISO;
    parameter SI.Duration delayMax(min=0, start=1) "Maximum delay time";

    Modelica.Blocks.Interfaces.RealInput delayTime
  equation
    y = delay(u, delayTime, delayMax);
  end VariableDelay;
end Nonlinear;