| 1 | within Modelica.Media; |
|---|
| 2 | package Air "Medium models for air" |
|---|
| 3 | |
|---|
| 4 | package SimpleAir "Air: Simple dry air model (0..100 degC)" |
|---|
| 5 | |
|---|
| 6 | extends Interfaces.PartialSimpleIdealGasMedium( |
|---|
| 7 | mediumName="SimpleAir", |
|---|
| 8 | cp_const=1005.45, |
|---|
| 9 | MM_const=0.0289651159, |
|---|
| 10 | R_gas=Constants.R/0.0289651159, |
|---|
| 11 | eta_const=1.82e-5, |
|---|
| 12 | lambda_const=0.026, |
|---|
| 13 | T_min=Cv.from_degC(0), |
|---|
| 14 | T_max=Cv.from_degC(100)); |
|---|
| 15 | |
|---|
| 16 | import SI = Modelica.SIunits; |
|---|
| 17 | import Cv = Modelica.SIunits.Conversions; |
|---|
| 18 | import Modelica.Constants; |
|---|
| 19 | |
|---|
| 20 | constant FluidConstants[nS] fluidConstants= |
|---|
| 21 | FluidConstants(iupacName={"simple air"}, |
|---|
| 22 | casRegistryNumber={"not a real substance"}, |
|---|
| 23 | chemicalFormula={"N2, O2"}, |
|---|
| 24 | structureFormula={"N2, O2"}, |
|---|
| 25 | molarMass=Modelica.Media.IdealGases.Common.SingleGasesData.N2.MM) |
|---|
| 26 | "constant data for the fluid"; |
|---|
| 27 | |
|---|
| 28 | annotation (Documentation(info="<html> |
|---|
| 29 | <h4>Simple Ideal gas air model for low temperatures</h4> |
|---|
| 30 | <p>This model demonstrats how to use the PartialSimpleIdealGas base class to build a |
|---|
| 31 | simple ideal gas model with a limited temperature validity range.</p> |
|---|
| 32 | </html>")); |
|---|
| 33 | end SimpleAir; |
|---|
| 34 | |
|---|
| 35 | package DryAirNasa "Air: Detailed dry air model as ideal gas (200..6000 K)" |
|---|
| 36 | extends IdealGases.Common.SingleGasNasa( |
|---|
| 37 | mediumName="Air", |
|---|
| 38 | data=IdealGases.Common.SingleGasesData.Air, |
|---|
| 39 | fluidConstants={IdealGases.Common.FluidData.N2}); |
|---|
| 40 | annotation ( Documentation(info="<HTML> |
|---|
| 41 | <IMG SRC=\"../Images/Media/IdealGases/SingleGases/Air.png\"></HTML>")); |
|---|
| 42 | |
|---|
| 43 | import Cv = Modelica.SIunits.Conversions; |
|---|
| 44 | |
|---|
| 45 | redeclare function dynamicViscosity |
|---|
| 46 | "Simple polynomial for dry air (moisture influence small), valid from 73.15 K to 373.15 K" |
|---|
| 47 | extends Modelica.Icons.Function; |
|---|
| 48 | input ThermodynamicState state "Thermodynamic state record"; |
|---|
| 49 | output DynamicViscosity eta "Dynamic viscosity"; |
|---|
| 50 | algorithm |
|---|
| 51 | eta := Incompressible.TableBased.Polynomials_Temp.evaluate({(-4.96717436974791E-011), 5.06626785714286E-008, 1.72937731092437E-005}, Cv.to_degC(state.T)); |
|---|
| 52 | annotation (Documentation(info="<html> |
|---|
| 53 | Dynamic viscosity is computed from temperature using a second order polynomial with a range of validity between 73 and 373 K. |
|---|
| 54 | </html>")); |
|---|
| 55 | end dynamicViscosity; |
|---|
| 56 | |
|---|
| 57 | redeclare function thermalConductivity |
|---|
| 58 | "Simple polynomial for dry air (moisture influence small), valid from 73.15 K to 373.15 K" |
|---|
| 59 | extends Modelica.Icons.Function; |
|---|
| 60 | input ThermodynamicState state "Thermodynamic state record"; |
|---|
| 61 | input Integer method=1 "Dummy for compatibility reasons"; |
|---|
| 62 | output ThermalConductivity lambda "Thermal conductivity"; |
|---|
| 63 | algorithm |
|---|
| 64 | lambda := Incompressible.TableBased.Polynomials_Temp.evaluate({(-4.8737307422969E-008), 7.67803133753502E-005, 0.0241814385504202},Cv.to_degC(state.T)); |
|---|
| 65 | |
|---|
| 66 | annotation (Documentation(info="<html> |
|---|
| 67 | Thermal conductivity is computed from temperature using a second order polynomial with a range of validity between 73 and 373 K. |
|---|
| 68 | </html>")); |
|---|
| 69 | end thermalConductivity; |
|---|
| 70 | |
|---|
| 71 | annotation (Documentation(info="<html> |
|---|
| 72 | Ideal gas medium model for dry air based on the package <a href=Modelica:Modelica.Media.IdealGases>IdealGases</a> with additional functions for dynamic viscosity and thermal conductivity in a limited temperature range. |
|---|
| 73 | </html>")); |
|---|
| 74 | end DryAirNasa; |
|---|
| 75 | |
|---|
| 76 | package MoistAir "Air: Moist air model (240 ... 400 K)" |
|---|
| 77 | extends Interfaces.PartialCondensingGases( |
|---|
| 78 | mediumName="Moist air", |
|---|
| 79 | substanceNames={"water", "air"}, |
|---|
| 80 | final reducedX=true, |
|---|
| 81 | final singleState=false, |
|---|
| 82 | reference_X={0.01,0.99}, |
|---|
| 83 | fluidConstants = {IdealGases.Common.FluidData.H2O,IdealGases.Common.FluidData.N2}); |
|---|
| 84 | |
|---|
| 85 | constant Integer Water=1 |
|---|
| 86 | "Index of water (in substanceNames, massFractions X, etc.)"; |
|---|
| 87 | constant Integer Air=2 |
|---|
| 88 | "Index of air (in substanceNames, massFractions X, etc.)"; |
|---|
| 89 | // constant SI.Pressure psat_low=saturationPressureWithoutLimits(200.0); |
|---|
| 90 | // constant SI.Pressure psat_high=saturationPressureWithoutLimits(422.16); |
|---|
| 91 | constant Real k_mair = steam.MM/dryair.MM "ratio of molar weights"; |
|---|
| 92 | |
|---|
| 93 | constant IdealGases.Common.DataRecord dryair = IdealGases.Common.SingleGasesData.Air; |
|---|
| 94 | constant IdealGases.Common.DataRecord steam = IdealGases.Common.SingleGasesData.H2O; |
|---|
| 95 | constant SI.MolarMass[2] MMX = {steam.MM,dryair.MM} |
|---|
| 96 | "Molar masses of components"; |
|---|
| 97 | |
|---|
| 98 | import Modelica.Media.Interfaces; |
|---|
| 99 | import Modelica.Math; |
|---|
| 100 | import SI = Modelica.SIunits; |
|---|
| 101 | import Cv = Modelica.SIunits.Conversions; |
|---|
| 102 | import Modelica.Constants; |
|---|
| 103 | import Modelica.Media.IdealGases.Common.SingleGasNasa; |
|---|
| 104 | |
|---|
| 105 | redeclare record extends ThermodynamicState |
|---|
| 106 | "ThermodynamicState record for moist air" |
|---|
| 107 | end ThermodynamicState; |
|---|
| 108 | |
|---|
| 109 | redeclare replaceable model extends BaseProperties( |
|---|
| 110 | T(stateSelect=if preferredMediumStates then StateSelect.prefer else StateSelect.default), |
|---|
| 111 | p(stateSelect=if preferredMediumStates then StateSelect.prefer else StateSelect.default), |
|---|
| 112 | Xi(stateSelect=if preferredMediumStates then StateSelect.prefer else StateSelect.default), |
|---|
| 113 | redeclare final constant Boolean standardOrderComponents=true) |
|---|
| 114 | "Moist air base properties record" |
|---|
| 115 | |
|---|
| 116 | /* p, T, X = X[Water] are used as preferred states, since only then all |
|---|
| 117 | other quantities can be computed in a recursive sequence. |
|---|
| 118 | If other variables are selected as states, static state selection |
|---|
| 119 | is no longer possible and non-linear algebraic equations occur. |
|---|
| 120 | */ |
|---|
| 121 | MassFraction x_water "Mass of total water/mass of dry air"; |
|---|
| 122 | Real phi "Relative humidity"; |
|---|
| 123 | annotation(Documentation(info="<html> |
|---|
| 124 | This model computes thermodynamic properties of moist air from three independent (thermodynamic or/and numerical) state variables. Preferred numerical states are temperature T, pressure p and the reduced composition vector Xi, which contains the water mass fraction only. As an EOS the <b>ideal gas law</b> is used and associated restrictions apply. The model can also be used in the <b>fog region</b>, when moisture is present in its liquid state. However, it is assumed that the liquid water volume is negligible compared to that of the gas phase. Computation of thermal properties is based on property data of <a href=Modelica:Modelica.Media.Air.DryAirNasa> dry air</a> and water (source: VDI-Wärmeatlas), respectively. Besides the standard thermodynamic variables <b>absolute and relative humidity</b>, x_water and phi, respectively, are given by the model. Upper case X denotes absolute humidity with respect to mass of moist air while absolute humidity with respect to mass of dry air only is denoted by a lower case x throughout the model. See <a href=Modelica:Modelica.Media.Air.MoistAir>package description</a> for further information. |
|---|
| 125 | </html>")); |
|---|
| 126 | |
|---|
| 127 | protected |
|---|
| 128 | MassFraction X_liquid "Mass fraction of liquid or solid water"; |
|---|
| 129 | MassFraction X_steam "Mass fraction of steam water"; |
|---|
| 130 | MassFraction X_air "Mass fraction of air"; |
|---|
| 131 | MassFraction X_sat |
|---|
| 132 | "Steam water mass fraction of saturation boundary in kg_water/kg_moistair"; |
|---|
| 133 | MassFraction x_sat |
|---|
| 134 | "Steam water mass content of saturation boundary in kg_water/kg_dryair"; |
|---|
| 135 | AbsolutePressure p_steam_sat "Partial saturation pressure of steam"; |
|---|
| 136 | equation |
|---|
| 137 | assert(T >= 200.0 and T <= 423.15, " |
|---|
| 138 | Temperature T is not in the allowed range |
|---|
| 139 | 200.0 K <= (T =" + String(T) + " K) <= 423.15 K |
|---|
| 140 | required from medium model \"" + mediumName + "\"."); |
|---|
| 141 | MM = 1/(Xi[Water]/MMX[Water]+(1.0-Xi[Water])/MMX[Air]); |
|---|
| 142 | |
|---|
| 143 | p_steam_sat = min(saturationPressure(T),0.999*p); |
|---|
| 144 | X_sat = min(p_steam_sat * k_mair/max(100*Constants.eps, p - p_steam_sat)*(1 - Xi[Water]), 1.0) |
|---|
| 145 | "Water content at saturation with respect to actual water content"; |
|---|
| 146 | X_liquid = max(Xi[Water] - X_sat, 0.0); |
|---|
| 147 | X_steam = Xi[Water]-X_liquid; |
|---|
| 148 | X_air = 1-Xi[Water]; |
|---|
| 149 | |
|---|
| 150 | h = specificEnthalpy_pTX(p,T,Xi); |
|---|
| 151 | R = dryair.R*(X_air/(1 - X_liquid)) + steam.R*X_steam/(1 - X_liquid); |
|---|
| 152 | // |
|---|
| 153 | u = h - R*T; |
|---|
| 154 | d = p/(R*T); |
|---|
| 155 | /* Note, u and d are computed under the assumption that the volume of the liquid |
|---|
| 156 | water is neglible with respect to the volume of air and of steam |
|---|
| 157 | */ |
|---|
| 158 | state.p = p; |
|---|
| 159 | state.T = T; |
|---|
| 160 | state.X = X; |
|---|
| 161 | |
|---|
| 162 | // these x are per unit mass of DRY air! |
|---|
| 163 | x_sat = k_mair*p_steam_sat/max(100*Constants.eps,p - p_steam_sat); |
|---|
| 164 | x_water = Xi[Water]/max(X_air,100*Constants.eps); |
|---|
| 165 | phi = p/p_steam_sat*Xi[Water]/(Xi[Water] + k_mair*X_air); |
|---|
| 166 | end BaseProperties; |
|---|
| 167 | |
|---|
| 168 | redeclare function setState_pTX |
|---|
| 169 | "Return thermodynamic state as function of pressure p, temperature T and composition X" |
|---|
| 170 | extends Modelica.Icons.Function; |
|---|
| 171 | input AbsolutePressure p "Pressure"; |
|---|
| 172 | input Temperature T "Temperature"; |
|---|
| 173 | input MassFraction X[:]=reference_X "Mass fractions"; |
|---|
| 174 | output ThermodynamicState state "Thermodynamic state"; |
|---|
| 175 | algorithm |
|---|
| 176 | state := if size(X,1) == nX then ThermodynamicState(p=p,T=T, X=X) else |
|---|
| 177 | ThermodynamicState(p=p,T=T, X=cat(1,X,{1-sum(X)})); |
|---|
| 178 | annotation (Documentation(info="<html> |
|---|
| 179 | The <a href=Modelica:Modelica.Media.Air.MoistAir.ThermodynamicState>thermodynamic state record</a> is computed from pressure p, temperature T and composition X. |
|---|
| 180 | </html>")); |
|---|
| 181 | end setState_pTX; |
|---|
| 182 | |
|---|
| 183 | redeclare function setState_phX |
|---|
| 184 | "Return thermodynamic state as function of pressure p, specific enthalpy h and composition X" |
|---|
| 185 | extends Modelica.Icons.Function; |
|---|
| 186 | input AbsolutePressure p "Pressure"; |
|---|
| 187 | input SpecificEnthalpy h "Specific enthalpy"; |
|---|
| 188 | input MassFraction X[:]=reference_X "Mass fractions"; |
|---|
| 189 | output ThermodynamicState state "Thermodynamic state"; |
|---|
| 190 | algorithm |
|---|
| 191 | state := if size(X,1) == nX then ThermodynamicState(p=p,T=T_phX(p,h,X),X=X) else |
|---|
| 192 | ThermodynamicState(p=p,T=T_phX(p,h,X), X=cat(1,X,{1-sum(X)})); |
|---|
| 193 | annotation (Documentation(info="<html> |
|---|
| 194 | The <a href=Modelica:Modelica.Media.Air.MoistAir.ThermodynamicState>thermodynamic state record</a> is computed from pressure p, specific enthalpy h and composition X. |
|---|
| 195 | </html>")); |
|---|
| 196 | end setState_phX; |
|---|
| 197 | |
|---|
| 198 | redeclare function setState_dTX |
|---|
| 199 | "Return thermodynamic state as function of density d, temperature T and composition X" |
|---|
| 200 | extends Modelica.Icons.Function; |
|---|
| 201 | input Density d "density"; |
|---|
| 202 | input Temperature T "Temperature"; |
|---|
| 203 | input MassFraction X[:]=reference_X "Mass fractions"; |
|---|
| 204 | output ThermodynamicState state "Thermodynamic state"; |
|---|
| 205 | algorithm |
|---|
| 206 | state := if size(X,1) == nX then ThermodynamicState(p=d*({steam.R,dryair.R}*X)*T,T=T,X=X) else |
|---|
| 207 | ThermodynamicState(p=d*({steam.R,dryair.R}*cat(1,X,{1-sum(X)}))*T,T=T, X=cat(1,X,{1-sum(X)})); |
|---|
| 208 | annotation (Documentation(info="<html> |
|---|
| 209 | The <a href=Modelica:Modelica.Media.Air.MoistAir.ThermodynamicState>thermodynamic state record</a> is computed from density d, temperature T and composition X. |
|---|
| 210 | </html>")); |
|---|
| 211 | end setState_dTX; |
|---|
| 212 | |
|---|
| 213 | function Xsaturation |
|---|
| 214 | "Return absolute humitity per unit mass of moist air at saturation as a function of the thermodynamic state record" |
|---|
| 215 | input ThermodynamicState state "Thermodynamic state record"; |
|---|
| 216 | output MassFraction X_sat "Steam mass fraction of sat. boundary"; |
|---|
| 217 | algorithm |
|---|
| 218 | X_sat := k_mair/(state.p/min(saturationPressure(state.T),0.999*state.p) - 1 + k_mair); |
|---|
| 219 | annotation (Documentation(info="<html> |
|---|
| 220 | Absolute humidity per unit mass of moist air at saturation is computed from pressure and temperature in the state record. Note, that unlike X_sat in the BaseProperties model this mass fraction refers to mass of moist air at saturation. |
|---|
| 221 | </html>")); |
|---|
| 222 | end Xsaturation; |
|---|
| 223 | |
|---|
| 224 | function xsaturation |
|---|
| 225 | "Return absolute humitity per unit mass of dry air at saturation as a function of the thermodynamic state record" |
|---|
| 226 | input ThermodynamicState state "Thermodynamic state record"; |
|---|
| 227 | output MassFraction x_sat "Absolute humidity per unit mass of dry air"; |
|---|
| 228 | algorithm |
|---|
| 229 | x_sat:=k_mair*saturationPressure(state.T)/max(100*Constants.eps,state.p - saturationPressure(state.T)); |
|---|
| 230 | annotation (Documentation(info="<html> |
|---|
| 231 | Absolute humidity per unit mass of dry air at saturation is computed from pressure and temperature in the thermodynamic state record. |
|---|
| 232 | </html>")); |
|---|
| 233 | end xsaturation; |
|---|
| 234 | |
|---|
| 235 | function xsaturation_pT |
|---|
| 236 | "Return absolute humitity per unit mass of dry air at saturation as a function of pressure p and temperature T" |
|---|
| 237 | input AbsolutePressure p "Pressure"; |
|---|
| 238 | input SI.Temperature T "Temperature"; |
|---|
| 239 | output MassFraction x_sat "Absolute humidity per unit mass of dry air"; |
|---|
| 240 | algorithm |
|---|
| 241 | x_sat:=k_mair*saturationPressure(T)/max(100*Constants.eps,p - saturationPressure(T)); |
|---|
| 242 | annotation (Documentation(info="<html> |
|---|
| 243 | Absolute humidity per unit mass of dry air at saturation is computed from pressure and temperature. |
|---|
| 244 | </html>")); |
|---|
| 245 | end xsaturation_pT; |
|---|
| 246 | |
|---|
| 247 | function massFraction_pTphi |
|---|
| 248 | "Return steam mass fraction as a function of relative humidity phi and temperature T" |
|---|
| 249 | input AbsolutePressure p "Pressure"; |
|---|
| 250 | input Temperature T "Temperature"; |
|---|
| 251 | input Real phi "Relative humidity (0 ... 1.0)"; |
|---|
| 252 | output MassFraction X_steam "Absolute humidity, steam mass fraction"; |
|---|
| 253 | protected |
|---|
| 254 | constant Real k = 0.621964713077499 "Ratio of molar masses"; |
|---|
| 255 | AbsolutePressure psat = saturationPressure(T) "Saturation pressure"; |
|---|
| 256 | algorithm |
|---|
| 257 | X_steam := phi*k/(k*phi+p/psat-phi); |
|---|
| 258 | annotation (Documentation(info="<html> |
|---|
| 259 | Absolute humidity per unit mass of moist air is computed from temperature, pressure and relative humidity. |
|---|
| 260 | </html>")); |
|---|
| 261 | end massFraction_pTphi; |
|---|
| 262 | |
|---|
| 263 | function relativeHumidity_pTX |
|---|
| 264 | "Return relative humidity as a function of pressure p, temperature T and composition X" |
|---|
| 265 | input SI.Pressure p "Pressure"; |
|---|
| 266 | input SI.Temperature T "Temperature"; |
|---|
| 267 | input SI.MassFraction[:] X "Composition"; |
|---|
| 268 | output Real phi "Relative humidity"; |
|---|
| 269 | protected |
|---|
| 270 | SI.Pressure p_steam_sat "Saturation pressure"; |
|---|
| 271 | SI.MassFraction X_air "Dry air mass fraction"; |
|---|
| 272 | algorithm |
|---|
| 273 | p_steam_sat :=min(saturationPressure(T), 0.999*p); |
|---|
| 274 | X_air :=1 - X[Water]; |
|---|
| 275 | phi :=max(0.0,min(1.0, p/p_steam_sat*X[Water]/(X[Water] + k_mair*X_air))); |
|---|
| 276 | annotation (Documentation(info="<html> |
|---|
| 277 | Relative humidity is computed from pressure, temperature and composition with 1.0 as the upper limit at saturation. Water mass fraction is the first entry in the composition vector. |
|---|
| 278 | </html>")); |
|---|
| 279 | end relativeHumidity_pTX; |
|---|
| 280 | |
|---|
| 281 | function relativeHumidity |
|---|
| 282 | "Return relative humidity as a function of the thermodynamic state record" |
|---|
| 283 | input ThermodynamicState state "Thermodynamic state"; |
|---|
| 284 | output Real phi "Relative humidity"; |
|---|
| 285 | algorithm |
|---|
| 286 | phi:=relativeHumidity_pTX(state.p, state.T, state.X); |
|---|
| 287 | annotation (Documentation(info="<html> |
|---|
| 288 | Relative humidity is computed from the thermodynamic state record with 1.0 as the upper limit at saturation. |
|---|
| 289 | </html>")); |
|---|
| 290 | end relativeHumidity; |
|---|
| 291 | |
|---|
| 292 | /* |
|---|
| 293 | redeclare function setState_psX "Return thermodynamic state as function of p, s and composition X" |
|---|
| 294 | extends Modelica.Icons.Function; |
|---|
| 295 | input AbsolutePressure p "Pressure"; |
|---|
| 296 | input SpecificEntropy s "Specific entropy"; |
|---|
| 297 | input MassFraction X[:]=reference_X "Mass fractions"; |
|---|
| 298 | output ThermodynamicState state; |
|---|
| 299 | algorithm |
|---|
| 300 | state := if size(X,1) == nX then ThermodynamicState(p=p,T=T_psX(s,p,X),X=X) |
|---|
| 301 | else ThermodynamicState(p=p,T=T_psX(p,s,X), X=cat(1,X,{1-sum(X)})); |
|---|
| 302 | end setState_psX; |
|---|
| 303 | */ |
|---|
| 304 | |
|---|
| 305 | redeclare function extends gasConstant |
|---|
| 306 | "Return ideal gas constant as a function from thermodynamic state, only valid for phi<1" |
|---|
| 307 | algorithm |
|---|
| 308 | R := dryair.R*(1-state.X[Water]) + steam.R*state.X[Water]; |
|---|
| 309 | annotation (Documentation(info="<html> |
|---|
| 310 | The ideal gas constant for moist air is computed from <a href=Modelica:Modelica.Media.Air.MoistAir.ThermodynamicState>thermodynamic state</a> assuming that all water is in the gas phase. |
|---|
| 311 | </html>")); |
|---|
| 312 | end gasConstant; |
|---|
| 313 | |
|---|
| 314 | function gasConstant_X |
|---|
| 315 | "Return ideal gas constant as a function from composition X" |
|---|
| 316 | input SI.MassFraction X[:] "Gas phase composition"; |
|---|
| 317 | output SI.SpecificHeatCapacity R "Ideal gas constant"; |
|---|
| 318 | algorithm |
|---|
| 319 | R := dryair.R*(1-X[Water]) + steam.R*X[Water]; |
|---|
| 320 | annotation (Documentation(info="<html> |
|---|
| 321 | The ideal gas constant for moist air is computed from the gas phase composition. The first entry in composition vector X is the steam mass fraction of the gas phase. |
|---|
| 322 | </html>")); |
|---|
| 323 | end gasConstant_X; |
|---|
| 324 | |
|---|
| 325 | function saturationPressureLiquid |
|---|
| 326 | "Return saturation pressure of water as a function of temperature T in the range of 273.16 to 373.16 K" |
|---|
| 327 | |
|---|
| 328 | extends Modelica.Icons.Function; |
|---|
| 329 | input SI.Temperature Tsat "saturation temperature"; |
|---|
| 330 | output SI.AbsolutePressure psat "saturation pressure"; |
|---|
| 331 | annotation(Inline=false,smoothOrder=5, |
|---|
| 332 | Documentation(derivative=saturationPressureLiquid_der,info="<html> |
|---|
| 333 | Saturation pressure of water above the triple point temperature is computed from temperature. It's range of validity is between |
|---|
| 334 | 273.16 and 373.16 K. Outside these limits a less accurate result is returned. |
|---|
| 335 | </html>")); |
|---|
| 336 | algorithm |
|---|
| 337 | psat := 611.657*Math.exp(17.2799 - 4102.99/(Tsat - 35.719)); |
|---|
| 338 | end saturationPressureLiquid; |
|---|
| 339 | |
|---|
| 340 | function saturationPressureLiquid_der |
|---|
| 341 | "Time derivative of saturationPressureLiquid" |
|---|
| 342 | |
|---|
| 343 | extends Modelica.Icons.Function; |
|---|
| 344 | input SI.Temperature Tsat "Saturation temperature"; |
|---|
| 345 | input Real dTsat(unit="K/s") "Saturation temperature derivative"; |
|---|
| 346 | output Real psat_der(unit="Pa/s") "Saturation pressure"; |
|---|
| 347 | annotation(Inline=false,smoothOrder=5, |
|---|
| 348 | Documentation(info="<html> |
|---|
| 349 | Derivative function of <a href=Modelica:Modelica.Media.Air.MoistAir.saturationPressureLiquid>saturationPressureLiquid</a> |
|---|
| 350 | </html>")); |
|---|
| 351 | algorithm |
|---|
| 352 | /*psat := 611.657*Math.exp(17.2799 - 4102.99/(Tsat - 35.719));*/ |
|---|
| 353 | psat_der:=611.657*Math.exp(17.2799 - 4102.99/(Tsat - 35.719))*4102.99*dTsat/(Tsat - 35.719)/(Tsat - 35.719); |
|---|
| 354 | |
|---|
| 355 | end saturationPressureLiquid_der; |
|---|
| 356 | |
|---|
| 357 | function sublimationPressureIce |
|---|
| 358 | "Return sublimation pressure of water as a function of temperature T between 223.16 and 273.16 K" |
|---|
| 359 | |
|---|
| 360 | extends Modelica.Icons.Function; |
|---|
| 361 | input SI.Temperature Tsat "sublimation temperature"; |
|---|
| 362 | output SI.AbsolutePressure psat "sublimation pressure"; |
|---|
| 363 | annotation(Inline=false,smoothOrder=5, |
|---|
| 364 | Documentation(derivative=sublimationPressureIce_der,info="<html> |
|---|
| 365 | Sublimation pressure of water below the triple point temperature is computed from temperature. It's range of validity is between |
|---|
| 366 | 223.16 and 273.16 K. Outside of these limits a less accurate result is returned. |
|---|
| 367 | </html>")); |
|---|
| 368 | algorithm |
|---|
| 369 | psat := 611.657*Math.exp(22.5159*(1.0 - 273.16/Tsat)); |
|---|
| 370 | end sublimationPressureIce; |
|---|
| 371 | |
|---|
| 372 | function sublimationPressureIce_der |
|---|
| 373 | "Derivative function for 'sublimationPressureIce'" |
|---|
| 374 | |
|---|
| 375 | extends Modelica.Icons.Function; |
|---|
| 376 | input SI.Temperature Tsat "Sublimation temperature"; |
|---|
| 377 | input Real dTsat(unit="K/s") "Time derivative of sublimation temperature"; |
|---|
| 378 | output Real psat_der(unit="Pa/s") "Sublimation pressure"; |
|---|
| 379 | annotation(Inline=false,smoothOrder=5, |
|---|
| 380 | Documentation(info="<html> |
|---|
| 381 | Derivative function of <a href=Modelica:Modelica.Media.Air.MoistAir.sublimationPressureIce>saturationPressureIce</a> |
|---|
| 382 | </html>")); |
|---|
| 383 | algorithm |
|---|
| 384 | /*psat := 611.657*Math.exp(22.5159*(1.0 - 273.16/Tsat));*/ |
|---|
| 385 | psat_der:=611.657*Math.exp(22.5159*(1.0 - 273.16/Tsat))*22.5159*273.16*dTsat/Tsat/Tsat; |
|---|
| 386 | end sublimationPressureIce_der; |
|---|
| 387 | |
|---|
| 388 | redeclare function extends saturationPressure |
|---|
| 389 | "Return saturation pressure of water as a function of temperature T between 223.16 and 373.16 K" |
|---|
| 390 | |
|---|
| 391 | annotation(Inline=false,smoothOrder=5, |
|---|
| 392 | Documentation(derivative=saturationPressure_der,info="<html> |
|---|
| 393 | Saturation pressure of water in the liquid and the solid region is computed using an Antoine-type correlation. It's range of validity is between 223.16 and 373.16 K. Outside of these limits a (less accurate) result is returned. Functions for the |
|---|
| 394 | <a href=Modelica.Media.Air.MoistAir.sublimationPressureIce>solid</a> and the <a href=\"Modelica.Media.MoistAir.saturationPressureLiquid\"> liquid</a> region, respectively, are combined using the first derivative continuous <a href=Modelica.Media.MoistAir.Utilities.spliceFunction>spliceFunction</a>. |
|---|
| 395 | </html>")); |
|---|
| 396 | algorithm |
|---|
| 397 | psat := Utilities.spliceFunction(saturationPressureLiquid(Tsat),sublimationPressureIce(Tsat),Tsat-273.16,1.0); |
|---|
| 398 | end saturationPressure; |
|---|
| 399 | |
|---|
| 400 | function saturationPressure_der |
|---|
| 401 | "Derivative function for 'saturationPressure'" |
|---|
| 402 | input Temperature Tsat "Saturation temperature"; |
|---|
| 403 | input Real dTsat(unit="K/s") "Time derivative of saturation temperature"; |
|---|
| 404 | output Real psat_der(unit="Pa/s") "Saturation pressure"; |
|---|
| 405 | annotation(Inline=false,smoothOrder=5, |
|---|
| 406 | Documentation(info="<html> |
|---|
| 407 | Derivative function of <a href=Modelica:Modelica.Media.Air.MoistAir.saturationPressure>saturationPressure</a> |
|---|
| 408 | </html>")); |
|---|
| 409 | |
|---|
| 410 | algorithm |
|---|
| 411 | /*psat := Utilities.spliceFunction(saturationPressureLiquid(Tsat),sublimationPressureIce(Tsat),Tsat-273.16,1.0);*/ |
|---|
| 412 | psat_der := Utilities.spliceFunction_der( |
|---|
| 413 | saturationPressureLiquid(Tsat), |
|---|
| 414 | sublimationPressureIce(Tsat), |
|---|
| 415 | Tsat - 273.16, |
|---|
| 416 | 1.0, |
|---|
| 417 | saturationPressureLiquid_der(Tsat=Tsat, dTsat=dTsat), |
|---|
| 418 | sublimationPressureIce_der(Tsat=Tsat, dTsat=dTsat), |
|---|
| 419 | dTsat, |
|---|
| 420 | 0); |
|---|
| 421 | end saturationPressure_der; |
|---|
| 422 | |
|---|
| 423 | function saturationTemperature |
|---|
| 424 | "Return saturation temperature of water as a function of (partial) pressure p" |
|---|
| 425 | |
|---|
| 426 | input SI.Pressure p "Pressure"; |
|---|
| 427 | input SI.Temperature T_min=200 "Lower boundary of solution"; |
|---|
| 428 | input SI.Temperature T_max=400 "Upper boundary of solution"; |
|---|
| 429 | output SI.Temperature T "Saturation temperature"; |
|---|
| 430 | |
|---|
| 431 | protected |
|---|
| 432 | package Internal |
|---|
| 433 | extends Modelica.Media.Common.OneNonLinearEquation; |
|---|
| 434 | |
|---|
| 435 | redeclare record extends f_nonlinear_Data |
|---|
| 436 | // Define data to be passed to user function |
|---|
| 437 | end f_nonlinear_Data; |
|---|
| 438 | |
|---|
| 439 | redeclare function extends f_nonlinear |
|---|
| 440 | algorithm |
|---|
| 441 | y:=saturationPressure(x); |
|---|
| 442 | // Compute the non-linear equation: y = f(x, Data) |
|---|
| 443 | end f_nonlinear; |
|---|
| 444 | |
|---|
| 445 | // Dummy definition |
|---|
| 446 | redeclare function extends solve |
|---|
| 447 | end solve; |
|---|
| 448 | end Internal; |
|---|
| 449 | algorithm |
|---|
| 450 | T:=Internal.solve(p, T_min, T_max); |
|---|
| 451 | annotation (Documentation(info="<html> |
|---|
| 452 | Computes saturation temperature from (partial) pressure via numerical inversion of the function <a href=Modelica:Modelica.Media.Air.MoistAir.saturationPressure>saturationPressure</a>. Therefore additional inputs are required (or the defaults are used) for upper and lower temperature bounds. |
|---|
| 453 | </html>")); |
|---|
| 454 | end saturationTemperature; |
|---|
| 455 | |
|---|
| 456 | redeclare function extends enthalpyOfVaporization |
|---|
| 457 | "Return enthalpy of vaporization of water as a function of temperature T, 0 - 130 degC" |
|---|
| 458 | algorithm |
|---|
| 459 | /*r0 := 1e3*(2501.0145 - (T - 273.15)*(2.3853 + (T - 273.15)*(0.002969 - (T |
|---|
| 460 | - 273.15)*(7.5293e-5 + (T - 273.15)*4.6084e-7))));*/ |
|---|
| 461 | //katrin: replaced by linear correlation, simpler and more accurate in the entire region |
|---|
| 462 | //source VDI-Waermeatlas, linear inter- and extrapolation between values for 0.01°C and 40°C. |
|---|
| 463 | r0:=(2405900-2500500)/(40-0)*(T-273.16)+2500500; |
|---|
| 464 | annotation (Documentation(info="<html> |
|---|
| 465 | Enthalpy of vaporization of water is computed from temperature in the region of 0 to 130 °C. |
|---|
| 466 | </html>")); |
|---|
| 467 | end enthalpyOfVaporization; |
|---|
| 468 | |
|---|
| 469 | function HeatCapacityOfWater |
|---|
| 470 | "Return specific heat capacity of water (liquid only) as a function of temperature T" |
|---|
| 471 | extends Modelica.Icons.Function; |
|---|
| 472 | input Temperature T "Temperature"; |
|---|
| 473 | output SpecificHeatCapacity cp_fl "Specific heat capacity of liquid"; |
|---|
| 474 | annotation (Documentation(info="<html> |
|---|
| 475 | The specific heat capacity of water (liquid and solid) is calculated using a |
|---|
| 476 | polynomial approach and data from VDI-Waermeatlas 8. Edition (Db1) |
|---|
| 477 | </html>")); |
|---|
| 478 | algorithm |
|---|
| 479 | cp_fl := 1e3*(4.2166 - (T - 273.15)*(0.0033166 + (T - 273.15)*(0.00010295 |
|---|
| 480 | - (T - 273.15)*(1.3819e-6 + (T - 273.15)*7.3221e-9)))); |
|---|
| 481 | end HeatCapacityOfWater; |
|---|
| 482 | |
|---|
| 483 | redeclare function extends enthalpyOfLiquid |
|---|
| 484 | "Return enthalpy of liquid water as a function of temperature T(use enthalpyOfWater instead)" |
|---|
| 485 | |
|---|
| 486 | annotation(Inline=false,smoothOrder=5, |
|---|
| 487 | Documentation(info="<html> |
|---|
| 488 | Specific enthalpy of liquid water is computed from temperature using a polynomial approach. Kept for compatibility reasons, better use <a href=Modelica:Modelica.Media.Air.MoistAir.enthalpyOfWater>enthalpyOfWater</a> instead. |
|---|
| 489 | </html>")); |
|---|
| 490 | algorithm |
|---|
| 491 | h := (T - 273.15)*1e3*(4.2166 - 0.5*(T - 273.15)*(0.0033166 + 0.333333*(T - 273.15)*(0.00010295 |
|---|
| 492 | - 0.25*(T - 273.15)*(1.3819e-6 + 0.2*(T - 273.15)*7.3221e-9)))); |
|---|
| 493 | end enthalpyOfLiquid; |
|---|
| 494 | |
|---|
| 495 | redeclare function extends enthalpyOfGas |
|---|
| 496 | "Return specific enthalpy of gas (air and steam) as a function of temperature T and composition X" |
|---|
| 497 | |
|---|
| 498 | annotation(Inline=false,smoothOrder=5, |
|---|
| 499 | Documentation(info="<html> |
|---|
| 500 | Specific enthalpy of moist air is computed from temperature, provided all water is in the gaseous state. The first entry in the composition vector X must be the mass fraction of steam. For a function that also covers the fog region please refer to <a href=Modelica:Modelica.Media.Air.MoistAir.h_pTX>h_pTX</a>. |
|---|
| 501 | </html>")); |
|---|
| 502 | algorithm |
|---|
| 503 | h := SingleGasNasa.h_Tlow(data=steam, T=T, refChoice=3, h_off=46479.819+2501014.5)*X[Water] |
|---|
| 504 | + SingleGasNasa.h_Tlow(data=dryair, T=T, refChoice=3, h_off=25104.684)*(1.0-X[Water]); |
|---|
| 505 | end enthalpyOfGas; |
|---|
| 506 | |
|---|
| 507 | redeclare function extends enthalpyOfCondensingGas |
|---|
| 508 | "Return specific enthalpy of steam as a function of temperature T" |
|---|
| 509 | |
|---|
| 510 | annotation(Inline=false,smoothOrder=5, |
|---|
| 511 | Documentation(info="<html> |
|---|
| 512 | Specific enthalpy of steam is computed from temperature. |
|---|
| 513 | </html>")); |
|---|
| 514 | algorithm |
|---|
| 515 | h := SingleGasNasa.h_Tlow(data=steam, T=T, refChoice=3, h_off=46479.819+2501014.5); |
|---|
| 516 | end enthalpyOfCondensingGas; |
|---|
| 517 | |
|---|
| 518 | function enthalpyOfWater |
|---|
| 519 | "Computes specific enthalpy of water (solid/liquid) near atmospheric pressure from temperature T" |
|---|
| 520 | input SIunits.Temperature T "Temperature"; |
|---|
| 521 | output SIunits.SpecificEnthalpy h "Specific enthalpy of water"; |
|---|
| 522 | annotation (derivative=enthalpyOfWater_der, Documentation(info="<html> |
|---|
| 523 | Specific enthalpy of water (liquid and solid) is computed from temperature using constant properties as follows:<br> |
|---|
| 524 | <ul> |
|---|
| 525 | <li> heat capacity of liquid water:4200 J/kg |
|---|
| 526 | <li> heat capacity of solid water: 2050 J/kg |
|---|
| 527 | <li> enthalpy of fusion (liquid=>solid): 333000 J/kg |
|---|
| 528 | </ul> |
|---|
| 529 | Pressure is assumed to be around 1 bar. This function is usually used to determine the specific enthalpy of the liquid or solid fraction of moist air. |
|---|
| 530 | </html>")); |
|---|
| 531 | algorithm |
|---|
| 532 | /*simple model assuming constant properties: |
|---|
| 533 | heat capacity of liquid water:4200 J/kg |
|---|
| 534 | heat capacity of solid water: 2050 J/kg |
|---|
| 535 | enthalpy of fusion (liquid=>solid): 333000 J/kg*/ |
|---|
| 536 | |
|---|
| 537 | h:=Utilities.spliceFunction(4200*(T-273.15),2050*(T-273.15)-333000,T-273.16,0.1); |
|---|
| 538 | end enthalpyOfWater; |
|---|
| 539 | |
|---|
| 540 | function enthalpyOfWater_der "Derivative function of enthalpyOfWater" |
|---|
| 541 | input SIunits.Temperature T "Temperature"; |
|---|
| 542 | input Real dT(unit="K/s") "Time derivative of temperature"; |
|---|
| 543 | output Real dh(unit="J/(kg.s)") "Time derivative of specific enthalpy"; |
|---|
| 544 | algorithm |
|---|
| 545 | /*simple model assuming constant properties: |
|---|
| 546 | heat capacity of liquid water:4200 J/kg |
|---|
| 547 | heat capacity of solid water: 2050 J/kg |
|---|
| 548 | enthalpy of fusion (liquid=>solid): 333000 J/kg*/ |
|---|
| 549 | |
|---|
| 550 | //h:=Utilities.spliceFunction(4200*(T-273.15),2050*(T-273.15)-333000,T-273.16,0.1); |
|---|
| 551 | dh:=Utilities.spliceFunction_der(4200*(T-273.15),2050*(T-273.15)-333000,T-273.16,0.1,4200*dT,2050*dT,dT,0); |
|---|
| 552 | annotation (Documentation(info="<html> |
|---|
| 553 | Derivative function for <a href=Modelica:Modelica.Media.Air.MoistAir.enthalpyOfWater>enthalpyOfWater</a>. |
|---|
| 554 | |
|---|
| 555 | </html>")); |
|---|
| 556 | end enthalpyOfWater_der; |
|---|
| 557 | |
|---|
| 558 | redeclare function extends pressure |
|---|
| 559 | "Returns pressure of ideal gas as a function of the thermodynamic state record" |
|---|
| 560 | algorithm |
|---|
| 561 | p := state.p; |
|---|
| 562 | annotation (Documentation(info="<html> |
|---|
| 563 | Pressure is returned from the thermodynamic state record input as a simple assignment. |
|---|
| 564 | </html>")); |
|---|
| 565 | end pressure; |
|---|
| 566 | |
|---|
| 567 | redeclare function extends temperature |
|---|
| 568 | "Return temperature of ideal gas as a function of the thermodynamic state record" |
|---|
| 569 | algorithm |
|---|
| 570 | T := state.T; |
|---|
| 571 | annotation (Documentation(info="<html> |
|---|
| 572 | Temperature is returned from the thermodynamic state record input as a simple assignment. |
|---|
| 573 | </html>")); |
|---|
| 574 | end temperature; |
|---|
| 575 | |
|---|
| 576 | function T_phX |
|---|
| 577 | "Return temperature as a function of pressure p, specific enthalpy h and composition X" |
|---|
| 578 | input AbsolutePressure p "Pressure"; |
|---|
| 579 | input SpecificEnthalpy h "Specific enthalpy"; |
|---|
| 580 | input MassFraction[:] X "Mass fractions of composition"; |
|---|
| 581 | output Temperature T "Temperature"; |
|---|
| 582 | |
|---|
| 583 | protected |
|---|
| 584 | package Internal |
|---|
| 585 | "Solve h(data,T) for T with given h (use only indirectly via temperature_phX)" |
|---|
| 586 | extends Modelica.Media.Common.OneNonLinearEquation; |
|---|
| 587 | redeclare record extends f_nonlinear_Data |
|---|
| 588 | "Data to be passed to non-linear function" |
|---|
| 589 | extends Modelica.Media.IdealGases.Common.DataRecord; |
|---|
| 590 | end f_nonlinear_Data; |
|---|
| 591 | |
|---|
| 592 | redeclare function extends f_nonlinear |
|---|
| 593 | algorithm |
|---|
| 594 | y := h_pTX(p,x,X); |
|---|
| 595 | end f_nonlinear; |
|---|
| 596 | |
|---|
| 597 | // Dummy definition has to be added for current Dymola |
|---|
| 598 | redeclare function extends solve |
|---|
| 599 | end solve; |
|---|
| 600 | end Internal; |
|---|
| 601 | |
|---|
| 602 | algorithm |
|---|
| 603 | T := Internal.solve(h, 200, 6000, p, X[1:nXi], steam); |
|---|
| 604 | annotation (Documentation(info="<html> |
|---|
| 605 | Temperature is computed from pressure, specific enthalpy and composition via numerical inversion of function <a href=Modelica:Modelica.Media.Air.MoistAir.h_pTX>h_pTX</a>. |
|---|
| 606 | </html>")); |
|---|
| 607 | end T_phX; |
|---|
| 608 | |
|---|
| 609 | redeclare function extends density |
|---|
| 610 | "Returns density of ideal gas as a function of the thermodynamic state record" |
|---|
| 611 | algorithm |
|---|
| 612 | d := state.p/(gasConstant(state)*state.T); |
|---|
| 613 | annotation (Documentation(info="<html> |
|---|
| 614 | Density is computed from pressure, temperature and composition in the thermodynamic state record applying the ideal gas law. |
|---|
| 615 | </html>")); |
|---|
| 616 | end density; |
|---|
| 617 | |
|---|
| 618 | redeclare function extends specificEnthalpy |
|---|
| 619 | "Return specific enthalpy of moist air as a function of the thermodynamic state record" |
|---|
| 620 | algorithm |
|---|
| 621 | h := h_pTX(state.p, state.T, state.X); |
|---|
| 622 | annotation (Documentation(info="<html> |
|---|
| 623 | Specific enthalpy of moist air is computed from the thermodynamic state record. The fog region is included for both, ice and liquid fog. |
|---|
| 624 | </html>")); |
|---|
| 625 | end specificEnthalpy; |
|---|
| 626 | |
|---|
| 627 | function h_pTX |
|---|
| 628 | "Return specific enthalpy of moist air as a function of pressure p, temperature T and composition X" |
|---|
| 629 | extends Modelica.Icons.Function; |
|---|
| 630 | input SI.Pressure p "Pressure"; |
|---|
| 631 | input SI.Temperature T "Temperature"; |
|---|
| 632 | input SI.MassFraction X[:] "Mass fractions of moist air"; |
|---|
| 633 | output SI.SpecificEnthalpy h "Specific enthalpy at p, T, X"; |
|---|
| 634 | annotation(Inline=false,smoothOrder=1, |
|---|
| 635 | Documentation(derivative=h_pTX_der,info="<html> |
|---|
| 636 | Specific enthalpy of moist air is computed from pressure, temperature and composition with X[1] as the total water mass fraction. The fog region is included for both, ice and liquid fog. |
|---|
| 637 | </html>")); |
|---|
| 638 | protected |
|---|
| 639 | SI.AbsolutePressure p_steam_sat "Partial saturation pressure of steam"; |
|---|
| 640 | SI.MassFraction X_sat "Absolute humidity per unit mass of moist air"; |
|---|
| 641 | SI.MassFraction X_liquid "mass fraction of liquid water" |
|---|