Martin, C. and A. Urquia and S. Dormido (2005b): Modelado Orientado a Objetos de Laboratorios Virtuales con Aplicación a la Enseñanza de Control de Procesos Químicos. Proceedings of the 1st Congreso Español de Informática (CEDI-EIWISA).
Name | Description |
---|---|
![]() | Limit the range of a signal |
![]() | PID controller with limited output, anti-windup compensation and setpoint weighting |
PIDSteamPowerBoiler | Steam Power Boiler + 2 PID controllers |
PoleZeroSteamPowerBoiler | Steam power boiler + PID controller + compensator network |
steamPowerBoiler | Steam power boiler |
steamPowerBoilerIdentification | Steam power boiler model used for identification |
![]() | Steam power boiler plant. Inputs: heat flow set-point and input liquid flow set-point. Outputs: vapor flow and water volume |
The Limiter block passes its input signal as output signal as long as the input is within the specified upper and lower limits. If this is not the case, the corresponding limits are passed as output.
Type | Name | Default | Description |
---|---|---|---|
Real | uMax | 1 | Upper limits of input signals |
Real | uMin | -1 | Lower limits of input signals |
Type | Name | Description |
---|---|---|
input RealInput | u | Connector of Real input signal |
output RealOutput | y | Connector of Real output signal |
block Limiter "Limit the range of a signal" import Modelica.Blocks; import Modelica.SIunits; import Modelica.Blocks.Interfaces; parameter Real uMax=1 "Upper limits of input signals"; parameter Real uMin = -1 "Lower limits of input signals"; extends Interfaces.SISO; equation y = if u > uMax then uMax else if u < uMin then uMin else u; end Limiter;
This is a PID controller incorporating several practical aspects. It is designed according to chapter 3 of the book
K. Astroem, T. Haegglund: PID Controllers: Theory, Design, and Tuning. 2nd edition, 1995.
Besides the additive proportional, integral and derivative part of this controller, the following practical aspects are included:
Type | Name | Default | Description |
---|---|---|---|
Real | k | 1 | Gain of PID block |
Time | Ti | 0.5 | Time constant of Integrator block [s] |
Time | Td | 0.1 | Time constant of Derivative block [s] |
Real | yMax | 1 | Upper limit of output |
Real | yMin | 0 | Lower limit of output |
Real | wp | 1 | Set-point weight for Proportional block (0..1) |
Real | wd | 0 | Set-point weight for Derivative block (0..1) |
Real | Ni | 0.9 | Ni*Ti is time constant of anti-windup compensation |
Real | Nd | 10 | The higher Nd, the more ideal the derivative block |
Real | y_start | 0 |
Type | Name | Description |
---|---|---|
input RealInput | u_s | Connector of setpoint input signal |
input RealInput | u_m | Connector of measurement input signal |
output RealOutput | y | Connector of actuator output signal |
block LimPID "PID controller with limited output, anti-windup compensation and setpoint weighting" extends Interfaces.SVcontrol; import Modelica.Blocks; import Modelica.SIunits; import Modelica.Blocks.Interfaces; parameter Real k = 1 "Gain of PID block"; 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=1 "Upper limit of output"; parameter Real yMin=0 "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 Real y_start = 0; Limiter limiter(uMax=yMax, uMin=yMin); Blocks.Math.Add addP(k1=wp, k2=-1); Blocks.Math.Add addD(k1=wd, k2=-1); Blocks.Math.Gain P; Blocks.Continuous.Integrator I( y_start=y_start, k=(1/Ti)); Blocks.Continuous.Derivative D(T=(max([Td/Nd,1.e-14])), k=(Td)); Blocks.Math.Gain gainPID(k=(k)); Blocks.Math.Add3 addPID; Blocks.Math.Add3 addI(k2=-1, k3=1); Blocks.Math.Add addSat(k2=-1); Blocks.Math.Gain gainTrack(k=(1/(k*Ni))); equation assert(yMax >= yMin, "PID: Limits must be consistent"); connect(u_s, addP.u1); connect(u_m, addP.u2); connect(u_s, addD.u1); connect(u_m, addD.u2); connect(u_s, addI.u1); connect(u_m, addI.u2); connect(gainTrack.y, addI.u3); 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(addSat.y, gainTrack.u); connect(gainPID.y, limiter.u); connect(limiter.y, y); connect(limiter.y, addSat.u1); end LimPID;
model PIDSteamPowerBoiler "Steam Power Boiler + 2 PID controllers" steamPowerBoilerOpen steamPowerBoilerOpen1(tempWaterInitial=420); LimPID PID_Volume( Ti=9, Td=0.1, yMax=0.01, k=1, wd=1, yMin=-0.01, y_start=0); LimPID PID_flowVapor( Ti=1.1, Td=3e-2, k=7e6, yMax=5e6, yMin=0, wd=1, y_start=0); Modelica.Blocks.Sources.Pulse FlowVaporPulse( amplitude=0.5, offset=8, period=700, startTime=300); Modelica.Blocks.Sources.Pulse VolumePulse( amplitude=0.03, offset=1.6, period=350, startTime=50); equation connect(PID_flowVapor.y, steamPowerBoilerOpen1.heatFlowC); connect(PID_Volume.y, steamPowerBoilerOpen1.flowVSPC); connect(PID_Volume.u_m, steamPowerBoilerOpen1.waterVolumeC); connect(FlowVaporPulse.y,PID_flowVapor.u_s); connect(VolumePulse.y,PID_Volume.u_s); connect(PID_flowVapor.u_m, steamPowerBoilerOpen1.flowVaporC); end PIDSteamPowerBoiler;
model PoleZeroSteamPowerBoiler "Steam power boiler + PID controller + compensator network" steamPowerBoilerOpen steamPowerBoilerOpen1; Modelica.Blocks.Continuous.TransferFunction FlowVaporControl(b={44000000, 15000000}, a={7.87,1}); Modelica.Blocks.Math.Feedback Feedback1; Modelica.Blocks.Sources.Pulse FlowVaporPulse( amplitude=0.5, offset=8, period=700, startTime=300); LimPID PID_Volume( Ti=9, Td=0.1, yMax=0.01, k=1); Modelica.Blocks.Sources.Pulse VolumePulse( amplitude=0.03, offset=1.6, period=350, startTime=450); Limiter limiter(uMax=5e6, uMin=0); equation connect(Feedback1.y,FlowVaporControl.u); connect(steamPowerBoilerOpen1.flowVaporC,Feedback1.u2); connect(FlowVaporPulse.y,Feedback1.u1); connect(PID_Volume.y, steamPowerBoilerOpen1.flowVSPC); connect(VolumePulse.y,PID_Volume.u_s); connect(PID_Volume.u_m, steamPowerBoilerOpen1.waterVolumeC); connect(FlowVaporControl.y, limiter.u); connect(limiter.y, steamPowerBoilerOpen1.heatFlowC); end PoleZeroSteamPowerBoiler;
Type | Name | Default | Description |
---|---|---|---|
Boolean | Ejs | false | |
Boolean | Sysquake | true | |
Real | sectionInitial | 1 | Boiler cross-section [m2] |
Real | vesselVolumeInitial | 5.66 | Boiler volume [m3] |
Real | molVaporInitial[:] | {1200} | [mol] |
Real | tempVaporInitial | 700 | [K] |
Real | massWaterInitial[:] | {2840} | [Kg] |
Real | tempWaterInitial | 294 | [K] |
partial model steamPowerBoiler "Steam power boiler" // Interactivity inner parameter Boolean Ejs = false; inner parameter Boolean Sysquake = true; parameter Real sectionInitial( unit="m2") = 1 "Boiler cross-section"; parameter Real vesselVolumeInitial( unit="m3") = 5.66 "Boiler volume"; parameter Real molVaporInitial[:]( unit="mol") = {1200}; parameter Real tempVaporInitial( unit="K") = 700; parameter Real massWaterInitial[:]( unit="Kg") = {2840}; parameter Real tempWaterInitial( unit="K") = 294; // Input variables Real heatFlowSP; Real valveOpening( min=0, max=1); Real pressG_downStream( unit="M.L-1.t-2"); Real tempG_downStream( unit="T"); Real flowVSP_sourceLiqCntrl( unit="L3.t-1"); Real tempSP_sourceLiqCntrl( unit="T"); // Public variables Real vapor_mol; Real vapor_temp; Real vapor_pressure; Real vapor_volume; Real water_mass; Real water_temp; Real water_pressBottom; Real water_volume; Real boil_temp; Real boil_totalMassFlow; Real boil_totalMolFlow; Real boil_tempFlow; Real boil_massHeatPhaseChg; Real heatSource_heatFlow; Real valve_totalMolFlow; Real valve_tempFlow; Real liqSource_totalMassFlow; Real liqSource_totalMassFlowSP; Real liqSource_tempFlow; protected parameter Real perfGasConst( unit="J/(mol*K)") = 8.31 "Constant of the perfect gases"; parameter Real CpCoefML[1,7] = [ 4.18E3, 0, 0, 0, 0, 0, 0] "Heat capacity per mass unit of the liquid. [Cp]: J/(Kg*K)"; parameter Real CpCoefNG[1,7] = [ 55.486, 54.24E-3, 0, 0, 0, 0, 0] "Molar heat capacity, at constant pressure, of the vapor. [Cp]:J/(mol*K)"; parameter Real molecWeigth[:]( unit="Kg/mol") = {18E-3} "Molecular weigth of the water"; parameter Real density[:]( unit="Kg/m3") = {1E3} "Density of liquid water"; parameter Real molEnthalpyGRef[:]( unit="J/mol") = {-241.8322E3} "Reference molar enthalpy of the vapor"; parameter Real massEnthalpyLRef[:]( unit="J/Kg") = {- 15.88E6} "Reference enthalpy per mass unit of the liquid"; parameter Real tempRef( unit="K") = 298 "Enthalpy reference temperature"; parameter Real Kprop( unit="Kg/(s*K)") = 10 "Parameter of the boiling model"; parameter Real Kvalve( unit="mol/(s*N/m**2)") = ( 1.1E-7 / molecWeigth[1]) "Valve coefficient"; protected JARA2i.gas.semiPerfGasCp6B vapor( nComp=1,perfGasConst=perfGasConst,CpCoefN=CpCoefNG, tempRef=tempRef,molEnthalpyRef=molEnthalpyGRef, molGinitial=molVaporInitial,tempGinitial=tempVaporInitial); protected JARA2i.liq.liquidCp6B water( nComp=1,CpCoefMInitial=CpCoefML, massEnthalpyRefInitial = massEnthalpyLRef, tempRefInitial=tempRef,densityInitial=density, sectionInitial = sectionInitial, massLinitial=massWaterInitial,tempLinitial=tempWaterInitial, percentVolSmallStep=1.1); protected JARA2i.liq.vesselLiqB vessel( vesselVolumeInitial=vesselVolumeInitial); protected PhysicalModel.waterBoil boil( nComp=1,CpCoefML=CpCoefML,CpCoefNG=CpCoefNG,Kprop=Kprop, molecWeigth=molecWeigth,molEnthalpyGRef=molEnthalpyGRef, massEnthalpyLRef=massEnthalpyLRef,tempRef=tempRef); protected JARA2i.heat.sourceHeatFB heatSource( nComp=1); protected PhysicalModel.heatSourCntrl heatSourceCntrl; protected PhysicalModel.valve valveG( Kv=Kvalve,CpCoefN=CpCoefNG,molEnthalpyRef=molEnthalpyGRef, tempRef=tempRef); protected PhysicalModel.pressDownStream outValvePress; protected JARA2i.liq.sourceVolLiqFB liqSource( nComp=1, densityInitial=density, CpCoefMInitial=CpCoefML,tempRefInitial=tempRef,pmax=1E8, pcodo=9.5E7,pmin=100, peps=50, massEnthalpyRefInitial = massEnthalpyLRef); protected PhysicalModel.sourceLiqCntrl sourceLiqCtrl; equation // Input variables heatFlowSP = heatSourceCntrl.heatFlowSP; valveOpening = valveG.valveOpening; pressG_downStream = outValvePress.pressG; tempG_downStream = outValvePress.tempG; flowVSP_sourceLiqCntrl = sourceLiqCtrl.flowVSP; tempSP_sourceLiqCntrl = sourceLiqCtrl.tempSP; // Public variables vapor_mol = vapor.molG[1]; vapor_temp = vapor.tempG; vapor_pressure = vapor.inMol.pressG; vapor_volume = vapor.fluidV; water_mass = water.massL[1]; water_temp = water.tempL; water_pressBottom = water.inMassBot.pressL; water_volume = water.fluidV; boil_temp = boil.tempBoiling; boil_totalMassFlow = boil.totalMassF; boil_totalMolFlow = boil.totalMolF; boil_tempFlow = boil.tempF; boil_massHeatPhaseChg = boil.massHeatPhaseChg; heatSource_heatFlow = heatSource.inHeat.heatF; valve_totalMolFlow = valveG.totalMolF; valve_tempFlow = valveG.inHeat.tempF; liqSource_totalMassFlow = -liqSource.totalMassF; liqSource_totalMassFlowSP = liqSource.totalMassFSP; liqSource_tempFlow = liqSource.tempF; when water_volume>0.99*vesselVolumeInitial then terminate("Boiler full of water"); end when; // Mass flow connect( vapor.inMol, boil.outMol); connect( water.inMassTop, boil.inMass); connect( vapor.inMol, valveG.inMol); connect( outValvePress.inMol, valveG.outMol); connect( liqSource.inMass, water.inMassBot); connect( vapor.constraintV, vessel.constraintV); connect( water.constraintV, vessel.constraintV); connect( heatSource.inHeat, water.inHeat); connect( heatSource.setPointSignal, heatSourceCntrl.setPointSignal); connect( liqSource.setPointSignal, sourceLiqCtrl.setPointSignal); // Volume constraint // Heat flow // Control signals end steamPowerBoiler;
Type | Name | Default | Description |
---|---|---|---|
Real | VolumeControl | 0 | |
Real | AmpInit | 5.8e5 | |
Real | AmpFin | 6e5 | |
Real | tini | 9000 | |
Real | vesselVolume | 3 | [m3] |
Real | molVaporInitial | 700 | [mol] |
Real | tempVaporInitial | 450 | [K] |
Real | massWaterInitial | 1600 | [Kg] |
Real | tempWaterInitial | 420 | [K] |
Real | flowVSP_sourceLiqCntrlParam | 1.82e-4 | [L3.t-1] |
Real | heatFlowSPParam | 5.8e5 | |
Real | valveOpening | 0.7 | |
Real | pressG_downStream | 1.2e5 | [M.L-1.t-2] |
Real | tempG_downStream | 300 | [T] |
Real | tempSP_sourceLiqCntrl | 300 | [T] |
model steamPowerBoilerIdentification "Steam power boiler model used for identification" Real systemOutput; Real systemInput; parameter Real VolumeControl= 0; // parameter Real AmpInit= 1.779e-4; // parameter Real AmpFin= 1.9e-4; // parameter Real tini= 8000; parameter Real AmpInit= 5.8e5; parameter Real AmpFin = 6e5; parameter Real tini= 9000; //System Parameters parameter Real vesselVolume( unit="m3") = 3; //Working Conditions parameter Real molVaporInitial( unit="mol") = 700; parameter Real tempVaporInitial( unit="K") = 450; parameter Real massWaterInitial( unit="Kg") = 1600; parameter Real tempWaterInitial( unit="K") = 420; //Input Variables Real heatFlowSP; Real flowVSP_sourceLiqCntrl( unit="L3.t-1"); parameter Real flowVSP_sourceLiqCntrlParam( unit="L3.t-1") = 1.82e-4; parameter Real heatFlowSPParam = 5.8e5; parameter Real valveOpening( min=0, max=1)= 0.7; parameter Real pressG_downStream( unit="M.L-1.t-2")= 1.2e5; parameter Real tempG_downStream( unit="T")= 300; parameter Real tempSP_sourceLiqCntrl( unit="T")= 300; protected parameter Real molVaporInitialV[:]( unit="mol") = {molVaporInitial}; parameter Real massWaterInitialV[:]( unit="Kg") = {massWaterInitial}; steamPowerBoiler Planta(vesselVolumeInitial = vesselVolume, molVaporInitial=molVaporInitialV, tempVaporInitial = tempVaporInitial, massWaterInitial = massWaterInitialV, tempWaterInitial = tempWaterInitial); equation heatFlowSP = if (VolumeControl <0.5) then systemInput else heatFlowSPParam; flowVSP_sourceLiqCntrl = if (VolumeControl >0.5) then systemInput else flowVSP_sourceLiqCntrlParam; systemInput =if (time<tini) then AmpInit else AmpFin; Planta.heatFlowSP = heatFlowSP; Planta.valveOpening = valveOpening; Planta.pressG_downStream = pressG_downStream; Planta.tempG_downStream = tempG_downStream; Planta.flowVSP_sourceLiqCntrl = flowVSP_sourceLiqCntrl; Planta.tempSP_sourceLiqCntrl = tempSP_sourceLiqCntrl; systemOutput = if (VolumeControl <0.5) then Planta.valve_totalMolFlow else Planta.water_volume; end steamPowerBoilerIdentification;
Type | Name | Default | Description |
---|---|---|---|
Real | vesselVolume | 3 | [m3] |
Real | molVaporInitial | 700 | [mol] |
Real | tempVaporInitial | 450 | [K] |
Real | massWaterInitial | 1600 | [Kg] |
Real | tempWaterInitial | 300 | [K] |
Real | valveOpening | 0.7 | |
Real | pressG_downStream | 1.2e5 | [M.L-1.t-2] |
Real | tempG_downStream | 300 | [T] |
Real | tempSP_sourceLiqCntrl | 300 | [T] |
Type | Name | Description |
---|---|---|
input RealInput | heatFlowC | Connector of Real input signal |
input RealInput | flowVSPC | Connector of Real input signal |
output RealOutput | flowVaporC | Connector of actuator output signal |
output RealOutput | waterVolumeC | Connector of actuator output signal |
model steamPowerBoilerOpen "Steam power boiler plant. Inputs: heat flow set-point and input liquid flow set-point. Outputs: vapor flow and water volume" //System Parameters parameter Real vesselVolume( unit="m3") = 3; //Working Conditions parameter Real molVaporInitial( unit="mol") = 700; parameter Real tempVaporInitial( unit="K") = 450; parameter Real massWaterInitial( unit="Kg") = 1600; parameter Real tempWaterInitial( unit="K") = 300; //Output Variables Real water_volume; Real flowVapor; //Input Variables Real heatFlowSP; Real flowVSP_sourceLiqCntrl; parameter Real valveOpening( min=0, max=1)= 0.7; parameter Real pressG_downStream( unit="M.L-1.t-2")= 1.2e5; parameter Real tempG_downStream( unit="T")= 300; parameter Real tempSP_sourceLiqCntrl( unit="T")= 300; Modelica.Blocks.Interfaces.RealInput heatFlowC "Connector of Real input signal"; Modelica.Blocks.Interfaces.RealInput flowVSPC "Connector of Real input signal"; Modelica.Blocks.Interfaces.RealOutput flowVaporC "Connector of actuator output signal"; Modelica.Blocks.Interfaces.RealOutput waterVolumeC "Connector of actuator output signal"; protected parameter Real molVaporInitialV[:]( unit="mol") = {molVaporInitial}; parameter Real massWaterInitialV[:]( unit="Kg") = {massWaterInitial}; steamPowerBoiler Planta(vesselVolumeInitial = vesselVolume, molVaporInitial=molVaporInitialV, tempVaporInitial = tempVaporInitial, massWaterInitial = massWaterInitialV, tempWaterInitial = tempWaterInitial); equation heatFlowSP = Planta.heatFlowSP; flowVSP_sourceLiqCntrl =Planta.flowVSP_sourceLiqCntrl; flowVapor = Planta.valve_totalMolFlow; water_volume = Planta.water_volume; Planta.heatFlowSP=heatFlowC; Planta.flowVSP_sourceLiqCntrl=-flowVSPC; Planta.valve_totalMolFlow =flowVaporC; Planta.water_volume =waterVolumeC; Planta.valveOpening = valveOpening; Planta.pressG_downStream = pressG_downStream; Planta.tempG_downStream = tempG_downStream; Planta.tempSP_sourceLiqCntrl = tempSP_sourceLiqCntrl; end steamPowerBoilerOpen;