PID Controller¶
![]()
Proportional-integral-derivative (PID) feedback controller for dynamic simulations. At each control step it reads the controlled (process) variable of one flowsheet object, compares it with the setpoint and writes a new value to the manipulated variable of another object. Supports manual override, cascade control, feedforward from a measured disturbance and integral anti-windup.
DWSIM.UnitOperations.SpecialOps.PIDController
Assembly DWSIM.UnitOperations.dll · Object ← BaseClass ← SpecialOpBaseClass ← PIDController
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("PIDExample")
.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))
(fs.AddTank("T-01").WithVolume(Q.CubicMeters(2.0)).WithHeight(Q.Meters(2.0))
.ConnectFeed(s1).ConnectProduct(s2))
(fs.AddValve("V-02").WithCalcMode(Valve.CalculationMode.Kv_Liquid).WithKv(400.0)
.WithOpeningKvRelationship().WithOpeningPercent(50.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
lic = (fs.AddPIDController("LIC-01")
.Controls("T-01", "Liquid Level", "m") # process variable
.Manipulates("V-02", "PROP_VA_5", "") # outlet valve opening, %
.WithSetPoint(1.0)
.WithTuning(2.0, 0.1, 0.0)
.WithOutputLimits(0.0, 100.0)
.WithOffset(29.0)
.ReverseActing(True)) # level up -> open the valve more
lic.Object.ManipulatedVariableSpan = 100.0
(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")
print(f"Simulated time = {result.FinalTimeSeconds / 60.0:.0f} min in {result.Steps} steps")
Output
Level = 0.010 m at the start, 1.000 m before the step
Peak level after step = 1.062 m
Final level = 1.000 m
Valve opening = 28.8 % before, 43.3 % at the end
Simulated time = 20 min in 241 steps
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 |
|---|---|---|---|
Active |
yes | ||
ManualOverride |
Manual Override | yes | |
LastError |
Previous Error | yes | |
CurrentError |
Current Error | yes | |
CumulativeError |
Integral of the Error | yes | |
SetPointAbs |
Set Point | yes | |
Kp |
Proportional Gain (Kp) | yes | |
Ki |
Integral Gain (Ki) | yes | |
Kd |
Derivative Gain (Kd) | yes | |
Output |
Controller Output (normalized) | yes | |
OutputMin |
Controller Output Minimum | yes | |
OutputMax |
Controller Output Maximum | yes | |
OutputAbs |
Manipulated Variable Value | yes | |
Offset |
Manipulated Variable at Zero Output | yes | |
ManipulatedVariableSpan |
Manipulated Variable Span | yes |
Learn more¶
-
User guide
-
Tutorials
API members¶
Public members declared by this class. Inherited members are documented on the base classes.
Constructors¶
PIDController(): Initializes a new default instance of the PIDController class.
Initializes a new default instance of the PIDController class.
PIDController(string, string): Initializes a new instance of the PIDController class with a name and description.
Initializes a new instance of the PIDController 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.
CascadeMasterID: Name (ID) of the master PID controller of a cascade.
Name (ID) of the master PID controller of a cascade. When set, this controller takes its setpoint from the master's OutputAbs at every step. Empty (default) for no cascade.
ControlledObject: The flowsheet object whose property is controlled, linked when the flowsheet or the graphic connects it.
The flowsheet object whose property is controlled, linked when the flowsheet or the graphic connects it. The calculation resolves the object from ControlledObjectData. Not serialized.
ControlledVariable: Name of the controlled property.
Name of the controlled property. The PID calculation does not read it; the property comes from ControlledObjectData.
CumulativeError: Running sum of the absolute normalized error, one term per control step, since the last reset.
Running sum of the absolute normalized error, one term per control step, since the last reset. Reported as the integral of the error.
CurrentError: Normalized error of the last control step, (PV - SP) / BaseSP, dimensionless.
Normalized error of the last control step, (PV - SP) / BaseSP, dimensionless.
CvOk: Flag indicating that the controlled variable is defined.
Flag indicating that the controlled variable is defined. The PID calculation does not use it.
DerivativeFilterCoefficient: Coefficient alpha of the first-order derivative filter, DTerm = alpha * DTerm_previous + (1 - alpha) * DTerm_raw.
Coefficient alpha of the first-order derivative filter, DTerm = alpha * DTerm_previous + (1 - alpha) * DTerm_raw. Values outside the open range (0, 1) disable the filter. Default 0.
DisturbanceObjectData: Measured disturbance for feedforward control: the object, property and units read at every step.
Measured disturbance for feedforward control: the object, property and units read at every step.
DTerm: Derivative of the last step, in 1/s: the rate of change of the normalized derivative error (PV -...
Derivative of the last step, in 1/s: the rate of change of the normalized derivative error (PV - SetpointWeightD * SP) / BaseSP, or of the negative normalized process variable when UseDerivativeOnPV is set, after the optional derivative filter.
ExecutionOrder: Position of this controller in the order the dynamic integrator runs the PID controllers, in ascending order.
Position of this controller in the order the dynamic integrator runs the PID controllers, in ascending order. Default 0.
FeedforwardGain: Feedforward gain, in manipulated variable units per disturbance unit, applied to the deviation of the disturbance...
Feedforward gain, in manipulated variable units per disturbance unit, applied to the deviation of the disturbance from its first reading after a reset, after the lead-lag of FeedforwardLeadTime and FeedforwardLagTime, and added to the manipulated variable value for as long as the deviation lasts. Zero (default) disables feedforward.
FeedforwardLagTime: Lag time constant, in s, of the feedforward lead-lag applied to the disturbance deviation before the feedforward gain.
Lag time constant, in s, of the feedforward lead-lag applied to the disturbance deviation before the feedforward gain. Zero or less disables the lag. Default 1.
FeedforwardLeadTime: Lead time constant, in s, of the feedforward lead-lag (FeedforwardLeadTime s + 1) /...
Lead time constant, in s, of the feedforward lead-lag (FeedforwardLeadTime s + 1) / (FeedforwardLagTime s + 1) applied to the disturbance deviation before the feedforward gain. Zero or less (default 0) leaves the plain lag.
InitialEstimate: Optional initial estimate of the manipulated variable.
Optional initial estimate of the manipulated variable. The PID calculation does not use it.
ITerm: Time integral of the normalized error, in seconds, accumulated since the last reset.
Time integral of the normalized error, in seconds, accumulated since the last reset. It is clamped by WindupGuard and held while the output sits at a limit.
Kd: Derivative gain, in s, applied to the rate of change of the normalized error (or of the process variable when...
Derivative gain, in s, applied to the rate of change of the normalized error (or of the process variable when UseDerivativeOnPV is set). Default 2.
Ki: Integral gain, in 1/s, applied to the time integral of the normalized error ITerm.
Integral gain, in 1/s, applied to the time integral of the normalized error ITerm. In the ISA form the integral time is Kp / Ki. Default 2.
Kp: Proportional gain, dimensionless, applied to the error normalized by the setpoint magnitude BaseSP.
Proportional gain, dimensionless, applied to the error normalized by the setpoint magnitude BaseSP. Default 10.
LastError: Normalized error of the previous control step, dimensionless.
Normalized error of the previous control step, dimensionless.
ManipulatedObject: The flowsheet object whose property the controller manipulates.
The flowsheet object whose property the controller manipulates. UpdateVars resolves it from ManipulatedObjectData at every step. Not serialized.
ManipulatedVariable: Name of the manipulated property.
Name of the manipulated property. The PID calculation does not read it; the property comes from ManipulatedObjectData.
ManipulatedVariableSpan: Range of the MANIPULATED variable, in its own units.
Range of the MANIPULATED variable, in its own units. Left at zero the controller keeps its original arithmetic, in which the output is scaled by the magnitude of the setpoint: OutputAbs = (1 -/+ Output) * |SP|. That only holds while the manipulated and the controlled variable are of the same order, which is true of a level held by a valve opening and false of, say, a flow held by a pressure setpoint, where the controller ends up with an authority of a few pascals and pins itself against a limit on the first step. Set to a positive value and the output rides on the manipulated variable's own scale: OutputAbs = Offset -/+ Output * Span, with Offset the MV at zero controller output. OutputMax - OutputMin is the natural value for it.
ManualOverride: When True the controller is in manual: it writes the operator's value MVValue to the manipulated object...
When True the controller is in manual: it writes the operator's value MVValue to the manipulated object and back-calculates Output from it. Returning to automatic sets the integral term so the output continues from the manual value. Default False.
MaximumIterations: Maximum number of iterations inherited from the adjust layout.
Maximum number of iterations inherited from the adjust layout. The PID calculation does not use it. Default 10.
MaxVal: Optional upper bound of the manipulated variable.
Optional upper bound of the manipulated variable. The PID calculation does not use it; the output limit is OutputMax.
MinVal: Optional lower bound of the manipulated variable.
Optional lower bound of the manipulated variable. The PID calculation does not use it; the output limit is OutputMin.
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.
MVHistory: Normalized controller output recorded at each control step, for the history chart.
Normalized controller output recorded at each control step, for the history chart. Not saved in the XML flowsheet file.
MvOk: Flag indicating that the manipulated variable is defined.
Flag indicating that the manipulated variable is defined. The PID calculation does not use it.
MVValue: Manipulated variable value, always in SI units: the value written to the manipulated object at the end of each step.
Manipulated variable value, always in SI units: the value written to the manipulated object at the end of each step. In manual mode it holds the operator's value. In automatic mode UpdateVars refreshes it from the manipulated object and the calculation replaces it with OutputAbs converted to SI. MVValueDisplay gives it in the manipulated variable's units.
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.
Offset: Manipulated variable value at zero controller output, in the manipulated variable's units.
Manipulated variable value at zero controller output, in the manipulated variable's units. With ManipulatedVariableSpan at zero it enters the normalized output as a bias of Offset / |SP|; with a positive span the manipulated variable is Offset -/+ Output * Span. Default 0.
Output: Normalized (dimensionless) controller output of the last step.
Normalized (dimensionless) controller output of the last step. It is converted into the manipulated variable value OutputAbs using the setpoint magnitude or ManipulatedVariableSpan.
OutputAbs: Manipulated variable value of the last step, in the manipulated variable's units, clamped to...
Manipulated variable value of the last step, in the manipulated variable's units, clamped to [OutputMin, OutputMax]. Setting it through SetPropertyValue also sets the value held in manual mode.
OutputMax: Upper limit of the manipulated variable value OutputAbs, in the manipulated variable's units.
Upper limit of the manipulated variable value OutputAbs, in the manipulated variable's units. Default 1000.
OutputMin: Lower limit of the manipulated variable value OutputAbs, in the manipulated variable's units.
Lower limit of the manipulated variable value OutputAbs, in the manipulated variable's units. Default -1000.
PIDForm: PID algorithm form, with Ti = Kp / Ki and Td = Kd / Kp.
PID algorithm form, with Ti = Kp / Ki and Td = Kd / Kp. 0 = parallel (default): Output = PTerm + Ki * ITerm + Kd * DTerm. 1 = ISA (standard, non-interacting): Output = Kp * (beta * e + ITerm / Ti + Td * DTerm). 2 = series (interacting), Kp * (1 + 1 / (Ti s)) * (1 + Td s): Output = Kp * ((1 + Td / Ti) * beta * e + ITerm / Ti + Td * DTerm), the same as the ISA form with Kp * (1 + Td / Ti), Ti + Td and Ti * Td / (Ti + Td). Any other value is calculated with the ISA form. Since Ti and Td are taken from Ki and Kd, the ISA output equals the parallel one and both are calculated as PTerm + Ki * ITerm + Kd * DTerm, which stays finite at Kp = 0.
PTerm: Proportional contribution of the last step: Kp * SetpointWeightP * CurrentError.
Proportional contribution of the last step: Kp * SetpointWeightP * CurrentError. In the series form (PIDForm = 2) it carries the interaction factor, Kp * (1 + Td / Ti) * SetpointWeightP * CurrentError.
PVHistory: Process variable values recorded at each control step, divided by BaseSP, for the history chart.
Process variable values recorded at each control step, divided by BaseSP, for the history chart. Not saved in the XML flowsheet file.
PVValue: Process (controlled) variable value read at the last update, in the controlled variable's units.
Process (controlled) variable value read at the last update, in the controlled variable's units.
ReferenceObject: Reference object, linked from ReferencedObjectData when the flowsheet loads.
Reference object, linked from ReferencedObjectData when the flowsheet loads. The PID calculation does not use it. Not serialized.
ReferenceVariable: Name of the reference property.
Name of the reference property. The PID calculation does not use it.
ReverseActing: Controller action.
Controller action. False (default): a process variable above the setpoint lowers the manipulated variable. True: a process variable above the setpoint raises it.
RvOk: Flag indicating that the reference variable is defined.
Flag indicating that the reference variable is defined. The PID calculation does not use it.
SetPoint: Gets or sets the controller setpoint, in the controlled variable's units.
Gets or sets the controller setpoint, in the controlled variable's units. Same value as AdjustValue.
SetpointWeightD: Setpoint weight (gamma) of the derivative term on error: the derivative acts on (PV - gamma * SP) / BaseSP.
Setpoint weight (gamma) of the derivative term on error: the derivative acts on (PV - gamma * SP) / BaseSP. At 1 (default) it is the derivative of the error, at 0 the derivative of the process variable alone, with no kick when the setpoint moves. Not used when UseDerivativeOnPV is set.
SetpointWeightP: Setpoint weight (beta) of the proportional term: PTerm = Kp * beta * CurrentError.
Setpoint weight (beta) of the proportional term: PTerm = Kp * beta * CurrentError. Default 1.
SPHistory: Setpoint values recorded at each control step, divided by BaseSP, for the history chart.
Setpoint values recorded at each control step, divided by BaseSP, for the history chart. Not saved in the XML flowsheet file.
SPValue: Setpoint value at the last update, in the controlled variable's units.
Setpoint value at the last update, in the controlled variable's units.
Status: Free-text status string.
Free-text status string. The PID calculation does not set it.
StepSize: Step size inherited from the adjust layout.
Step size inherited from the adjust layout. The PID calculation does not use it. Default 0.1.
SupportsDynamicMode: Gets a value indicating whether this controller runs in dynamic mode.
Gets a value indicating whether this controller runs in dynamic mode. Always True.
UseDerivativeOnPV: When True the derivative term acts on the rate of change of the process variable (derivative on measurement), which...
When True the derivative term acts on the rate of change of the process variable (derivative on measurement), which avoids a derivative kick when the setpoint changes. Default False (derivative on the error).
WindupGuard: Anti-windup limit: the integral term ITerm is clamped to the range [-WindupGuard, WindupGuard], in...
Anti-windup limit: the integral term ITerm is clamped to the range [-WindupGuard, WindupGuard], in normalized error times seconds. Default 20.
Methods¶
Calculate(object): Calculates the object.
Calculates the object.
| 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.
EstimateParameters(): Estimates starting values for the tuning from the current error and the current integrator time step: Kp and Kd are...
Estimates starting values for the tuning from the current error and the current integrator time step: Kp and Kd are set from the mid-point of the output range, and Ki is set to zero.
GetChartModel(string): Builds the history chart with the normalized setpoint, process variable and controller output per control step.
Builds the history chart with the normalized setpoint, process variable and controller output per control step.
| Parameter | Type | Description |
|---|---|---|
name |
String |
The chart name, shown as the subtitle ("History"). |
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 localized description string for this controller type.
Returns the localized description string for this controller type.
GetDisplayName(): Returns the localized display name for this controller type.
Returns the localized 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. |
GetPropertyDescription(string): Readable names for the property identifiers, which are the .NET property names.
Readable names for the property identifiers, which are the .NET property names.
| Parameter | Type | Description |
|---|---|---|
prop |
String |
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. |
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 P, I and D terms, the errors, the output, the derivative filter, the histories and...
Clears the controller state: the P, I and D terms, the errors, the output, the derivative filter, the histories and BaseSP. Tuning, limits and the setpoint are kept.
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. |
StartFromManipulatedVariable(): Resets the controller and makes its first step start from the manipulated variable as it is now: the output is read...
Resets the controller and makes its first step start from the manipulated variable as it is now: the output is read back from the valve opening (or whatever the controller moves) and the integral term is set to hold it, the same handover as leaving manual. A run that starts from a stored flowsheet state continues from the opening the state carries, whatever the tuning.
UpdateEditForm(): Redraws the editor of this object with the current values, if it is open.
Redraws the editor of this object with the current values, if it is open.
UpdateVars(): Reads the setpoint, the process variable and, in automatic mode, the manipulated variable from the flowsheet into...
Reads the setpoint, the process variable and, in automatic mode, the manipulated variable from the flowsheet into SPValue, PVValue (both in display units) and MVValue (in SI), and resolves ManipulatedObject. Leaves the values unchanged when the controller is not fully configured.
Fields¶
BaseSP: Setpoint magnitude |SP| captured at the first control step after a reset, used to normalize the error, the output...
Setpoint magnitude |SP| captured at the first control step after a reset, used to normalize the error, the output and the histories. Nothing until the first step.