Modelica.Blocks.Continuous.LimPID Modelica.Blocks.Continuous.LimPID

P, PI, PD, and PID controller with limited output, anti-windup compensation and setpoint weighting

Modelica.Blocks.Continuous.LimPID

Information

Via parameter controllerType either P, PI, PD, or PID can be selected. If, e.g., PI is selected, all components belonging to the D-part are removed from the block (via conditional declarations). The example model Modelica.Blocks.Examples.PID_Controller demonstrates the usage of this controller. Several practical aspects of PID controller design are incorporated according to chapter 3 of the book:

Åström K.J., and Hägglund T.:
PID Controllers: Theory, Design, and Tuning. Instrument Society of America, 2nd edition, 1995.

Besides the additive proportional, integral and derivative part of this controller, the following features are present:

The parameters of the controller can be manually adjusted by performing simulations of the closed loop system (= controller + plant connected together) and using the following strategy:

  1. Set very large limits, e.g., yMax = Modelica.Constants.inf
  2. Select a P-controller and manually enlarge parameter k (the total gain of the controller) until the closed-loop response cannot be improved any more.
  3. Select a PI-controller and manually adjust parameters k and Ti (the time constant of the integrator). The first value of Ti can be selected, such that it is in the order of the time constant of the oscillations occurring with the P-controller. If, e.g., vibrations in the order of T=10 ms occur in the previous step, start with Ti=0.01 s.
  4. If you want to make the reaction of the control loop faster (but probably less robust against disturbances and measurement noise) select a PID-Controller and manually adjust parameters k, Ti, Td (time constant of derivative block).
  5. Set the limits yMax and yMin according to your specification.
  6. Perform simulations such that the output of the PID controller goes in its limits. Tune Ni (Ni*Ti is the time constant of the anti-windup compensation) such that the input to the limiter block (= limiter.u) goes quickly enough back to its limits. If Ni is decreased, this happens faster. If Ni=infinity, the anti-windup compensation is switched off and the controller works bad.

Initialization

This block can be initialized in different ways controlled by parameter initType. The possible values of initType are defined in Modelica.Blocks.Types.InitPID. This type is identical to Types.Init, with the only exception that the additional option DoNotUse_InitialIntegratorState is added for backward compatibility reasons (= integrator is initialized with InitialState whereas differential part is initialized with NoInit which was the initialization in version 2.2 of the Modelica standard library).

Based on the setting of initType, the integrator (I) and derivative (D) blocks inside the PID controller are initialized according to the following table:

initType I.initType D.initType
NoInit NoInit NoInit
SteadyState SteadyState SteadyState
InitialState InitialState InitialState
InitialOutput
and initial equation: y = y_start
NoInit SteadyState
DoNotUse_InitialIntegratorState InitialState NoInit

In many cases, the most useful initial condition is SteadyState because initial transients are then no longer present. If initType = InitPID.SteadyState, then in some cases difficulties might occur. The reason is the equation of the integrator:

   der(y) = k*u;

The steady state equation "der(x)=0" leads to the condition that the input u to the integrator is zero. If the input u is already (directly or indirectly) defined by another initial condition, then the initialization problem is singular (has none or infinitely many solutions). This situation occurs often for mechanical systems, where, e.g., u = desiredSpeed - measuredSpeed and since speed is both a state and a derivative, it is natural to initialize it with zero. As sketched this is, however, not possible. The solution is to not initialize u_m or the variable that is used to compute u_m by an algebraic equation.

If parameter limitAtInit = false, the limits at the output of this controller block are removed from the initialization problem which leads to a much simpler equation system. After initialization has been performed, it is checked via an assert whether the output is in the defined limits. For backward compatibility reasons limitAtInit = true. In most cases it is best to use limitAtInit = false.

Extends from Interfaces.SVcontrol (Single-Variable continuous controller).

Parameters

TypeNameDefaultDescription
SimpleControllercontrollerType.Modelica.Blocks.Types.Simpl...Type of controller
Realk1Gain of controller [1]
TimeTi0.5Time constant of Integrator block [s]
TimeTd0.1Time constant of Derivative block [s]
RealyMax Upper limit of output
RealyMin-yMaxLower limit of output
Realwp1Set-point weight for Proportional block (0..1)
Realwd0Set-point weight for Derivative block (0..1)
RealNi0.9Ni*Ti is time constant of anti-windup compensation
RealNd10The higher Nd, the more ideal the derivative block
Initialization
InitPIDinitType.Modelica.Blocks.Types.InitP...Type of initialization (1: no init, 2: steady state, 3: initial state, 4: initial output)
BooleanlimitsAtInittrue= false, if limits are ignored during initialization
Realxi_start0Initial or guess value value for integrator output (= integrator state)
Realxd_start0Initial or guess value for state of derivative block
Realy_start0Initial value of output
Advanced
Booleanstrictfalse= true, if strict limits with noEvent(..)

Connectors

TypeNameDescription
input RealInputu_sConnector of setpoint input signal
input RealInputu_mConnector of measurement input signal
output RealOutputyConnector of actuator output signal

Modelica definition

block LimPID "P, PI, PD, and PID controller with limited output, anti-windup compensation and setpoint weighting" import Modelica.Blocks.Types.InitPID; import Modelica.Blocks.Types.Init; import Modelica.Blocks.Types.SimpleController; extends Interfaces.SVcontrol; output Real controlError = u_s - u_m "Control error (set point - measurement)"; parameter .Modelica.Blocks.Types.SimpleController controllerType= .Modelica.Blocks.Types.SimpleController.PID "Type of controller"; parameter Real k(min=0, unit="1") = 1 "Gain of controller"; parameter SIunits.Time Ti(min=Modelica.Constants.small)=0.5 "Time constant of Integrator block"; parameter SIunits.Time Td(min=0)= 0.1 "Time constant of Derivative block"; parameter Real yMax(start=1) "Upper limit of output"; parameter Real yMin=-yMax "Lower limit of output"; parameter Real wp(min=0) = 1 "Set-point weight for Proportional block (0..1)"; parameter Real wd(min=0) = 0 "Set-point weight for Derivative block (0..1)"; parameter Real Ni(min=100*Modelica.Constants.eps) = 0.9 "Ni*Ti is time constant of anti-windup compensation"; parameter Real Nd(min=100*Modelica.Constants.eps) = 10 "The higher Nd, the more ideal the derivative block"; parameter .Modelica.Blocks.Types.InitPID initType= .Modelica.Blocks.Types.InitPID.DoNotUse_InitialIntegratorState "Type of initialization (1: no init, 2: steady state, 3: initial state, 4: initial output)"; parameter Boolean limitsAtInit = true "= false, if limits are ignored during initialization"; parameter Real xi_start=0 "Initial or guess value value for integrator output (= integrator state)"; parameter Real xd_start=0 "Initial or guess value for state of derivative block"; parameter Real y_start=0 "Initial value of output"; parameter Boolean strict=false "= true, if strict limits with noEvent(..)"; constant SI.Time unitTime=1; Blocks.Math.Add addP(k1=wp, k2=-1); Blocks.Math.Add addD(k1=wd, k2=-1) if with_D; Blocks.Math.Gain P(k=1); Blocks.Continuous.Integrator I(k=unitTime/Ti, y_start=xi_start, initType=if initType==InitPID.SteadyState then Init.SteadyState else if initType==InitPID.InitialState or initType==InitPID.DoNotUse_InitialIntegratorState then Init.InitialState else Init.NoInit) if with_I; Blocks.Continuous.Derivative D(k=Td/unitTime, T=max([Td/Nd, 1.e-14]), x_start=xd_start, initType=if initType==InitPID.SteadyState or initType==InitPID.InitialOutput then Init.SteadyState else if initType==InitPID.InitialState then Init.InitialState else Init.NoInit) if with_D; Blocks.Math.Gain gainPID(k=k); Blocks.Math.Add3 addPID; Blocks.Math.Add3 addI(k2=-1) if with_I; Blocks.Math.Add addSat(k1=+1, k2=-1) if with_I; Blocks.Math.Gain gainTrack(k=1/(k*Ni)) if with_I; Blocks.Nonlinear.Limiter limiter(uMax=yMax, uMin=yMin, strict=strict, limitsAtInit=limitsAtInit); protected parameter Boolean with_I = controllerType==SimpleController.PI or controllerType==SimpleController.PID; parameter Boolean with_D = controllerType==SimpleController.PD or controllerType==SimpleController.PID; public Sources.Constant Dzero(k=0) if not with_D; Sources.Constant Izero(k=0) if not with_I; initial equation if initType==InitPID.InitialOutput then gainPID.y = y_start; end if; equation if initType == InitPID.InitialOutput and (y_start < yMin or y_start > yMax) then Modelica.Utilities.Streams.error("LimPID: Start value y_start (=" + String(y_start) + ") is outside of the limits of yMin (=" + String(yMin) +") and yMax (=" + String(yMax) + ")"); end if; connect(u_s, addP.u1); connect(u_s, addD.u1); connect(u_s, addI.u1); connect(addP.y, P.u); connect(addD.y, D.u); connect(addI.y, I.u); connect(P.y, addPID.u1); connect(D.y, addPID.u2); connect(I.y, addPID.u3); connect(addPID.y, gainPID.u); connect(gainPID.y, addSat.u2); connect(gainPID.y, limiter.u); connect(limiter.y, addSat.u1); connect(limiter.y, y); connect(addSat.y, gainTrack.u); connect(gainTrack.y, addI.u3); connect(u_m, addP.u2); connect(u_m, addD.u2); connect(u_m, addI.u2); connect(Dzero.y, addPID.u2); connect(Izero.y, addPID.u3); end LimPID;

Modelica.Blocks.Continuous.Integrator Modelica.Blocks.Continuous.Integrator

Output the integral of the input signal

Modelica.Blocks.Continuous.Integrator

Information

This blocks computes output y (element-wise) as integral of the input u multiplied with the gain k:

         k
     y = - u
         s

It might be difficult to initialize the integrator in steady state. This is discussed in the description of package Continuous.

Extends from Interfaces.SISO (Single Input Single Output continuous control block).

Parameters

TypeNameDefaultDescription
Realk1Integrator gain [1]
Initialization
InitinitTypeModelica.Blocks.Types.Init.I...Type of initialization (1: no init, 2: steady state, 3,4: initial output)
Realy_start0Initial or guess value of output (= state)
RealOutputy.starty_startConnector of Real output signal

Connectors

TypeNameDescription
input RealInputuConnector of Real input signal

Modelica definition

block Integrator "Output the integral of the input signal" import Modelica.Blocks.Types.Init; parameter Real k(unit="1")=1 "Integrator gain"; /* InitialState is the default, because it was the default in Modelica 2.2 and therefore this setting is backward compatible */ parameter Modelica.Blocks.Types.Init initType=Modelica.Blocks.Types.Init.InitialState "Type of initialization (1: no init, 2: steady state, 3,4: initial output)"; parameter Real y_start=0 "Initial or guess value of output (= state)"; extends Interfaces.SISO(y(start=y_start)); initial equation if initType == Init.SteadyState then der(y) = 0; elseif initType == Init.InitialState or initType == Init.InitialOutput then y = y_start; end if; equation der(y) = k*u; end Integrator;

Modelica.Blocks.Continuous.LimIntegrator Modelica.Blocks.Continuous.LimIntegrator

Integrator with limited value of the output

Modelica.Blocks.Continuous.LimIntegrator

Information

This blocks computes y (element-wise) as integral of the input u multiplied with the gain k. If the integral reaches a given upper or lower limit and the input will drive the integral outside of this bound, the integration is halted and only restarted if the input drives the integral away from the bounds.

It might be difficult to initialize the integrator in steady state. This is discussed in the description of package Continuous.

If parameter limitAtInit = false, the limits of the integrator are removed from the initialization problem which leads to a much simpler equation system. After initialization has been performed, it is checked via an assert whether the output is in the defined limits. For backward compatibility reasons limitAtInit = true. In most cases it is best to use limitAtInit = false.

Extends from Interfaces.SISO (Single Input Single Output continuous control block).

Parameters

TypeNameDefaultDescription
Realk1Integrator gain [1]
RealoutMax Upper limit of output
RealoutMin-outMaxLower limit of output
Initialization
InitinitTypeModelica.Blocks.Types.Init.I...Type of initialization (1: no init, 2: steady state, 3/4: initial output)
BooleanlimitsAtInittrue= false, if limits are ignored during initialization (i.e., der(y)=k*u)
Realy_start0Initial or guess value of output (must be in the limits outMin .. outMax)
RealOutputy.starty_startConnector of Real output signal
Advanced
Booleanstrictfalse= true, if strict limits with noEvent(..)

Connectors

TypeNameDescription
input RealInputuConnector of Real input signal

Modelica definition

block LimIntegrator "Integrator with limited value of the output" import Modelica.Blocks.Types.Init; parameter Real k(unit="1")=1 "Integrator gain"; parameter Real outMax(start=1) "Upper limit of output"; parameter Real outMin=-outMax "Lower limit of output"; parameter Modelica.Blocks.Types.Init initType=Modelica.Blocks.Types.Init.InitialState "Type of initialization (1: no init, 2: steady state, 3/4: initial output)"; parameter Boolean limitsAtInit = true "= false, if limits are ignored during initialization (i.e., der(y)=k*u)"; parameter Real y_start=0 "Initial or guess value of output (must be in the limits outMin .. outMax)"; parameter Boolean strict=false "= true, if strict limits with noEvent(..)"; extends Interfaces.SISO(y(start=y_start)); initial equation if initType == Init.SteadyState then der(y) = 0; elseif initType == Init.InitialState or initType == Init.InitialOutput then y = y_start; end if; equation if initial() and not limitsAtInit then der(y) = k*u; assert(y >= outMin - 0.001*abs(outMax-outMin) and y <= outMax + 0.001*abs(outMax-outMin), "LimIntegrator: During initialization the limits have been ignored.\n" + "However, the result is that the output y is not within the required limits:\n" + " y = " + String(y) + ", outMin = " + String(outMin) + ", outMax = " + String(outMax)); elseif strict then der(y) = noEvent(if y < outMin and k*u < 0 or y > outMax and k*u > 0 then 0 else k*u); else der(y) = if y < outMin and k*u < 0 or y > outMax and k*u > 0 then 0 else k*u; end if; end LimIntegrator;

Modelica.Blocks.Continuous.FirstOrder Modelica.Blocks.Continuous.FirstOrder

First order transfer function block (= 1 pole)

Modelica.Blocks.Continuous.FirstOrder

Information

This blocks defines the transfer function between the input u and the output y (element-wise) as first order system:

               k
     y = ------------ * u
            T * s + 1

If you would like to be able to change easily between different transfer functions (FirstOrder, SecondOrder, ... ) by changing parameters, use the general block TransferFunction instead and model a first order SISO system with parameters
b = {k}, a = {T, 1}.

Example:
   parameter: k = 0.3, T = 0.4
   results in:
             0.3
      y = ----------- * u
          0.4 s + 1.0

Extends from Interfaces.SISO (Single Input Single Output continuous control block).

Parameters

TypeNameDefaultDescription
Realk1Gain [1]
TimeT Time Constant [s]
Initialization
InitinitTypeModelica.Blocks.Types.Init.N...Type of initialization (1: no init, 2: steady state, 3/4: initial output)
Realy_start0Initial or guess value of output (= state)
RealOutputy.starty_startConnector of Real output signal

Connectors

TypeNameDescription
input RealInputuConnector of Real input signal

Modelica definition

block FirstOrder "First order transfer function block (= 1 pole)" import Modelica.Blocks.Types.Init; parameter Real k(unit="1")=1 "Gain"; parameter SIunits.Time T(start=1) "Time Constant"; parameter Modelica.Blocks.Types.Init initType=Modelica.Blocks.Types.Init.NoInit "Type of initialization (1: no init, 2: steady state, 3/4: initial output)"; parameter Real y_start=0 "Initial or guess value of output (= state)"; extends Interfaces.SISO(y(start=y_start)); initial equation if initType == Init.SteadyState then der(y) = 0; elseif initType == Init.InitialState or initType == Init.InitialOutput then y = y_start; end if; equation der(y) = (k*u - y)/T; end FirstOrder;

Modelica.Blocks.Continuous.Derivative Modelica.Blocks.Continuous.Derivative

Approximated derivative block

Modelica.Blocks.Continuous.Derivative

Information

This blocks defines the transfer function between the input u and the output y (element-wise) as approximated derivative:

             k * s
     y = ------------ * u
            T * s + 1

If you would like to be able to change easily between different transfer functions (FirstOrder, SecondOrder, ... ) by changing parameters, use the general block TransferFunction instead and model a derivative block with parameters
b = {k,0}, a = {T, 1}.

If k=0, the block reduces to y=0.

Extends from Interfaces.SISO (Single Input Single Output continuous control block).

Parameters

TypeNameDefaultDescription
Realk1Gains [1]
TimeT0.01Time constants (T>0 required; T=0 is ideal derivative block) [s]
Initialization
InitinitTypeModelica.Blocks.Types.Init.N...Type of initialization (1: no init, 2: steady state, 3: initial state, 4: initial output)
Realx_start0Initial or guess value of state
Realy_start0Initial value of output (= state)

Connectors

TypeNameDescription
input RealInputuConnector of Real input signal
output RealOutputyConnector of Real output signal

Modelica definition

block Derivative "Approximated derivative block" import Modelica.Blocks.Types.Init; parameter Real k(unit="1")=1 "Gains"; parameter SIunits.Time T(min=Modelica.Constants.small) = 0.01 "Time constants (T>0 required; T=0 is ideal derivative block)"; parameter Modelica.Blocks.Types.Init initType=Modelica.Blocks.Types.Init.NoInit "Type of initialization (1: no init, 2: steady state, 3: initial state, 4: initial output)"; parameter Real x_start=0 "Initial or guess value of state"; parameter Real y_start=0 "Initial value of output (= state)"; extends Interfaces.SISO; output Real x(start=x_start) "State of block"; protected parameter Boolean zeroGain = abs(k) < Modelica.Constants.eps; initial equation if initType == Init.SteadyState then der(x) = 0; elseif initType == Init.InitialState then x = x_start; elseif initType == Init.InitialOutput then if zeroGain then x = u; else y = y_start; end if; end if; equation der(x) = if zeroGain then 0 else (u - x)/T; y = if zeroGain then 0 else (k/T)*(u - x); end Derivative;

Automatically generated Mon Sep 11 16:11:52 2017.