MPC Controller¶
![]()
Model predictive controller for dynamic simulations, based on Dynamic Matrix Control (DMC). It moves several manipulated variables at once to keep several controlled variables inside their ranges, using first-order plus dead time step response models between each pair.
DWSIM.UnitOperations.SpecialOps.MPCController
Assembly DWSIM.UnitOperations.dll · Object ← BaseClass ← SpecialOpBaseClass ← MPCController
At a glance¶

This object has no stream connections; it acts on other objects through their properties.
Example¶
This code runs on every build of this site, and the output below is what it printed.
fs = (Flowsheet.Create("MPCExample")
.WithCompound("Water")
.WithPropertyPackage(PropertyPackages.SteamTables))
inlet = (fs.AddMaterialStream("Inlet").At(Q.Celsius(25.0), Q.Pascal(130000.0))
.WithMassFlow(Q.KgPerSecond(10.0)).AsFlowSpec())
s1 = fs.AddMaterialStream("S-1").AsPressureSpec()
s2 = fs.AddMaterialStream("S-2").AsPressureSpec()
outlet = fs.AddMaterialStream("Outlet").AsPressureSpec()
(fs.AddValve("V-01").WithCalcMode(Valve.CalculationMode.Kv_Liquid).WithKv(100.0)
.WithOpeningPercent(50.0).ConnectFeed(inlet).ConnectProduct(s1))
tank = (fs.AddTank("T-01").WithVolume(Q.CubicMeters(2.0)).WithHeight(Q.Meters(2.0))
.ConnectFeed(s1).ConnectProduct(s2))
valve = (fs.AddValve("V-02").WithCalcMode(Valve.CalculationMode.Kv_Liquid).WithKv(400.0)
.WithOpeningKvRelationship().WithOpeningPercent(29.0)
.ConnectFeed(s2).ConnectProduct(outlet))
fs.AutoLayout()
fs.Solve() # steady state to start from
outlet.Object.Phases[0].Properties.pressure = 101325.0 # discharge to atmosphere
builder = fs.AddUnitOperation(ObjectType.Controller_MPC, "LC-MPC")
mpc = builder.Object.__implementation__
cv = MPCVariable() # controlled variable: the tank level
cv.ObjectID, cv.Name = tank.Object.Name, "T-01 level"
cv.PropertyName, cv.Units = "Liquid Level", "m"
cv.MinValue, cv.MaxValue = 0.9, 1.1 # the target is the middle of the range, 1 m
mv = MPCVariable() # manipulated variable: the outlet valve opening
mv.ObjectID, mv.Name = valve.Object.Name, "V-02 opening"
mv.PropertyName, mv.Units = "PROP_VA_5", ""
mv.MinValue, mv.MaxValue = 0.0, 100.0 # %
mpc.ControlledVariables.Add(cv)
mpc.ManipulatedVariables.Add(mv)
model = StepResponseModel() # level response to the opening
model.CVIndex, model.MVIndex = 0, 0
model.Integrating = True # the level ramps after a step in the opening
model.Gain = -0.0004 # m/s per %: 0.4 kg/s more outflow per % from a 1 m2 tank
model.TimeConstant = 0.0
mpc.StepResponseModels.Add(model)
mpc.SampleTime = 5.0 # s, one integration step
mpc.PredictionHorizon = 30 # 30 samples, 150 s ahead
mpc.ControlHorizon = 5 # five future moves
mpc.MoveSuppressionWeight = 0.1
(fs.Dynamics.DefineIntegrator("Int1")
.WithIntegrationStep(TimeSpan.FromSeconds(5.0)).WithDuration(TimeSpan.FromMinutes(20.0))
.Monitor("T-01", "Liquid Level", "m", "level")
.Monitor("V-02", "PROP_VA_5", "", "opening"))
(fs.Dynamics.DefineEventSet("FeedStep")
.AddStepChange("Inlet", "PROP_MS_2", 15.0, Q.Seconds(600.0), "kg/s", "feed 10 -> 15 kg/s"))
(fs.Dynamics.DefineSchedule("Run").WithIntegrator("Int1").WithEventSet("FeedStep")
.UseCurrentStateAsInitial(True).MakeCurrent())
result = fs.RunDynamics("Run").Execute()
level, opening = result.GetSeries("level"), result.GetSeries("opening")
print(f"Level = {level.Initial:.3f} m at the start, {level.ValueAt(595.0):.3f} m before the step")
print(f"Peak level after step = {max(v for t, v in zip(level.TimeSeconds, level.Values) if t >= 600.0):.3f} m")
print(f"Final level = {level.Final:.3f} m")
print(f"Valve opening = {opening.ValueAt(595.0):.1f} % before, {opening.Final:.1f} % at the end")
# Measured disturbance as feedforward: a second tank, T-00, in front of T-01 delays the feed step
# by its own lag. Measuring the feed and telling the controller how it acts on the level lets
# the valve open before the level rises.
def two_tanks(feedforward):
fs2 = (Flowsheet.Create("MPCTwoTanks")
.WithCompound("Water")
.WithPropertyPackage(PropertyPackages.SteamTables))
feed = (fs2.AddMaterialStream("Inlet").At(Q.Celsius(25.0), Q.Pascal(130000.0))
.WithMassFlow(Q.KgPerSecond(10.0)).AsFlowSpec())
names = ["S-1", "S-A", "S-B", "S-2", "Outlet"]
s = {n: fs2.AddMaterialStream(n).AsPressureSpec() for n in names}
(fs2.AddValve("V-01").WithCalcMode(Valve.CalculationMode.Kv_Liquid).WithKv(100.0)
.WithOpeningPercent(50.0).ConnectFeed(feed).ConnectProduct(s["S-1"]))
(fs2.AddTank("T-00").WithVolume(Q.CubicMeters(2.0)).WithHeight(Q.Meters(2.0))
.ConnectFeed(s["S-1"]).ConnectProduct(s["S-A"]))
(fs2.AddValve("V-00").WithCalcMode(Valve.CalculationMode.Kv_Liquid).WithKv(330.0)
.WithOpeningKvRelationship().WithOpeningPercent(50.0) # fixed opening
.ConnectFeed(s["S-A"]).ConnectProduct(s["S-B"]))
t01 = (fs2.AddTank("T-01").WithVolume(Q.CubicMeters(2.0)).WithHeight(Q.Meters(2.0))
.ConnectFeed(s["S-B"]).ConnectProduct(s["S-2"]))
v02 = (fs2.AddValve("V-02").WithCalcMode(Valve.CalculationMode.Kv_Liquid).WithKv(400.0)
.WithOpeningKvRelationship().WithOpeningPercent(29.0)
.ConnectFeed(s["S-2"]).ConnectProduct(s["Outlet"]))
fs2.Solve()
s["Outlet"].Object.Phases[0].Properties.pressure = 101325.0
mpc2 = fs2.AddUnitOperation(ObjectType.Controller_MPC, "LC-MPC").Object.__implementation__
for var, obj, prop, units, low, high, target in (
(MPCVariable(), t01, "Liquid Level", "m", 0.9, 1.1, mpc2.ControlledVariables),
(MPCVariable(), v02, "PROP_VA_5", "", 0.0, 100.0, mpc2.ManipulatedVariables)):
var.ObjectID, var.Name, var.PropertyName, var.Units = obj.Object.Name, obj.Object.GraphicObject.Tag, prop, units
var.MinValue, var.MaxValue = low, high
target.Add(var)
model = StepResponseModel()
model.CVIndex, model.MVIndex, model.Integrating, model.Gain, model.TimeConstant = 0, 0, True, -0.0004, 0.0
mpc2.StepResponseModels.Add(model)
mpc2.SampleTime, mpc2.PredictionHorizon, mpc2.ControlHorizon, mpc2.MoveSuppressionWeight = 5.0, 30, 5, 0.1
dv = MPCVariable() # measured disturbance: the feed flow
dv.ObjectID, dv.Name = feed.Object.Name, "Inlet flow"
dv.PropertyName, dv.Units = "PROP_MS_2", "kg/s"
mpc2.DisturbanceVariables.Add(dv)
if feedforward:
dm = StepResponseModel() # level response to the feed: a ramp behind the lag of T-00
dm.CVIndex, dm.DVIndex = 0, 0
dm.Integrating = True
dm.Gain = 1.0 / 997.0 # m/s per kg/s into a 1 m2 tank
dm.TimeConstant = 115.0 # s, from an open-loop feed step: 63 % of T-00's outflow change
mpc2.DisturbanceModels.Add(dm)
(fs2.Dynamics.DefineIntegrator("Int1")
.WithIntegrationStep(TimeSpan.FromSeconds(5.0)).WithDuration(TimeSpan.FromMinutes(45.0))
.Monitor("T-01", "Liquid Level", "m", "level"))
(fs2.Dynamics.DefineEventSet("FeedStep")
.AddStepChange("Inlet", "PROP_MS_2", 15.0, Q.Seconds(1500.0), "kg/s", "feed 10 -> 15 kg/s"))
(fs2.Dynamics.DefineSchedule("Run").WithIntegrator("Int1").WithEventSet("FeedStep")
.UseCurrentStateAsInitial(True).MakeCurrent())
lv = fs2.RunDynamics("Run").Execute().GetSeries("level")
return max(abs(v - 1.0) for t, v in zip(lv.TimeSeconds, lv.Values) if t >= 1500.0)
print(f"Two tanks, peak level deviation after the feed step = {two_tanks(False):.3f} m without the "
f"disturbance model, {two_tanks(True):.3f} m with it")
Output
Level = 0.010 m at the start, 1.000 m before the step
Peak level after step = 1.080 m
Final level = 1.000 m
Valve opening = 28.8 % before, 43.3 % at the end
Two tanks, peak level deviation after the feed step = 0.027 m without the disturbance model, 0.009 m with it
DWSIM 10.2.11.0, generated 2026-10-08.
Properties¶
IDs accepted by GetPropertyValue, SetPropertyValue, the sensitivity analysis, the optimizer, the Adjust block and dynamic events. Units are SI; pass another unit system to GetPropertyValue to get them converted.
| ID | Name | Unit (SI) | Input |
|---|---|---|---|
Prediction Horizon |
yes | ||
Control Horizon |
yes | ||
Sample Time |
s | yes | |
Move Suppression Weight |
yes | ||
Active |
yes | ||
Use Measured Disturbances |
yes |
Learn more¶
-
User guide
API members¶
Public members declared by this class. Inherited members are documented on the base classes.
Constructors¶
MPCController(): Initializes a new default instance of the MPCController class.
Initializes a new default instance of the MPCController class.
MPCController(string, string): Initializes a new instance of the MPCController class with a name and description.
Initializes a new instance of the MPCController class with a name and description.
| Parameter | Type | Description |
|---|---|---|
name |
String |
The name of this controller. |
description |
String |
A brief description of this controller. |
Properties¶
Active: Gets or sets whether the controller acts during a dynamic run.
Gets or sets whether the controller acts during a dynamic run. The integrator skips an inactive controller. Default True.
ControlHorizon: Control horizon M, in samples: the number of future moves computed for each manipulated variable (only the first is...
Control horizon M, in samples: the number of future moves computed for each manipulated variable (only the first is applied). Limited to the prediction horizon. Default 5.
ControlledVariables: Controlled variables.
Controlled variables. Each one is driven to the middle of its range (MinValue + MaxValue) / 2, with its Weight in the objective.
CVHistory: Controlled variable values recorded at each control step, one array per step in the variables' units, for the trend...
Controlled variable values recorded at each control step, one array per step in the variables' units, for the trend charts.
DisturbanceModels: Disturbance models, one per controlled/disturbance variable pair, indexed by CVIndex and DVIndex in the variable...
Disturbance models, one per controlled/disturbance variable pair, indexed by CVIndex and DVIndex in the variable lists: the response of the controlled variable to a unit step in the measured disturbance, first order plus dead time or integrating. The disturbance is taken as constant over the prediction horizon. An empty list leaves the controller as it is without disturbances.
DisturbanceVariables: Measured disturbance variables.
Measured disturbance variables. The controller reads them at each control step; a disturbance with a model in DisturbanceModels acts as feedforward, its change since the last step entering the predicted trajectory of the controlled variable as a manipulated variable move does. MinValue, MaxValue and Weight are not used.
DVHistory: Measured disturbance values recorded at each control step, one array per step in the variables' units, for the trend...
Measured disturbance values recorded at each control step, one array per step in the variables' units, for the trend charts. Recorded only when the controller has disturbance variables.
ExecutionOrder: Position of this controller in the order the dynamic integrator runs the MPC controllers, in ascending order.
Position of this controller in the order the dynamic integrator runs the MPC controllers, in ascending order. Default 0.
ManipulatedVariables: Manipulated variables moved by the controller, each clamped to its MinValue and MaxValue.
Manipulated variables moved by the controller, each clamped to its MinValue and MaxValue.
MobileCompatible: Gets a value indicating whether this controller is compatible with mobile interfaces.
Gets a value indicating whether this controller is compatible with mobile interfaces. Always False.
MoveSuppressionWeight: Move suppression weight (lambda), dimensionless.
Move suppression weight (lambda), dimensionless. It is scaled by the mean diagonal of each manipulated variable's block of the dynamic matrix; larger values give smaller, smoother moves. Default 0.1.
MVHistory: Manipulated variable values recorded at each control step, one array per step in the variables' units, for the trend...
Manipulated variable values recorded at each control step, one array per step in the variables' units, for the trend charts.
ObjectClass: Gets or sets the simulation object class, which is always Logical for special operations.
Gets or sets the simulation object class, which is always Logical for special operations.
PredictionHorizon: Prediction horizon P, in samples: the number of future samples over which the controlled variable error is minimized.
Prediction horizon P, in samples: the number of future samples over which the controlled variable error is minimized. Default 30.
SampleTime: Control interval, in s.
Control interval, in s. In dynamic mode the controller acts every n-th call, with n the sample time divided by the integrator call interval, rounded and at least 1. Default 1.
StepResponseModels: Step response models, one per controlled/manipulated variable pair, indexed by CVIndex and MVIndex in the variable...
Step response models, one per controlled/manipulated variable pair, indexed by CVIndex and MVIndex in the variable lists.
UseMeasuredDisturbances: Gets or sets whether the disturbance models act as feedforward.
Gets or sets whether the disturbance models act as feedforward. With False the controller still reads and records the disturbances but predicts as if it had no disturbance models. Default True.
Methods¶
Calculate(object): Dynamic Matrix Control.
Dynamic Matrix Control. At each control step the predicted CV trajectory is shifted one sample, updated with the MV moves measured since the last step and moved onto the current measurement (model error correction). The first of the M moves that minimize the weighted squared error over P samples plus the move suppression term is applied, within the MV limits. For an integrating CV the model error is also extrapolated as a ramp, which removes the offset a load change leaves. The changes of the measured disturbances that have a disturbance model enter the prediction the same way as the MV moves (feedforward).
| Parameter | Type | Description |
|---|---|---|
args |
Object |
CloneXML(): Creates a deep copy of this object by round-tripping through XML serialization.
Creates a deep copy of this object by round-tripping through XML serialization.
CloseEditForm(): Closes the editor of this object, if it is open.
Closes the editor of this object, if it is open.
DisplayEditForm(): Opens the editor of this object.
Opens the editor of this object. A host that has no editor for it does nothing.
GetChartModel(string): Builds the trend chart with the given name.
Builds the trend chart with the given name.
| Parameter | Type | Description |
|---|---|---|
name |
String |
The chart name: "CV Trends" (also used for an empty name), "MV Trends" or "DV Trends". |
GetChartModelNames(): Returns the names of the charts this controller can embed in the flowsheet.
Returns the names of the charts this controller can embed in the flowsheet.
GetDisplayDescription(): Returns the description string for this controller type.
Returns the description string for this controller type.
GetDisplayName(): Returns the display name for this controller type.
Returns the display name for this controller type.
GetEditingForm(): The editor window of this object, a window of the host's UI framework.
The editor window of this object, a window of the host's UI framework.
GetIconBitmapBytes(): Returns the raw bytes of the icon image for this controller.
Returns the raw bytes of the icon image for this controller.
GetProperties(PropertyType): Get a list of all properties of the object.
Get a list of all properties of the object.
| Parameter | Type | Description |
|---|---|---|
proptype |
PropertyType |
Type of the property. |
GetPropertyUnit(string, IUnitsOfMeasure): Gets the units of a property.
Gets the units of a property.
| Parameter | Type | Description |
|---|---|---|
prop |
String |
Property identifier. |
su |
IUnitsOfMeasure |
Units system to use. Null to use the default (SI) system. |
GetPropertyValue(string, IUnitsOfMeasure): Gets the value of a property.
Gets the value of a property.
| Parameter | Type | Description |
|---|---|---|
prop |
String |
Property identifier. |
su |
IUnitsOfMeasure |
Units system to use. Null to use the default (SI) system. |
InitializeModels(): Regenerates the step response coefficients of every model, disturbance models included, from its gain, time constant...
Regenerates the step response coefficients of every model, disturbance models included, from its gain, time constant and dead time, at the current sample time and a length that covers the prediction horizon and the settling of each model.
LoadData(List<XElement>): Loads object data stored in a collection of XML elements.
Loads object data stored in a collection of XML elements.
| Parameter | Type | Description |
|---|---|---|
data |
List<XElement> |
Reset(): Clears the controller state: the predicted trajectories, the last moves, the cached model and tuning, the call...
Clears the controller state: the predicted trajectories, the last moves, the cached model and tuning, the call counter, the histories and the last values of the variables.
SaveData(): Saves object data in a collection of XML elements.
Saves object data in a collection of XML elements.
SetPropertyValue(string, object, IUnitsOfMeasure): Sets the value of a property.
Sets the value of a property.
| Parameter | Type | Description |
|---|---|---|
prop |
String |
Property identifier. |
propval |
Object |
Property value to set at the specified units. |
su |
IUnitsOfMeasure |
Units system to use. Null to use the default (SI) system. |