├── FluidProps_v240508.xlsb
├── README.md
└── FluidProps.bas
/FluidProps_v240508.xlsb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SchildCode/FluidProps/HEAD/FluidProps_v240508.xlsb
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FluidProps [](https://zenodo.org/doi/10.5281/zenodo.10370491)
2 | An Excel workbook with open-source user-defined Visual Basic functions in module 'FluidProps.bas' to calculate the following thermophysical properties, and is usesful for engineers, meteorologists and others:
3 | - Psychrometrics of moist air
4 | - Atmospheric properties: Wind, temperature and pressure as a function of altitude
5 | - Gases: Dry air and ideal gases
6 | - Water
7 | - Antifreeze coolants
8 | - Refrigerants
9 | - Flow friction in pipes/ducts
10 |
11 | Conventional fluid property software solve [equation-of-state (EOS)](https://en.wikipedia.org/wiki/Equation_of_state) equations for each constitulent molecule in the fluid mixture. This approach is very flexible, but has two drawbacks:
12 | (i) It is slow because some properties, e.g. enthalpy, are calculated by a combination of root-solving iteration and numerical integration, and
13 | (ii) The most popular forms ([Cubic EOS](https://en.wikipedia.org/wiki/Equation_of_state#Cubic_equations_of_state)) are known to deviate significantly from true measured thermophysical properties.
14 | FluidProps instead applies regressions that are significantly faster, and pretty accurate. For the refrigerants in particular, the propeties apply up to the critical-point with optimized rational functions of reduced temperature. In the code is documented the range of applicability, correlation coefficient (R²), and maximum deviation, for most of the correlations.
15 |
16 | ### Detailed list of functions
17 | - **Water_Dens(Tw_K)**
[kg/m³] Density of liquid water at 101325 Pa
18 | - **Water_Cp(Tw_K)**
[J/(kg·K)] Heat capacity of liquid water at 101325 Pa
19 | - **Water_Conduct(Tw_K)**
[W/(m·K)] Thermal conductivity of liquid water and solid ice at 101325 Pa
20 | - **Water_KineVisc(Tw_K)**
[m²/s] Kinematic viscosity of liquid water at 101325 Pa
21 | - **Water_DynaVisc(Tw_K)**
[Pa·s] Dynamic viscosity of liquid water at 101325 Pa
22 | - **Water_Pr(Tw_K)**
[-] Prandtl number of liquid water at 101325 Pa
23 | - **Water_Enth(Tw_K)**
[J/kg] Specific enthalpy of liquid water at 101325 Pa
24 | - **Water_thermDiff(Tw_K)**
[m²/s] Thermal diffusivity of liquid water at standard pressure (101325 Pa)
25 | - **Vapour_Pws(Tdry_K, Optional ice As Boolean = False)**
[Pa] Saturation vapour pressure, i.e. the equilibrium water vapor pressure above a flat surface
26 | - **Vapour_Cp(Tdry_K)**
[J/(kg·K)] Heat capacity of water vapour, valid near 101325 Pa
27 | - **Vapour_Dv(Tdry_K, Patm_Pa)**
[m²/s] Vapour mass diffusivity of water vapour in air. A.k.a. diffustion coefficient. Used to calculate Schmidt number
28 | - **EthyleneGlycol_VolFraction(Tfreeze_C)**
[-] Minimum required volume fraction of Ethylene Glycol for freezing point Tfreeze_C, valid at 101325 Pa
29 | - **EthyleneGlycol_Dens(T_C, VolFraction)**
[kg/m³] Density of aqueous solution of ethylene glycol coolant/antifreeze
30 | - **EthyleneGlycol_Cp(T_C, VolFraction)**
[J/(kg·K)] Specific heat capacity of aqueous solution of ethylene glycol coolant/antifreeze
31 | - **EthyleneGlycol_Conduct(T_C, VolFraction)**
[W/(m·K)] Thermal conductivity of aqueous solution of ethylene glycol coolant/antifreeze
32 | - **EthyleneGlycol_DynaVisc(T_C, VolFraction)**
[Pa·s] Dynamic viscosity of aqueous solution of ethylene glycol coolant/antifreeze
33 | - **PropyleneGlycol_VolFraction(Tfreeze_C)**
[-] Minimum required volume fraction of Propylene Glycol for freezing point Tfreeze_C, valid at 101325 Pa
34 | - **PropyleneGlycol_Dens(T_C, VolFraction)**
[kg/m³] Density of aqueous solution of Propylene glycol coolant/antifreeze
35 | - **PropyleneGlycol_Cp(T_C, VolFraction)**
[J/(kg·K)] Specific heat capacity of aqueous solution of Propylene glycol coolant/antifreeze
36 | - **PropyleneGlycol_Conduct(T_C, VolFraction)**
[W/mK] Thermal conductivity of aqueous solution of Propylene glycol coolant/antifreeze
37 | - **PropyleneGlycol_DynaVisc(T_C, VolFraction)**
[Pa·s] Dynamic viscosity of aqueous solution of Propylene glycol coolant/antifreeze
38 | - **Refrigerant_Sbubble(Refrigerant, TK)**
[kJ/kg] Bubble-point entropy, i.e. left side of Ts-diagram
39 | - **Refrigerant_Sdew(Refrigerant, TK)**
[kJ/kg] Dew-point entropy, i.e. right side of Ts-diagram
40 | - **Refrigerant_CpDew(Refrigerant, TK)**
[kJ/(kg·K)] Refrigerant gas-phase specific heat capacity, at dew-point temperature and pressure
41 | - **Refrigerant_Hbubble(Refrigerant, TK)**
[kJ/kg] Bubble-point enthalpy, i.e. left side of Ph-diagram
42 | - **Refrigerant_Hdew(Refrigerant, TK)**
[kJ/kg] Dew-point enthalpy, i.e. right side of Ph-diagram
43 | - **Refrigerant_Tdew(Refrigerant, Pa)**
[K] Dew-point temperature at pressure Pa
44 | - **Refrigerant_Pdew(Refrigerant, TK)**
[Pa] Stauration pressure given dew-point temperature
45 | - **DryAir_KineVisc(Tdry_K)**
[m²/s] Kinematic viscosity of dry air, valid at 101325 Pa
46 | - **DryAir_DynaVisc(Tdry_K)**
[Pa·s] Dynamic viscosity of dry air, valid at 101325 Pa
47 | - **DryAir_Cp(Tdry_K)**
[J/(kg·K)] Specific heat capacity of dry air, valid at 101325 Pa
48 | - **DryAir_Conduct(Tdry_K)**
[W/mK] Specific heat capacity of dry air, valid at 101325 Pa
49 | - **DryAir_Pr(Tdry_K)**
[-] Prandtl number of dry air, valid at 101325 Pa
50 | - **DryAir_thermDiff(Tdry_K)**
[m²/s] Thermal diffusivity of dry air at standard atmospheric pressure (101325 Pa)
51 | - **Air_Cp(Tdry_K, HumidRatio)**
[J/(k·gK)] Specific heat capacity of moist air
52 | - **Air_Enth(Tdry_K, HumidRatio)**
[J/kg dry air] Air specific enthalpy per kg dry air
53 | - **Air_DryBulb(Enthalpy_Jkg, HumidRatio)**
[K] Dry-bulb air temperature
54 | - **Air_DensR(Tdry_K, RH, Patm_Pa)**
[kg/m³] Air density, given RH
55 | - **Air_DensH(Tdry_K, HumidRatio, Patm_Pa)**
[kg/m³] Air density, given humidity ratio
56 | - **Air_TdewP(Tdry_K, Pv_Pa)**
[K] Dew-point (or frost-point) temperature, given parial pressure of vapour
57 | - **Air_TdewH(Tdry_K, HumidRatio, Patm_Pa)**
[K] Dew-point (or frost-point) temperature, given humidity ratio
58 | - **Air_TdewR(Tdry_K, RH)**
[K] Dew-point (or frost-point) temperature, given RH
59 | - **Air_TdewW(Tdry_K, Twet_K, Patm_Pa)**
[K] Dew-point (or frost-point) temperature, given wet-bulb temperature
60 | - **Air_HumidRatioR(Tdry_K, RH, Patm_Pa)**
[kg water vapour / kg dry air] Humidity ratio of moist air, given RH
61 | - **Air_HumidRatioD(Tdew_K, Patm_Pa)**
[kg water vapour / kg dry air] Humidity ratio of moist air, given dew-point temperature
62 | - **Air_HumidRatioW(Tdry_K, Twet_K, Patm_Pa)**
[kg water vapour / kg dry air] Humidity ratio of moist air, given wet-bulb tempeature
63 | - **Air_HumidRatioX(SpecificHumid)**
[kg water vapour / kg dry air] Humidity ratio of moist air, given specific humidity
64 | - **Air_RHd(Tdry_K, Tdew_K, Optional ice As Boolean = False)**
[-] Relative humidity (over liquid water), given dew-point temperature
65 | - **Air_RHh(Tdry_K, HumidRatio, Patm_Pa)**
[-] Relative humidity (over liquid water), given humidity ratio
66 | - **Air_RHw(Tdry_K, Twet_K, Patm_Pa)**
[-] Relative humidity (over liquid water), given wet-bulb temperature
67 | - **Air_TwetH(Tdry_K, HumidRatio, Patm_Pa)**
[K] Wet-bulb temperature, given humidity ratio. Fast iterative reverse calculation by secant method
68 | - **Air_TwetR(Tdry_K, RH, Patm_Pa)**
[K] Wet-bulb temperature, given RH
69 | - **Air_TwetD(Tdry_K, Tdew_K, Patm_Pa)**
[K] Wet-bulb temperature, given dew-point temperature
70 | - **Atmos_Pa(Height_over_sea_level_m)**
[Pa] Estimate of standard-atmosphere barometric pressure as a function of height over sea level
71 | - **Atmos_Pa2(Atmos_Pa1, Atmos_T1, Altitude1_m, Altitude2_m)**
[Pa] Estimate of atmospheric pressure at altitude 1 (e.g. sea level, og building site) given pressure andtemperature at Altitude2 (e.g. station altitude)
72 | - **Atmos_T(Height_over_sea_level_m)**
[K] Estimate temperature as a function of height over sea level. Valid in troposphere (<11km)
73 | - **Atmos_T2(Atmos_T1, Altitude1_m, Altitude2_m)**
[K] Estimate of dry-bulb temperature at Altitude2_m given Tdry1_K at aAltitude1_m. Assumes Environmental Lapse Rate (ELR)
74 | - **Wind_Loc2_ms(Wind_Loc1_ms, Alpha_Loc1, Alpha_Loc2, Height_Loc2_m)**
[m/s] Wind speed at Location 2 given wind speed from 10 m high weather station at Location1.
75 | - **OrificeMassFlow_m3s(Tappings_str, DuctDia_m, OrificeDia_m, Tdry_K, RH, Patm_Pa, dP_Pa)**
[m³/s] Volumetric air flow rate measured by means of pressure drop over an ISO 5167-1 orifice plate
76 | - **Air_DuctFriction(FlowRate_m3s, Diam_m, Roughness_m, Tdry_K, RH, Patm_Pa)**
[Pa/m] Pressure drop per meter duct, for airflow in ducts
77 | - **Water_PipeFriction(FlowRate_m3s, Diam_m, Roughness_m, T_K)**
[Pa/m] Pressure drop per meter pipe, for water flow in pipes
78 | - **FrictionFactor(Re, relRough)**
[-] Darcy friction factor for laminar or turbulent flow calculated with the Colebrook-White equation.
79 |
80 | ### References
81 | References are given for each individual function. Sources include "ASHRAE Fundamentals" handbook, and NIST chem. database
82 |
83 | ### License & warranty
84 | Free share-alike license (CC BY-SA 4.0): https://creativecommons.org/licenses/by-sa/4.0/. Provided with no warranty of any kind.
85 |
86 | ### Author
87 | Source code and workbook are copyright peter.schild@oslomet.no
88 |
89 | ### BibTeX for citing FluidProps
90 |
91 | ```bibtex
92 | @Misc{Schild20,
93 | author = {Schild, Peter G.},
94 | title = {{FluidProps}: Open-source code to calculate therrmophysical properties for engineering},
95 | howpublished = {\url{https://github.com/SchildCode/FluidProps/}},
96 | doi = {10.5281/zenodo.10370491},
97 | url = {https://doi.org/10.5281/zenodo.10370491}
98 | year = {2020}
99 | }
100 | ```
101 |
--------------------------------------------------------------------------------
/FluidProps.bas:
--------------------------------------------------------------------------------
1 | 'FLUIDPROPS: A library of diverse fluid properties and equations (incl. psychrometrics, thermodanamics and fluid flow)
2 | '- All input and output parameters are in SI units
3 | '- References are given for all equations & data. Main references are NIST Chemistry WebBook, and ASHRAE Fundamentals Handbook 2017 (based on ASHRAE LibHuAirProp)
4 | '- The code calculates two kinds of properties differently. This approach ensures maximum consistency of dependencies between the different calculated properties:
5 | ' (i) FUNDAMENTAL properties, based on accurate experimental data. Examples are: density, heat capacity, thermal conductivity, dynamic viscosity
6 | ' (ii) DERIVED properties, calculated from one or more fundamental properties using formulae. Examples are kinematic viscosity [v=µ/rho], thermal diffusivity [a=k/(rho·cp)] and Prandtl number [Pr=µ·cp/k]
7 | ' Examples of (i) fundamentalare
8 | '- Original version is available at https://github.com/SchildCode/FluidProps
9 | '- If you use this code, please cite it. BibTeX-format reference is given on page https://github.com/SchildCode/FluidProps
10 |
11 | 'Copyright original author: Peter.Schild@OsloMet.no, 2000-2024
12 | 'This source-code is licensed freely as Attribute-ShareAlike under CC BY-SA 4.0 (https://creativecommons.org/licenses/by-sa/4.0/).
13 | 'It is provided without warranty of any kind.
14 | 'Please do give author feedback if you have suggestions to improvements.
15 |
16 | Option Explicit
17 | Const ZeroC# = 273.15 '[K]
18 | Const onePi# = 3.14159265358979
19 |
20 | Private Function ErrorMsg#(ErrorText As String)
21 | 'Here you can change the behaviour when out-of bounds values are calculated. Uncomment the line(s) for your preferred alternative(s).
22 | MsgBox ErrorText 'ALTERNATIVE 1: Popup message box.
23 | ErrorMsg = -999# 'ALTERNATIVE 2: Return unlikely value (as Double). This is useful when you want to return error-flag to the calling routine
24 | 'Stop 'ALTERNATIVE 3: Comment out as needed
25 | End Function
26 |
27 | Private Function usrMaxDbl#(aa#, bb#)
28 | 'Significantly faster than Worksheetfunction.Max(aa,bb)
29 | If aa < bb Then
30 | usrMaxDbl = bb
31 | Else
32 | usrMaxDbl = aa
33 | End If
34 | End Function
35 |
36 | Private Function usrMinDbl#(aa#, bb#)
37 | 'Significantly faster than Worksheetfunction.Min(aa,bb)
38 | If aa < bb Then
39 | usrMinDbl = aa
40 | Else
41 | usrMinDbl = bb
42 | End If
43 | End Function
44 |
45 | '----------------------------
46 | 'LIQUID WATER & ICE
47 | '----------------------------
48 |
49 | Public Function Water_Dens#(ByVal Tw_K#)
50 | 'Water_Dens [kg/m³] = Density of liquid water at standard atmospheric pressure (101325 Pa).
51 | 'INPUTS: Tw_K [K] = Water temperature
52 | 'NOTE: This is a fundamental thermophysical property, based on empirical data.
53 |
54 | Const Tcrit# = 647.096 '[K] Critical-point temperature
55 | Dim Trc# '[-] Complement of Reduced temperature = 1 - (T / T_critical)
56 |
57 | If Tw_K < 273.15 Or 373.15 < Tw_K Then
58 | Water_Dens = ErrorMsg("Tw out of range in water_Dens. Tw = " & Tw_K & " K")
59 | Else
60 | Trc = 1 - Tw_K / Tcrit
61 | 'Data source: Eric W. Lemmon, Mark O. McLinden and Daniel G. Friend, "Thermophysical Properties of Fluid Systems" in NIST Chemistry WebBook, NIST Standard Reference Database Number 69, Eds. P.J. Linstrom and W.G. Mallard, National Institute of Standards and Technology, Gaithersburg MD, 20899, https://doi.org/10.18434/T4D303, (retrieved March 31, 2020).
62 | 'https://webbook.nist.gov/chemistry/fluid/
63 | 'Fitted by symbolic regression to a rational function using https://github.com/SchildCode/RatFun-Regression
64 | 'Statistics: R²=0.999999813, Max deviation = ±0.01168 kg/m³ in the range 273.16K to 373.12K
65 | Water_Dens = (1 + Trc ^ 2 * (-2.68259321562161 + 0.969985158312932 * Trc ^ 2)) / (1.5658241366722E-03 - 2.34210562352665E-03 * Trc)
66 | End If
67 | End Function
68 |
69 | Public Function Water_Cp#(ByVal Tw_K#)
70 | 'Water_Cp [J/kgK] = Heat capacity of liquid water at standard atmospheric pressure (101325 Pa)
71 | 'INPUTS: Tw_K [K] = Water temperature
72 | 'NOTE: This is a fundamental thermophysical property, based on empirical data.
73 |
74 | Const Tcrit# = 647.096 '[K] Critical-point temperature
75 | Dim Tr# '[-] Reduced temperature = T / T_critical
76 |
77 | If Tw_K < 273.15 Or 373.15 < Tw_K Then
78 | Water_Cp = ErrorMsg("Tw out of range in water_Cp. Tw = " & Tw_K & " K")
79 | Else
80 | Tr = Tw_K / Tcrit
81 | 'Data source: Eric W. Lemmon, Mark O. McLinden and Daniel G. Friend, "Thermophysical Properties of Fluid Systems" in NIST Chemistry WebBook, NIST Standard Reference Database Number 69, Eds. P.J. Linstrom and W.G. Mallard, National Institute of Standards and Technology, Gaithersburg MD, 20899, https://doi.org/10.18434/T4D303, (retrieved March 31, 2020).
82 | 'https://webbook.nist.gov/chemistry/fluid/
83 | 'Fitted by symbolic regression to a rational function using https://github.com/SchildCode/RatFun-Regression
84 | 'Statistics: R²=0.999991, Max deviation = ±0.127 J/kgK in the range 273.16K to 373.12K
85 | Water_Cp = (-38527.626300554 * Tr ^ 5) / (1 + Tr * (-7.57372380642321 + Tr * (20.5726787552669 - 21.1539281976836 * Tr)))
86 | End If
87 | End Function
88 |
89 | Public Function Water_Conduct#(ByVal Tw_K#)
90 | 'Water_Conduct [W/mK] = Thermal conductivity of liquid water and solid ice at standard atmospheric pressure (101325 Pa)
91 | 'INPUTS: Tw_K [K] = Water temperature
92 | 'NOTE: This is a fundamental thermophysical property, based on empirical data.
93 |
94 | Const Tcrit# = 647.096 '[K] Critical-point temperature
95 | Dim Tr# '[-] Complement to 1 of reduced temperature = 1 - (T / T_critical)
96 |
97 | Select Case Tw_K
98 | Case Is < 228#
99 | Water_Conduct = ErrorMsg("Tw too low in water_Conduct. Tw = " & Tw_K & " K")
100 | Case Is < ZeroC 'solid ice
101 | 'REFERENCE: US Coast Guard
102 | Water_Conduct = 5.1143235511 - 0.0105864721 * Tw_K
103 | Case Is <= 373.15 'liquid water
104 | Tr = 1 - Tw_K / Tcrit
105 | 'Data source: Eric W. Lemmon, Mark O. McLinden and Daniel G. Friend, "Thermophysical Properties of Fluid Systems" in NIST Chemistry WebBook, NIST Standard Reference Database Number 69, Eds. P.J. Linstrom and W.G. Mallard, National Institute of Standards and Technology, Gaithersburg MD, 20899, https://doi.org/10.18434/T4D303, (retrieved March 31, 2020).
106 | 'https://webbook.nist.gov/chemistry/fluid/
107 | 'Fitted by symbolic regression to a rational function using https://github.com/SchildCode/RatFun-Regression
108 | 'Statistics: R²=0.999999986, Max deviation = ±1.43693E-05 W/mK in the range 273.16K to 373.12K
109 | Water_Conduct = (0.614572668031482 + Tr * Tr * Tr * (-8.39219943470412 + 10.3751706905586 * Tr)) / (1 + Tr * Tr * (-3.56844084636025 + 7.17981988639961 * Tr * Tr * Tr))
110 | Case Else
111 | Water_Conduct = ErrorMsg("Tw too high in water_Conduct. Tw = " & Tw_K & " K")
112 | End Select
113 | End Function
114 |
115 | Public Function Water_Enth#(ByVal Tw_K#)
116 | 'Water_Enth [J/kg] = Specific enthalpy of liquid water at standard atmospheric pressure (101325 Pa)
117 | 'INPUTS: Tw_K [K] = Water temperature
118 | 'NOTE: This is strictly a derived thermophysical property, based on integrating dh = cp·dT over over the temperature range from reference state (T=0°C) to T_K. This is complicated by the fact that cp is itself a non-linear function of temperature. Therefore a dedicated correlation is given here
119 |
120 | Dim TC# '[°C]
121 |
122 | If Tw_K < 273.15 Or 373.15 < Tw_K Then
123 | Water_Enth = ErrorMsg("Tw out of range in water_Enth. Tw = " & Tw_K & " K")
124 | Else
125 | TC = Tw_K - ZeroC
126 | 'Data source: Eric W. Lemmon, Mark O. McLinden and Daniel G. Friend, "Thermophysical Properties of Fluid Systems" in NIST Chemistry WebBook, NIST Standard Reference Database Number 69, Eds. P.J. Linstrom and W.G. Mallard, National Institute of Standards and Technology, Gaithersburg MD, 20899, https://doi.org/10.18434/T4D303, (retrieved March 31, 2020).
127 | 'https://webbook.nist.gov/chemistry/fluid/
128 | 'Fitted by symbolic regression to a rational function using https://github.com/SchildCode/RatFun-Regression
129 | 'Statistics: R²=0.9999999979, Max deviation = ±22 J/kgK in the range 273.16K to 373.12K
130 | Water_Enth = (83.1183363886333 + TC * (4216.04762279028 + TC * (108.878331267255 + 5.58619783034135E-05 * TC ^ 2))) / (1 + 2.61682405418377E-02 * TC)
131 | End If
132 | End Function
133 |
134 | Public Function Water_DynaVisc#(ByVal Tw_K#)
135 | 'Water_DynaVisc [Pa·s] = Dynamic viscosity of liquid water at standard atmospheric pressure (101325 Pa)
136 | 'INPUTS: Tw_K [K] = Water temperature
137 | 'NOTE: This is a fundamental thermophysical property, based on empirical data, because it directly relates to the molecular characteristics and interactions in a fluid, independent of its density
138 |
139 | Const Tcrit# = 647.096 '[K] Critical-point temperature
140 | Dim Tr# '[-] Complement to 1 of reduced temperature = 1 - (T / T_critical)
141 |
142 | If Tw_K < 273.15 Or 373.15 < Tw_K Then
143 | Water_DynaVisc = ErrorMsg("Tw out of range in water_DynaVisc. Tw = " & Tw_K & " K")
144 | Else
145 | Tr = 1 - Tw_K / Tcrit
146 | 'Data source: Eric W. Lemmon, Mark O. McLinden and Daniel G. Friend, "Thermophysical Properties of Fluid Systems" in NIST Chemistry WebBook, NIST Standard Reference Database Number 69, Eds. P.J. Linstrom and W.G. Mallard, National Institute of Standards and Technology, Gaithersburg MD, 20899, https://doi.org/10.18434/T4D303, (retrieved March 31, 2020).
147 | 'https://webbook.nist.gov/chemistry/fluid/
148 | 'Fitted by symbolic regression to a rational function using https://github.com/SchildCode/RatFun-Regression
149 | 'Statistics: R²=0.9999999874, Max deviation = ±2.297E-07 Pa·s in the range 273.16K to 373.12K
150 | Water_DynaVisc = (1 - 3.72194823883595 * Tr * Tr * Tr) / (100556.859960968 * Tr - 399310.024486561 * Tr * Tr + 444709.674726627 * Tr * Tr * Tr - 161766.674865504 * Tr * Tr * Tr * Tr * Tr)
151 | End If
152 | End Function
153 |
154 | Public Function Water_KineVisc#(ByVal Tw_K#)
155 | 'Water_KineVisc [m²/s] = Kinematic viscosity of liquid water at standard atmospheric pressure (101325 Pa)
156 | 'INPUTS: Tw_K [K] = Water temperature
157 | 'NOTE: This is a derived thermophysical property:
158 | ' v = µ/rho, where v=kinematic visc. [m²/s], µ=dynamic visc. [Pa·s], rho=density [kg/m³]
159 |
160 | If Tw_K < 273.15 Or 373.15 < Tw_K Then
161 | Water_KineVisc = ErrorMsg("Tw out of range in water_KineVisc. Tw = " & Tw_K & " K")
162 | Else
163 | Water_KineVisc = Water_DynaVisc(Tw_K) / Water_Dens(Tw_K)
164 | End If
165 | End Function
166 |
167 | Public Function Water_Pr#(ByVal Tw_K#)
168 | 'Water_Pr [-] = Prandtl number of liquid water at standard atmospheric pressure (101325 Pa)
169 | 'INPUTS: Tw_K [K] = Water temperature
170 | 'NOTE: This is a derived thermophysical property:
171 | ' Pr = v/a where v=kinematic viscosity [Pa·s], a=thermal diffusivity [W/mK]. Both v and a are themselves derived properties
172 | ' Pr = Cp·µ/k where Cp=heat capacity [J/kgK], µ=dynamic viscosity [Pa·s], k=thermal conductivity [W/mK]. Cp, µ and k are all fundamental properties. Therefore this equation is preferred.
173 |
174 | If Tw_K < 273.15 Or 373.15 < Tw_K Then
175 | Water_Pr = ErrorMsg("Tw out of range in water_Pr. Tw = " & Tw_K & " K")
176 | Else
177 | Water_Pr = Water_Cp(Tw_K) * Water_DynaVisc(Tw_K) / Water_Conduct(Tw_K)
178 | End If
179 | End Function
180 |
181 | Public Function Water_thermDiff#(ByVal Tw_K#)
182 | 'Water_thermDiff [m²/s] = Thermal diffusivity of liquid water at standard atmospheric pressure (101325 Pa)
183 | 'INPUTS: Tw_K [K] = Water temperature
184 | 'NOTE: This is a derived thermophysical property:
185 | ' a = k/(rho·Cp) where a=thermal diffusivity [m²/s], k=thermal conductivity [W/(m·K)], rho=density [kg/m³], Cp=specific heat capacity [J/(kg·K)]
186 |
187 | If Tw_K < 273.15 Or 373.15 < Tw_K Then
188 | Water_thermDiff = ErrorMsg("Tw out of range in Water_thermDiff. Tw = " & Tw_K & " K")
189 | Else
190 | Water_thermDiff = Water_Conduct(Tw_K) / (Water_Dens(Tw_K) * Water_Cp(Tw_K))
191 | End If
192 | End Function
193 |
194 | '-----------------------------
195 | 'WATER VAPOUR
196 | '-----------------------------
197 |
198 | Private Function Vapour_Pws#(ByVal Tdry_K#, Optional ice As Boolean = False)
199 | 'Vapour_Pws [Pa] = Saturation vapour pressure, i.e. the equilibrium water vapor pressure above a flat surface
200 | 'INPUTS:
201 | '- Tdry_K [K] = Air dry-bulb temperature. If Tdry_K is dew-point, then Vapour_Pws is vapour pressure
202 | '- ice = TRUE if over ice when below 0°C (e.g. chilled mirror hygrometer), default is FALSE (Meteo data is always over liquid water)
203 | 'NOTE: This is a fundamental thermophysical property, based on empirical data
204 |
205 | 'DISCUSSION OF ICE CONTRA LIQUID WATER:
206 | 'Care needs to be taken to consider the difference between saturation vapour over ice or liquid water.
207 | 'By default this routine assumes liquid water.
208 | 'In meteorological practice, relative humidity is always given over liquid water (bottom eqn.).
209 | 'If the process of heating/cooling takes place fast, temporary existing of supercooled water at temperature lower than –0.01 °C is possible.
210 | 'As a result, formulas for calculating the pressure of saturating above water as well as ice are needed (in practice between temperatures from –18°C to the triple point +0.01°C).
211 |
212 | 'CHILLED MIRROR VERSUS CAPACITIVE HYGROMETERS:
213 | 'The equation for ice is mostly of interest for frost-point measurements when using chilled mirror hygrometers below 0°C, since these
214 | 'instruments directly measure the temperature at which a frost layer and the overlying vapour are in equilibrium.
215 | 'Below the triple point (T < 0.01°C), either dew or frost may exist on the mirror, which implies the mirror may be measuring
216 | 'the dew-point (Td) or the frost-point (Tf). Supercooled conditions not uncommon with chilled mirror hygrometers, in which case the
217 | 'mirror surface can maintain a layer of liquid water as low as -15°C for hours or days (especially above -5°C).
218 | 'However, assuming liquid water is always on the mirror results in far larger errors. Therefore always assume frost!
219 | 'Capacitive RH sensors (e.g. Vaisala, Rotronic) always respond to RH relative to a plane surface of liquid water.
220 |
221 | 'MORE ACCURATE ALTERNATIVE EQUATIONS
222 | '- IAPWS R6-95 (2016): "Revised release on the IAPWS formulation 1995 for the thermodynamic properties of ordinary water substance for general and scientific use", 19 pp., http://www.iapws.org/relguide/IAPWS95-2016.pdf
223 | '- IAPWS R7-97 (2012): http://www.iapws.org/relguide/IF97-Rev.html
224 | '- IAPWS R10-06 (2009): http://www.iapws.org/relguide/Ice-2009.html
225 | '- IAPWS R14-08 (2011): "Revised release on the pressure along the melting and sublimation curves of ordinary water substance", 7 pp., http://www.iapws.org/relguide/MeltSub2011.pdf.
226 | ' See ASHRAE Fundamentals 2021 §1.8 for more details about a slightly more accurate but slower, equation
227 |
228 | If Tdry_K < 173.15 Or 375.15 < Tdry_K Then
229 | Vapour_Pws = ErrorMsg("Tdry_K out of range in Function Vapour_Pws (Tdry_K=" & Tdry_K & ")")
230 | ElseIf Tdry_K < 273.16 And ice Then
231 | 'ASHRAE Handbook Fundamentals 2017, Eqn.(5) for ice. Validity range approx -100°C to 0°C
232 | 'Vapour_Pws = Exp(-5674.5359 / Tdry_K + 6.3925247 - 0.009677843 * Tdry_K + 0.00000062215701 * Tdry_K ^ 2 + 2.0747825E-09 * Tdry_K ^ 3 - 9.484024E-13 * Tdry_K ^ 4 + 4.1635019 * Log(Tdry_K))
233 | Vapour_Pws = Exp(-5674.5359 / Tdry_K + 6.3925247 + Tdry_K * (-0.009677843 + Tdry_K * (0.00000062215701 + Tdry_K * (2.0747825E-09 - Tdry_K * 9.484024E-13))) + 4.1635019 * Log(Tdry_K))
234 | Else
235 | 'ASHRAE Handbook Fundamentals 2017, Eqn.(6) over liquid water. Validity range approx -50°C to +102°C
236 | 'Vapour_Pws = Exp(-5800.2206 / Tdry_K + 1.3914993 - 0.048640239 * Tdry_K + 0.000041764768 * Tdry_K ^ 2 - 0.000000014452093 * Tdry_K ^ 3 + 6.5459673 * Log(Tdry_K))
237 | Vapour_Pws = Exp(-5800.2206 / Tdry_K + 1.3914993 + Tdry_K * (-0.048640239 + Tdry_K * (0.000041764768 - Tdry_K * 0.000000014452093)) + 6.5459673 * Log(Tdry_K))
238 | End If
239 | End Function
240 |
241 | Public Function Vapour_Cp#(ByVal Tdry_K#)
242 | 'Vapour_Cp [J/kgK] = Heat capacity of water vapour, valid near standard atmospheric pressure (101325 Pa)
243 | 'INPUTS: Tdry_K [K] = Dry-bulb air temperature
244 | 'NOTE: This is a fundamental thermophysical property, based on empirical data
245 |
246 | Dim Tdry_C#
247 |
248 | Tdry_C = Tdry_K - ZeroC
249 | 'REFERENCE: Reid et al. (1987 p.656f., 668)
250 | Vapour_Cp = 1858 + 0.382 * Tdry_C + 0.000422 * Tdry_C ^ 2 - 0.0000001996 * Tdry_C ^ 3
251 | End Function
252 |
253 | Public Function Vapour_Dv#(ByVal Tdry_K#, ByVal Patm_Pa#)
254 | 'Vapour_Dv [m²/s] = Vapour mass diffusivity of water vapour in air. A.k.a. diffustion coefficient. Used to calculate Schmidt number.
255 | 'Typical value: Dv = 25.8 mm²/s = 2.58E-5 m²/s at 25°C and standard atmospheric pressure (101325 Pa)
256 | 'INPUTS:
257 | '- Tdry_K [K] = Dry-bulb air temperature
258 | '- Patm_Pa [Pa] = Atmospheric pressure
259 | 'NOTE: This is a fundamental thermophysical property, based on empirical data
260 |
261 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, page 6.2, Eqn.(10): Citation of Sherwood & Pigford, 1952. Valid up to 1100°C
262 | Vapour_Dv# = 0.000000926 * (Tdry_K ^ 2.5) / (Patm_Pa * (Tdry_K + 245)) '[m²/s]
263 | End Function
264 |
265 | '-----------------------------
266 | 'ANTIFREEZE COOLANT LIQUIDS
267 | '-----------------------------
268 |
269 | Public Function EthyleneGlycol_VolFraction#(Tfreeze_C#)
270 | 'EthyleneGlycol_VolFraction [-] = Minimum required volume fraction of Ethylene Glycol for freezing point Tfreeze_C, valid at standard atmospheric pressure (101325 Pa)
271 | 'INPUTS: Tfreeze_C [°C] = Minimum freezing point
272 | 'NOTE: This is a fundamental thermophysical property, based on empirical data
273 |
274 | If Tfreeze_C < -48.3 Or 0 < Tfreeze_C Then
275 | EthyleneGlycol_VolFraction = ErrorMsg("Tfreeze_C out of range in EthyleneGlycol_VolFraction. Tfreeze_C = " & Tfreeze_C & " K")
276 | Else
277 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, Page 31.6
278 | 'Fitted by symbolic regression to a rational function using https://github.com/SchildCode/RatFun-Regression
279 | 'Statistics: R²=0.999917452; Max error = ±0.00439850988 [Volume fraction] in the range -48°C to 0°C
280 | EthyleneGlycol_VolFraction = (Tfreeze_C * (-2.97952987932674E-02 + 1.42763189691829E-04 * Tfreeze_C)) / (1 - 4.31395029603815E-02 * Tfreeze_C)
281 | End If
282 | End Function
283 |
284 | Public Function EthyleneGlycol_Dens#(T_C#, VolFraction#)
285 | 'EthyleneGlycol_Dens [kg/m³] = Density of aqueous solution of ethylene glycol coolant/antifreeze
286 | 'INPUTS:
287 | '- T_C [°C] = Temperature of aqueous solution.
288 | '- VolFraction [-] = Volume fraction of ethylene glycol, in the range 0 to 1.
289 | 'NOTE: You can first find the minimum required value of VolFraction with function EthyleneGlycol_VolFraction(T_C)
290 |
291 | If T_C < -35 Or 100 < T_C Then
292 | EthyleneGlycol_Dens = ErrorMsg("T_C out of range in EthyleneGlycol_Dens. T_C = " & T_C & " °C")
293 | ElseIf VolFraction < 0 Or 0.9 < VolFraction Then
294 | EthyleneGlycol_Dens = ErrorMsg("VolFraction out of range in EthyleneGlycol_Dens. VolFraction = " & VolFraction)
295 | Else
296 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, Section 31
297 | 'Fitted by symbolic regression to a polynomial by Eureqa (https://www.nutonian.com/products/eureqa/)
298 | 'Statistics: R²=0.99997026; Max error = ±0.69203097 kg/m³ (±0.06%) in the range -35°C to 100°C
299 | EthyleneGlycol_Dens = 1001.1409640659 + 179.444904879415 * VolFraction - 0.182158011573945 * T_C - 0.314100479180544 * T_C * VolFraction - 2.44011693274942E-03 * T_C ^ 2 - 38.9624042140087 * VolFraction ^ 2
300 | End If
301 | End Function
302 |
303 | Public Function EthyleneGlycol_Cp#(T_C#, VolFraction#)
304 | 'EthyleneGlycol_Cp [J/kgK] = Specific heat capacity of aqueous solution of ethylene glycol coolant/antifreeze
305 | 'INPUTS:
306 | '- T_C [°C] = Temperature of aqueous solution.
307 | '- VolFraction [-] = Volume fraction of ethylene glycol, in the range 0 to 1.
308 | 'NOTE: You can first find the minimum required value of VolFraction with function EthyleneGlycol_VolFraction(T_C)
309 |
310 | If T_C < -35 Or 100 < T_C Then
311 | EthyleneGlycol_Cp = ErrorMsg("T_C out of range in EthyleneGlycol_Cp. T_C = " & T_C & " °C")
312 | ElseIf VolFraction < 0 Or 0.9 < VolFraction Then
313 | EthyleneGlycol_Cp = ErrorMsg("VolFraction out of range in EthyleneGlycol_Cp. VolFraction = " & VolFraction)
314 | Else
315 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, Section 31
316 | 'Fitted by symbolic regression to a polynomial by Eureqa (https://www.nutonian.com/products/eureqa/)
317 | 'Statistics: R²=0.9999987; Max error = ±1.4920783 J/kgK (±0.037%) in the range -35°C to 100°C
318 | EthyleneGlycol_Cp = 4097.79502411204 + 1.19750661201195 * T_C + 5.61124881968268 * T_C * VolFraction - 1557.90516584712 * VolFraction - 461.188951269786 * VolFraction ^ 2 - 0.558537199166186 * T_C * VolFraction ^ 2
319 | End If
320 | End Function
321 |
322 | Public Function EthyleneGlycol_Conduct#(T_C#, VolFraction#)
323 | 'EthyleneGlycol_Conduct [W/mK] = Thermal conductivity of aqueous solution of ethylene glycol coolant/antifreeze
324 | 'INPUTS:
325 | '- T_C [°C] = Temperature of aqueous solution.
326 | '- VolFraction [-] = Volume fraction of ethylene glycol, in the range 0 to 1.
327 | 'NOTE: You can first find the minimum required value of VolFraction with function EthyleneGlycol_VolFraction(T_C)
328 |
329 | If T_C < -35 Or 100 < T_C Then
330 | EthyleneGlycol_Conduct = ErrorMsg("T_C out of range in EthyleneGlycol_Conduct. T_C = " & T_C & " °C")
331 | ElseIf VolFraction < 0 Or 0.9 < VolFraction Then
332 | EthyleneGlycol_Conduct = ErrorMsg("VolFraction out of range in EthyleneGlycol_Conduct. VolFraction = " & VolFraction)
333 | Else
334 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, Section 31
335 | 'Fitted by symbolic regression to a polynomial by Eureqa (https://www.nutonian.com/products/eureqa/)
336 | 'Statistics: R²=0.99995783; Max error = ±0.00253363 W/mK (±0.8%) in the range -35°C to 100°C
337 | EthyleneGlycol_Conduct = 0.562795658206869 + 1.89231603003848E-03 * T_C + 0.206393536467352 * VolFraction ^ 2 + 8.32696279315093E-04 * T_C * VolFraction ^ 2 + 7.24337888092844E-06 * VolFraction * T_C ^ 2 - 0.524076791259904 * VolFraction - 2.61949570275199E-03 * T_C * VolFraction - 7.14058837551305E-06 * T_C ^ 2
338 | End If
339 | End Function
340 |
341 | Public Function EthyleneGlycol_DynaVisc#(T_C#, VolFraction#)
342 | 'EthyleneGlycol_DynaVisc [Pa·s] = Dynamic viscosity of aqueous solution of ethylene glycol coolant/antifreeze
343 | 'INPUTS:
344 | '- T_C [°C] = Temperature of aqueous solution.
345 | '- VolFraction [-] = Volume fraction of ethylene glycol, in the range 0 to 1.
346 | 'NOTE: You can first find the minimum required value of VolFraction with function EthyleneGlycol_VolFraction(T_C)
347 |
348 | Dim Tr# 'reciprocal temperature deviation
349 |
350 | If T_C < -35 Or 100 < T_C Then
351 | EthyleneGlycol_DynaVisc = ErrorMsg("T_C out of range in EthyleneGlycol_DynaVisc. T_C = " & T_C & " °C")
352 | ElseIf VolFraction < 0 Or 0.9 < VolFraction Then
353 | EthyleneGlycol_DynaVisc = ErrorMsg("VolFraction out of range in EthyleneGlycol_Dynavisc. VolFraction = " & VolFraction)
354 | Else
355 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, Section 31
356 | 'Fitted by symbolic regression with Eureqa (https://www.nutonian.com/products/eureqa/)
357 | 'Statistics: R²=0.99950351; Max error = ±0.19262573 Pa·s (Mean ±2.36%) in the range -35°C to 100°C
358 | Tr = 1 / (113.365314457654 + T_C)
359 | EthyleneGlycol_DynaVisc = Exp(-28853.879497481 * VolFraction * Tr * Tr + (377.303159990392 + 849.345796155349 * VolFraction) * Tr - 9.84889759113783 - 1.73736446942109 * VolFraction)
360 | End If
361 | End Function
362 |
363 | Public Function PropyleneGlycol_VolFraction#(Tfreeze_C#)
364 | 'PropyleneGlycol_VolFraction [-] = Minimum required volume fraction of Propylene Glycol for freezing point Tfreeze_C, valid at standard atmospheric pressure (101325 Pa)
365 | 'INPUTS: Tfreeze_C [°C] = Minimum freezing point
366 |
367 | If Tfreeze_C < -51.1 Or 0 < Tfreeze_C Then
368 | PropyleneGlycol_VolFraction = ErrorMsg("Tfreeze_C out of range in PropyleneGlycol_VolFraction. Tfreeze_C = " & Tfreeze_C & " K")
369 | Else
370 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, Page 31.6
371 | 'Fitted by symbolic regression to a rational function using https://github.com/SchildCode/RatFun-Regression
372 | 'Statistics: R²=0.999973663; Max error = ±0.003282686 [Volume fraction] in the range -51°C to 0°C
373 | PropyleneGlycol_VolFraction = (Tfreeze_C * (-2.93493229032601E-02 - 1.59432533823575E-04 * Tfreeze_C ^ 2)) / (1 + Tfreeze_C ^ 2 * (6.66645351796462E-03 - 1.46482042633864E-04 * Tfreeze_C))
374 | End If
375 | End Function
376 |
377 | Public Function PropyleneGlycol_Dens#(T_C#, VolFraction#)
378 | 'PropyleneGlycol_Dens [kg/m³] = Density of aqueous solution of Propylene glycol coolant/antifreeze
379 | 'INPUTS:
380 | '- T_C [°C] = Temperature of aqueous solution.
381 | '- VolFraction [-] = Volume fraction of Propylene glycol, in the range 0 to 1.
382 | 'NOTE: You can first find the minimum required value of VolFraction with function PropyleneGlycol_VolFraction(T_C)
383 | If T_C < -35 Or 100 < T_C Then
384 | PropyleneGlycol_Dens = ErrorMsg("T_C out of range in PropyleneGlycol_Dens. T_C = " & T_C & " °C")
385 | ElseIf VolFraction < 0 Or 0.9 < VolFraction Then
386 | PropyleneGlycol_Dens = ErrorMsg("VolFraction out of range in PropyleneGlycol_Dens. VolFraction = " & VolFraction)
387 | Else
388 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, Section 31
389 | 'Fitted by symbolic regression to a polynomial by Eureqa (https://www.nutonian.com/products/eureqa/)
390 | 'Statistics: R²=0.99885777; Max error = ±4.637788 kg/m³ (±0.49%) in the range -35°C to 100°C
391 | PropyleneGlycol_Dens = 1001.60967056623 + 116.278983583743 * VolFraction + 0.003052484815767 * T_C ^ 2 * VolFraction ^ 2 - 8.53826710430915E-02 * T_C - 0.737217611426134 * T_C * VolFraction - 3.19173967918996E-03 * T_C ^ 2 - 53.8301051153873 * VolFraction ^ 3
392 | End If
393 | End Function
394 |
395 | Public Function PropyleneGlycol_Cp#(T_C#, VolFraction#)
396 | 'PropyleneGlycol_Cp [J/kgK] = Specific heat capacity of aqueous solution of Propylene glycol coolant/antifreeze
397 | 'INPUTS:
398 | '- T_C [°C] = Temperature of aqueous solution.
399 | '- VolFraction [-] = Volume fraction of Propylene glycol, in the range 0 to 1.
400 | 'NOTE: You can first find the minimum required value of VolFraction with function PropyleneGlycol_VolFraction(T_C)
401 |
402 | If T_C < -35 Or 100 < T_C Then
403 | PropyleneGlycol_Cp = ErrorMsg("T_C out of range in PropyleneGlycol_Cp. T_C = " & T_C & " °C")
404 | ElseIf VolFraction < 0 Or 0.9 < VolFraction Then
405 | PropyleneGlycol_Cp = ErrorMsg("VolFraction out of range in PropyleneGlycol_Cp. VolFraction = " & VolFraction)
406 | Else
407 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, Section 31
408 | 'Fitted by symbolic regression to a polynomial by Eureqa (https://www.nutonian.com/products/eureqa/)
409 | 'Statistics: R²=0.99999523; Max error = ±2.7606174 J/kgK (±0.09%) in the range -35°C to 100°C
410 | PropyleneGlycol_Cp = 4131.79124057325 + 1.0587116373911 * T_C + 5.60018700825693 * T_C * VolFraction - 786.13680726358 * VolFraction - 49.8664661311868 * VolFraction ^ 6 - 1134.40440780431 * VolFraction ^ 2
411 | End If
412 | End Function
413 |
414 | Public Function PropyleneGlycol_Conduct#(T_C#, VolFraction#)
415 | 'PropyleneGlycol_Conduct [W/mK] = Thermal conductivity of aqueous solution of Propylene glycol coolant/antifreeze
416 | 'INPUTS:
417 | '- T_C [°C] = Temperature of aqueous solution.
418 | '- VolFraction [-] = Volume fraction of Propylene glycol, in the range 0 to 1.
419 | 'NOTE: You can first find the minimum required value of VolFraction with function PropyleneGlycol_VolFraction(T_C)
420 |
421 | If T_C < -35 Or 100 < T_C Then
422 | PropyleneGlycol_Conduct = ErrorMsg("T_C out of range in PropyleneGlycol_Conduct. T_C = " & T_C & " °C")
423 | ElseIf VolFraction < 0 Or 0.9 < VolFraction Then
424 | PropyleneGlycol_Conduct = ErrorMsg("VolFraction out of range in PropyleneGlycol_Conduct. VolFraction = " & VolFraction)
425 | Else
426 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, Section 31
427 | 'Fitted by symbolic regression to a polynomial by Eureqa (https://www.nutonian.com/products/eureqa/)
428 | 'Statistics: R²=0.99993905; Max error = ±0.00277531 W/mK (±1%) in the range -35°C to 100°C
429 | PropyleneGlycol_Conduct = 0.566116039484301 + 1.9173284065513E-03 * T_C + 0.20750768738397 * VolFraction ^ 2 + 7.59544959739093E-04 * T_C * VolFraction ^ 2 + 7.25403057090419E-06 * VolFraction * T_C ^ 2 - 0.582804237084253 * VolFraction - 2.63636971222475E-03 * T_C * VolFraction - 7.29003289330946E-06 * T_C ^ 2
430 | End If
431 | End Function
432 |
433 | Public Function PropyleneGlycol_DynaVisc#(T_C#, VolFraction#)
434 | 'PropyleneGlycol_DynaVisc [Pa·s] = Dynamic viscosity of aqueous solution of Propylene glycol coolant/antifreeze
435 | 'INPUTS:
436 | '- T_C [°C] = Temperature of aqueous solution.
437 | '- VolFraction [-] = Volume fraction of Propylene glycol, in the range 0 to 1.
438 | 'NOTE: You can first find the minimum required value of VolFraction with function PropyleneGlycol_VolFraction(T_C)
439 |
440 | Dim Tr# 'reciprocal temperature deviation
441 |
442 | If T_C < -35 Or 100 < T_C Then
443 | PropyleneGlycol_DynaVisc = ErrorMsg("T_C out of range in PropyleneGlycol_DynaVisc. T_C = " & T_C & " °C")
444 | ElseIf VolFraction < 0 Or 0.9 < VolFraction Then
445 | PropyleneGlycol_DynaVisc = ErrorMsg("VolFraction out of range in PropyleneGlycol_DynaVisc. VolFraction = " & VolFraction)
446 | Else
447 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, Section 31
448 | 'Fitted by symbolic regression with Eureqa (https://www.nutonian.com/products/eureqa/)
449 | 'Statistics: R²=0.99925065; Max error = ±0.27060081 Pa·s (Mean ±3.7%) in the range -35°C to 100°C
450 | Tr = 1 / (216.452232513663 + T_C)
451 | PropyleneGlycol_DynaVisc = Exp(391867.744949403 * Tr * Tr + (1834.88325375033 * VolFraction - 1809.46299784498) * Tr - 6.32340689214633 - 3.83110457708013 * VolFraction)
452 | End If
453 | End Function
454 |
455 | '-----------------------------
456 | 'REFRIGERANTS
457 | '-----------------------------
458 |
459 | Function Refrigerant_Sbubble#(Refrigerant$, TK#)
460 | 'Refrigerant_Sbubble [kJ/kg] = Bubble-point entropy, i.e. left side of Ts-diagram
461 | 'INPUTS:
462 | '- Refrigerant [string] = Refrigerant ASHRAE-code e.g. "R410a"
463 | '- TK [K] = Refrigerant temperature at bubble-point [K]
464 | 'SOURCE: Fitted to tables in ASHRAE Handbook Fundamentals, 2017, Chapter 30
465 | 'NOTE: Equations generated by symbolic regression with https://github.com/SchildCode/RatFun-Regression:
466 | ' Average statistics for all 9 refrigerants: R² = 0.9992, Max Absolute Error = ±0.038 kJ/kg over the whole temperature range
467 | 'AUTHOR: P.G.Schild, 2020
468 |
469 | Dim Tr# 'Complement to 1 of reducted temperature, i.e. 1 - (T [K] / Tcritical [K]), where Tcritical is the refrigerant's critical point
470 | Dim Sc# 'Entropy at refrigerant's critical point [kJ/(kgK)]
471 |
472 | Select Case Refrigerant
473 | Case "R32" 'CAS# 75-10-5: HFC "Difluoromethane", https://echa.europa.eu/substance-information/-/substanceinfo/100.000.764
474 | Tr = usrMaxDbl(0, 1 - TK / 351.26)
475 | Sc = 1.6486
476 | Refrigerant_Sbubble = Sc - (Tr * (15.1860219519526 + Tr * (143.148871606057 + 154.369735731194 * Tr * Tr * Tr))) / (1 + Tr * (68.0718307045745 + 2.08783990667309 * Tr))
477 | Case "R134a" 'CAS# 811-97-2: HFC "Norflurane" aka 1,1,1,2-Tetrafluoroethane, https://echa.europa.eu/substance-information/-/substanceinfo/100.011.252
478 | Tr = usrMaxDbl(0, 1 - TK / 374.2)
479 | Sc = 1.5621
480 | Refrigerant_Sbubble = Sc - (Tr * (9.66688452454042 + Tr * (124.51193401481 + 87.882560248025 * Tr * Tr * Tr))) / (1 + Tr * (75.6962662137555 - 5.77561006753399 * Tr))
481 | Case "R290" 'CAS# 74-98-6: HC Propane, https://echa.europa.eu/substance-information/-/substanceinfo/100.000.753
482 | Tr = usrMaxDbl(0, 1 - TK / 369.89)
483 | Sc = 2.0516
484 | Refrigerant_Sbubble = Sc - (Tr * (8.56145481255502 + Tr * (35.510705198475 + 18.5210905201964 * Tr * Tr * Tr))) / (1 + Tr * (14.2493896051139 - 3.94295854870169 * Tr))
485 | Case "R407c" 'Zerotropic HFC blend R-32+125+134a (23±2/25±2/52±2%), https://en.wikipedia.org/wiki/R-407C
486 | Tr = usrMaxDbl(0, 1 - TK / 359.18)
487 | Sc = 1.5384
488 | Refrigerant_Sbubble = Sc - (Tr * (12.0937091475015 + Tr * (144.068346027271 + 132.520960498277 * Tr * Tr * Tr))) / (1 + Tr * (83.4894309710863 - 1.27877450209623 * Tr))
489 | Case "R410a" 'Zerotropic HFC blend R-32+125 (50+.5,–1.5/50+1.5,–.5%), https://en.wikipedia.org/wiki/R-410A
490 | Tr = usrMaxDbl(0, 1 - TK / 344.51)
491 | Sc = 1.5181
492 | Refrigerant_Sbubble = Sc - (Tr * (11.8920967219117 + Tr * (105.378762642689 + 92.8988132330928 * Tr * Tr * Tr))) / (1 + Tr * (61.7062405514335 - 5.41121070779363 * Tr))
493 | Case "R600" 'CAS# 106-97-8: Butane, https://echa.europa.eu/substance-information/-/substanceinfo/100.003.136
494 | Tr = usrMaxDbl(0, 1 - TK / 425.13)
495 | Sc = 2.3631
496 | Refrigerant_Sbubble = Sc - (Tr * (11.7531025603875 + Tr * (146.664843481129 + 96.5147138011199 * Tr * Tr * Tr))) / (1 + Tr * (44.9953777537236 + 1.32317305669742 * Tr))
497 | Case "R600a" 'CAS# 75-28-5: Isobutane, https://echa.europa.eu/substance-information/-/substanceinfo/100.000.780
498 | Tr = usrMaxDbl(0, 1 - TK / 407.81)
499 | Sc = 2.2259
500 | Refrigerant_Sbubble = Sc - (Tr * (16.6771635516396 + Tr * (269.516471103558 + 154.474379472207 * Tr * Tr * Tr))) / (1 + Tr * (83.3067470338159 + 4.12393369005376 * Tr))
501 | Case "R717" 'CAS# 7664-41-7: Ammonia (NH3), https://echa.europa.eu/substance-information/-/substanceinfo/100.028.760
502 | Tr = usrMaxDbl(0, 1 - TK / 405.4)
503 | Sc = 3.5542
504 | Refrigerant_Sbubble = Sc - (Tr * (46.6217766617561 + Tr * (320.380840016196 + 146.290765084784 * Tr * Tr * Tr))) / (1 + Tr * (62.3383436370725 - 17.1613521295301 * Tr))
505 | Case "R744" 'CAS# 124-38-9: Carbon dioxide (CO2), https://echa.europa.eu/substance-information/-/substanceinfo/100.004.271
506 | Tr = usrMaxDbl(0, 1 - TK / 304.13)
507 | Sc = 1.4336
508 | Refrigerant_Sbubble = Sc - (Tr * (27.1966097899245 + Tr * (361.985272011556 + 889.007724088429 * Tr * Tr * Tr))) / (1 + Tr * (133.382664055875 + 48.0011035103798 * Tr))
509 | Case Else
510 | MsgBox "Refrigerant '" & Refrigerant & "' is not in database", vbExclamation
511 | End Select
512 | End Function
513 |
514 | Function Refrigerant_Sdew#(Refrigerant$, TK#)
515 | 'Refrigerant_Sdew [kJ/kgK] = Dew-point entropy, i.e. right side of Ts-diagram
516 | 'INPUTS:
517 | '- Refrigerant [string] = Refrigerant ASHRAE-code e.g. "R410a"
518 | '- TK [K] = Refrigerant temperature at dew-point [K]
519 | 'SOURCE: Fitted to tables in ASHRAE Handbook Fundamentals, 2017, Chapter 30
520 | 'NOTE: Equations generated by symbolic regression with https://github.com/SchildCode/RatFun-Regression:
521 | ' Average statistics for all 9 refrigerants: R² = 0.9992, Max Absolute Error = ±0.038 kJ/kg over the whole temperature range
522 | 'AUTHOR: P.G.Schild, 2020
523 |
524 | Dim Tr# 'Complement to 1 of reducted temperature, i.e. 1 - (T [K] / Tcritical [K]), where Tcritical is the refrigerant's critical point
525 | Dim Sc# 'Entropy at refrigerant's critical point [kJ/(kgK)]
526 |
527 | Select Case Refrigerant
528 | Case "R32" 'CAS# 75-10-5: HFC "Difluoromethane", https://echa.europa.eu/substance-information/-/substanceinfo/100.000.764
529 | Tr = usrMaxDbl(0, 1 - TK / 351.26)
530 | Sc = 1.6486
531 | Refrigerant_Sdew = Sc - (Tr * (-13.242688036753 + Tr * (-7.85942757928493 - 12.9119465504887 * Tr * Tr * Tr))) / (1 + Tr * (33.7237924262883 - 38.0678948048016 * Tr))
532 | Case "R134a" 'CAS# 811-97-2: HFC "Norflurane" aka 1,1,1,2-Tetrafluoroethane, https://echa.europa.eu/substance-information/-/substanceinfo/100.011.252
533 | Tr = usrMaxDbl(0, 1 - TK / 374.2)
534 | Sc = 1.5621
535 | Refrigerant_Sdew = Sc - (Tr * (-9.51052079751144 + Tr * (7.21511712934949 - 84.2188159972129 * Tr * Tr * Tr))) / (1 + Tr * (58.6621646913184 - 51.2420967661778 * Tr))
536 | Case "R290" 'CAS# 74-98-6: HC Propane, https://echa.europa.eu/substance-information/-/substanceinfo/100.000.753
537 | Tr = usrMaxDbl(0, 1 - TK / 369.89)
538 | Sc = 2.0516
539 | Refrigerant_Sdew = Sc - (Tr * (-20.6942057756752 + Tr * (12.70036134274 - 164.688891778152 * Tr * Tr * Tr))) / (1 + Tr * (68.5173216390091 - 60.9109869548097 * Tr))
540 | Case "R407c" 'Zerotropic HFC blend R-32+125+134a (23±2/25±2/52±2%), https://en.wikipedia.org/wiki/R-407C
541 | Tr = usrMaxDbl(0, 1 - TK / 359.18)
542 | Sc = 1.5384
543 | Refrigerant_Sdew = Sc - (Tr * (-10.6594912900386 + Tr * (2.99671314125426 - 39.689391865346 * Tr * Tr * Tr))) / (1 + Tr * (53.9104351779721 - 65.7745697998255 * Tr))
544 | Case "R410a" 'Zerotropic HFC blend R-32+125 (50+.5,–1.5/50+1.5,–.5%), https://en.wikipedia.org/wiki/R-410A
545 | Tr = usrMaxDbl(0, 1 - TK / 344.51)
546 | Sc = 1.5181
547 | Refrigerant_Sdew = Sc - (Tr * (-9.06033100087089 + Tr * (-1.98308659288065 - 21.3907718089308 * Tr * Tr * Tr))) / (1 + Tr * (36.5331745192676 - 42.3686508350456 * Tr))
548 | Case "R600" 'CAS# 106-97-8: Butane, https://echa.europa.eu/substance-information/-/substanceinfo/100.003.136
549 | Tr = usrMaxDbl(0, 1 - TK / 425.13)
550 | Sc = 2.3631
551 | Refrigerant_Sdew = Sc - (Tr * (-15.2969975847954 + Tr * (45.5856679195242 - 227.716934021835 * Tr * Tr * Tr))) / (1 + Tr * (70.1864060308476 - 42.1559614082148 * Tr))
552 | Case "R600a" 'CAS# 75-28-5: Isobutane, https://echa.europa.eu/substance-information/-/substanceinfo/100.000.780
553 | Tr = usrMaxDbl(0, 1 - TK / 407.81)
554 | Sc = 2.2259
555 | Refrigerant_Sdew = Sc - (Tr * (-16.3952941348538 + Tr * (44.8062389226689 - 253.17952957514 * Tr * Tr * Tr))) / (1 + Tr * (76.2734611172978 - 44.2643027129568 * Tr))
556 | Case "R717" 'CAS# 7664-41-7: Ammonia (NH3), https://echa.europa.eu/substance-information/-/substanceinfo/100.028.760
557 | Tr = usrMaxDbl(0, 1 - TK / 405.4)
558 | Sc = 3.5542
559 | Refrigerant_Sdew = Sc - (Tr * (-31.7292833707121 + Tr * (2.12038637392883 + 125.751612531618 * Tr * Tr * Tr))) / (1 + Tr * (23.4298351350206 - 37.2902799144488 * Tr))
560 | Case "R744" 'CAS# 124-38-9: Carbon dioxide (CO2), https://echa.europa.eu/substance-information/-/substanceinfo/100.004.271
561 | Tr = usrMaxDbl(0, 1 - TK / 304.13)
562 | Sc = 1.4336
563 | Refrigerant_Sdew = Sc - (Tr * (-33.5633898829662 + Tr * (-319.312986430669 - 1897.38052550397 * Tr * Tr * Tr))) / (1 + Tr * (128.631833292984 + 222.971101627653 * Tr))
564 | Case Else
565 | MsgBox "Refrigerant '" & Refrigerant & "' is not in database", vbExclamation
566 | End Select
567 | End Function
568 |
569 | Function Refrigerant_CpDew#(Refrigerant$, TK#)
570 | 'Refrigerant_CpDew [kJ/(kgK)] = Refrigerant gas-phase specific heat capacity, at dew-point temperature and pressure
571 | 'INPUTS:
572 | '- Refrigerant [string] = Refrigerant ASHRAE-code e.g. "R410a"
573 | '- TK [K] = Refrigerant temperature at dew-point [K]
574 | 'SOURCE: Fitted to tables in ASHRAE Handbook Fundamentals, 2017, Chapter 30
575 | 'NOTE: Equations generated by symbolic regression with https://github.com/SchildCode/RatFun-Regression:
576 | ' Average statistics for all 9 refrigerants: R² =0.99997, Max Absolute Error = ±0.1196 kJ/kg over the whole temperature range
577 | 'AUTHOR: P.G.Schild, 2020
578 |
579 | Dim Tr# 'Complement to 1 of reducted temperature, i.e. 1 - (T [K] / Tcritical [K]), where Tcritical is the refrigerant's critical point
580 |
581 | Select Case Refrigerant
582 | Case "R32" 'CAS# 75-10-5: HFC "Difluoromethane", https://echa.europa.eu/substance-information/-/substanceinfo/100.000.764
583 | Tr = usrMaxDbl(0, 1 - TK / 351.26)
584 | Refrigerant_CpDew = (1 + 6.92945151413515 * Tr) / (7.95296515498074E-04 + Tr * (7.56906798797785 + Tr * Tr * (41.4119987064445 - 43.6398246025174 * Tr)))
585 | Case "R134a" 'CAS# 811-97-2: HFC "Norflurane" aka 1,1,1,2-Tetrafluoroethane, https://echa.europa.eu/substance-information/-/substanceinfo/100.011.252
586 | Tr = usrMaxDbl(0, 1 - TK / 374.21)
587 | Refrigerant_CpDew = (1 + 11.097341049689 * Tr) / (6.955416937568E-04 + Tr * (14.1851844493013 + Tr * Tr * (36.4167084397886 - 18.6464966625328 * Tr)))
588 | Case "R290" 'CAS# 74-98-6: HC Propane, https://echa.europa.eu/substance-information/-/substanceinfo/100.000.753
589 | Tr = usrMaxDbl(0, 1 - TK / 369.89)
590 | Refrigerant_CpDew = (1 + 8.81128897439505 * Tr) / (-1.71291057253671E-03 + Tr * (6.52239839563111 + Tr * Tr * (13.0520585115035 - 7.71319590930056 * Tr)))
591 | Case "R407c" 'Zerotropic HFC blend R-32+125+134a (23±2/25±2/52±2%), https://en.wikipedia.org/wiki/R-407C
592 | Tr = usrMaxDbl(0, 1 - TK / 359.18)
593 | Refrigerant_CpDew = (1 + 9.63114541187629 * Tr) / (5.71296826196862E-02 + Tr * (12.3247804143034 + Tr * Tr * (39.8238751285889 - 29.611210148231 * Tr)))
594 | Case "R410a" 'Zerotropic HFC blend R-32+125 (50+.5,–1.5/50+1.5,–.5%), https://en.wikipedia.org/wiki/R-410A
595 | Tr = usrMaxDbl(0, 1 - TK / 344.51)
596 | Refrigerant_CpDew = (1 + 7.66354857414616 * Tr) / (-1.14940244991465E-02 + Tr * (10.0247292919728 + Tr * Tr * (25.8576838505004 - 7.36543568651091 * Tr)))
597 | Case "R600" 'CAS# 106-97-8: Butane, https://echa.europa.eu/substance-information/-/substanceinfo/100.003.136
598 | Tr = usrMaxDbl(0, 1 - TK / 425.13)
599 | Refrigerant_CpDew = (1 + 17.1386947248888 * Tr) / (-1.15384435270888E-03 + Tr * (9.34151907884644 + Tr * Tr * (29.2760562576776 - 20.9240025543195 * Tr)))
600 | Case "R600a" 'CAS# 75-28-5: Isobutane, https://echa.europa.eu/substance-information/-/substanceinfo/100.000.780
601 | Tr = usrMaxDbl(0, 1 - TK / 407.81)
602 | Refrigerant_CpDew = (1 + 14.803472846493 * Tr) / (4.07517047136446E-04 + Tr * (8.82622325226665 + Tr * Tr * (23.3969428536691 - 10.3769449798891 * Tr)))
603 | Case "R717" 'CAS# 7664-41-7: Ammonia (NH3), https://echa.europa.eu/substance-information/-/substanceinfo/100.028.760
604 | Tr = usrMaxDbl(0, 1 - TK / 405.4)
605 | Refrigerant_CpDew = (1 + 4.82962793918416 * Tr) / (1.49143706578461E-03 + Tr * (2.15038151957287 + Tr * Tr * (12.967159534515 - 16.9104094739299 * Tr)))
606 | Case "R744" 'CAS# 124-38-9: Carbon dioxide (CO2), https://echa.europa.eu/substance-information/-/substanceinfo/100.004.271
607 | Tr = usrMaxDbl(0, 1 - TK / 304.13)
608 | Refrigerant_CpDew = (1 + 2.48348359150248 * Tr) / (-3.71811874594367E-03 + Tr * (6.70751524823017 + Tr * Tr * (-9.14533639703711 + 27.1182140684234 * Tr)))
609 | Case Else
610 | MsgBox "Refrigerant '" & Refrigerant & "' is not in database", vbExclamation
611 | End Select
612 | End Function
613 |
614 | Function Refrigerant_Hbubble#(Refrigerant$, TK#)
615 | 'Refrigerant_Hbubble [kJ/kgK] = Bubble-point enthalpy, i.e. left side of Ph-diagram
616 | 'INPUTS:
617 | '- Refrigerant [string] = Refrigerant ASHRAE-code e.g. "R410a"
618 | '- TK [K] = Refrigerant temperature at bubble-point [K]
619 | 'SOURCE: Fitted to tables in ASHRAE Handbook Fundamentals, 2017, Chapter 30
620 | 'NOTE: Equations generated by symbolic regression with https://github.com/SchildCode/RatFun-Regression:
621 | ' Average statistics for all 9 refrigerants: R² = 0.9988, Max Absolute Error = ±12.3 kJ/kg over the whole temperature range
622 | 'AUTHOR: P.G.Schild, 2020
623 |
624 | Dim Tr# 'Complement to 1 of reducted temperature, i.e. 1 - (T [K] / Tcritical [K]), where Tcritical is the refrigerant's critical point
625 | Dim Hc# 'Enthalpy at refrigerant's critical point [kJ/(kgK)]
626 |
627 | Select Case Refrigerant
628 | Case "R32" 'CAS# 75-10-5: HFC "Difluoromethane", https://echa.europa.eu/substance-information/-/substanceinfo/100.000.764
629 | Tr = usrMaxDbl(0, 1 - TK / 351.26)
630 | Hc = 414.15
631 | Refrigerant_Hbubble = Hc - (Tr * (5377.91956101175 + Tr * (46617.0249105985 + -26186.6467842203 * Tr + 18897.9434846015 * Tr * Tr))) / (1 + 63.9712636775809 * Tr)
632 | Case "R134a" 'CAS# 811-97-2: HFC "Norflurane" aka 1,1,1,2-Tetrafluoroethane, https://echa.europa.eu/substance-information/-/substanceinfo/100.011.252
633 | Tr = usrMaxDbl(0, 1 - TK / 374.21)
634 | Hc = 389.64
635 | Refrigerant_Hbubble = Hc - (Tr * (3394.72261017963 + Tr * (40801.2388080537 + -20357.687633116 * Tr + 11486.3069162471 * Tr * Tr))) / (1 + 65.6607987817449 * Tr)
636 | Case "R290" 'CAS# 74-98-6: HC Propane, https://echa.europa.eu/substance-information/-/substanceinfo/100.000.753
637 | Tr = usrMaxDbl(0, 1 - TK / 369.89)
638 | Hc = 555.24
639 | Refrigerant_Hbubble = Hc - (Tr * (5980.0523933281 + Tr * (62774.7502810252 + -35878.445484561 * Tr + 17789.013871877 * Tr * Tr))) / (1 + 53.2299251271831 * Tr)
640 | Case "R407c" 'Zerotropic HFC blend R-32+125+134a (23±2/25±2/52±2%), https://en.wikipedia.org/wiki/R-407C
641 | Tr = usrMaxDbl(0, 1 - TK / 359.18)
642 | Hc = 378.48
643 | Refrigerant_Hbubble = Hc - (Tr * (4328.31866498393 + Tr * (52325.3798350729 + -33255.7490812499 * Tr + 24515.5967903022 * Tr * Tr))) / (1 + 81.490354672861 * Tr)
644 | Case "R410a" 'Zerotropic HFC blend R-32+125 (50+.5,–1.5/50+1.5,–.5%), https://en.wikipedia.org/wiki/R-410A
645 | Tr = usrMaxDbl(0, 1 - TK / 344.51)
646 | Hc = 368.55
647 | Refrigerant_Hbubble = Hc - (Tr * (5201.29701026661 + Tr * (56110.3436425771 + -37951.9563805045 * Tr + 29802.5295009664 * Tr * Tr))) / (1 + 86.9160207163079 * Tr)
648 | Case "R600" 'CAS# 106-97-8: Butane, https://echa.europa.eu/substance-information/-/substanceinfo/100.003.136
649 | Tr = usrMaxDbl(0, 1 - TK / 425.13)
650 | Hc = 693.91
651 | Refrigerant_Hbubble = Hc - (Tr * (7474.46863484402 + Tr * (118031.599919433 + -73061.4013453035 * Tr + 36613.5643621172 * Tr * Tr))) / (1 + 82.244230350485 * Tr)
652 | Case "R600a" 'CAS# 75-28-5: Isobutane, https://echa.europa.eu/substance-information/-/substanceinfo/100.000.780
653 | Tr = usrMaxDbl(0, 1 - TK / 407.81)
654 | Hc = 633.94
655 | Refrigerant_Hbubble = Hc - (Tr * (5933.78729020458 + Tr * (81550.6034348199 + -46479.5335661856 * Tr + 19788.1064194294 * Tr * Tr))) / (1 + 62.6569962573858 * Tr)
656 | Case "R717" 'CAS# 7664-41-7: Ammonia (NH3), https://echa.europa.eu/substance-information/-/substanceinfo/100.028.760
657 | Tr = usrMaxDbl(0, 1 - TK / 405.4)
658 | Hc = 1119.22
659 | Refrigerant_Hbubble = Hc - (Tr * (19386.5537852179 + Tr * (141335.503781378 + -51644.2531815673 * Tr + 24630.8411918969 * Tr * Tr))) / (1 + 63.1166522083121 * Tr)
660 | Case "R744" 'CAS# 124-38-9: Carbon dioxide (CO2), https://echa.europa.eu/substance-information/-/substanceinfo/100.004.271
661 | Tr = usrMaxDbl(0, 1 - TK / 304.13)
662 | Hc = 332.25
663 | Refrigerant_Hbubble = Hc - (Tr * (8662.76845072689 + Tr * (122300.527720206 + -140235.701163124 * Tr + 169170.64073272 * Tr * Tr))) / (1 + 140.335963597642 * Tr)
664 | Case Else
665 | MsgBox "Refrigerant '" & Refrigerant & "' is not in database", vbExclamation
666 | End Select
667 | End Function
668 |
669 | Function Refrigerant_Hdew#(Refrigerant$, TK#)
670 | 'Refrigerant_Hdew [kJ/kgK] = Dew-point enthalpy, i.e. right side of Ph-diagram
671 | 'INPUTS:
672 | '- Refrigerant [string] = Refrigerant ASHRAE-code e.g. "R410a"
673 | '- TK [K] = Refrigerant temperature at dew-point [K]
674 | 'SOURCE: Fitted to tables in ASHRAE Handbook Fundamentals, 2017, Chapter 30
675 | 'NOTE: Equations generated by symbolic regression with https://github.com/SchildCode/RatFun-Regression:
676 | ' Average statistics for all 9 refrigerants: R² = 0.9988, Max Absolute Error = ±12.3 kJ/kg over the whole temperature range
677 | 'AUTHOR: P.G.Schild, 2020
678 |
679 | Dim Tr# 'Complement to 1 of reducted temperature, i.e. 1 - (T [K] / Tcritical [K]), where Tcritical is the refrigerant's critical point
680 | Dim Hc# 'Enthalpy at refrigerant's critical point [kJ/(kgK)]
681 |
682 | Select Case Refrigerant
683 | Case "R32" 'CAS# 75-10-5: HFC "Difluoromethane", https://echa.europa.eu/substance-information/-/substanceinfo/100.000.764
684 | Tr = usrMaxDbl(0, 1 - TK / 351.26)
685 | Hc = 414.15
686 | Refrigerant_Hdew = Hc - (Tr * (-5932.29197274236 + Tr * (-7474.14778941814 + 37232.6789055002 * Tr - 22446.5110014522 * Tr * Tr))) / (1 + 54.8880924955789 * Tr)
687 | Case "R134a" 'CAS# 811-97-2: HFC "Norflurane" aka 1,1,1,2-Tetrafluoroethane, https://echa.europa.eu/substance-information/-/substanceinfo/100.011.252
688 | Tr = usrMaxDbl(0, 1 - TK / 374.21)
689 | Hc = 389.64
690 | Refrigerant_Hdew = Hc - (Tr * (-3751.70385782936 + Tr * (5831.65935922266 + 27700.362352493 * Tr - 24202.4102725855 * Tr * Tr))) / (1 + 66.8081879997468 * Tr)
691 | Case "R290" 'CAS# 74-98-6: HC Propane, https://echa.europa.eu/substance-information/-/substanceinfo/100.000.753
692 | Tr = usrMaxDbl(0, 1 - TK / 369.89)
693 | Hc = 555.24
694 | Refrigerant_Hdew = Hc - (Tr * (-6162.54497872838 + Tr * (14556.343263775 + 23814.1304213942 * Tr - 20162.9485399487 * Tr * Tr))) / (1 + 51.8069652067125 * Tr)
695 | Case "R407c" 'Zerotropic HFC blend R-32+125+134a (23±2/25±2/52±2%), https://en.wikipedia.org/wiki/R-407C
696 | Tr = usrMaxDbl(0, 1 - TK / 359.18)
697 | Hc = 378.48
698 | Refrigerant_Hdew = Hc - (Tr * (-4564.27373440949 + Tr * (882.872422159062 + 40394.4185405698 * Tr - 33600.2462786707 * Tr * Tr))) / (1 + 76.2370399341407 * Tr)
699 | Case "R410a" 'Zerotropic HFC blend R-32+125 (50+.5,–1.5/50+1.5,–.5%), https://en.wikipedia.org/wiki/R-410A
700 | Tr = usrMaxDbl(0, 1 - TK / 344.51)
701 | Hc = 368.55
702 | Refrigerant_Hdew = Hc - (Tr * (-3589.75407224144 + Tr * (-1361.38040952226 + 25709.0595297822 * Tr - 18483.9174340378 * Tr * Tr))) / (1 + 50.8134937179985 * Tr)
703 | Case "R600" 'CAS# 106-97-8: Butane, https://echa.europa.eu/substance-information/-/substanceinfo/100.003.136
704 | Tr = usrMaxDbl(0, 1 - TK / 425.13)
705 | Hc = 693.91
706 | Refrigerant_Hdew = Hc - (Tr * (-5333.19521865306 + Tr * (28454.2616111567 + 15346.8792540675 * Tr - 18640.3206761566 * Tr * Tr))) / (1 + 51.9950340400431 * Tr)
707 | Case "R600a" 'CAS# 75-28-5: Isobutane, https://echa.europa.eu/substance-information/-/substanceinfo/100.000.780
708 | Tr = usrMaxDbl(0, 1 - TK / 407.81)
709 | Hc = 633.94
710 | Refrigerant_Hdew = Hc - (Tr * (-5417.04632564831 + Tr * (27151.1755440779 + 18518.992936087 * Tr - 22659.4433334061 * Tr * Tr))) / (1 + 56.7071435554079 * Tr)
711 | Case "R717" 'CAS# 7664-41-7: Ammonia (NH3), https://echa.europa.eu/substance-information/-/substanceinfo/100.028.760
712 | Tr = usrMaxDbl(0, 1 - TK / 405.4)
713 | Hc = 1119.22
714 | Refrigerant_Hdew = Hc - (Tr * (-19517.5661343799 + Tr * (-46893.4973683591 + 164529.226824158 * Tr - 96822.8035355886 * Tr * Tr))) / (1 + 57.1634083848444 * Tr)
715 | Case "R744" 'CAS# 124-38-9: Carbon dioxide (CO2), https://echa.europa.eu/substance-information/-/substanceinfo/100.004.271
716 | Tr = usrMaxDbl(0, 1 - TK / 304.13)
717 | Hc = 332.25
718 | Refrigerant_Hdew = Hc - (Tr * (-9797.0760882652 + Tr * (-46687.6243854889 + 192043.685041829 * Tr - 201038.158033694 * Tr * Tr))) / (1 + 119.839331986652 * Tr)
719 | Case Else
720 | MsgBox "Refrigerant '" & Refrigerant & "' is not in database", vbExclamation
721 | End Select
722 | End Function
723 |
724 | Function Refrigerant_Tdew#(Refrigerant$, Pa#)
725 | 'Refrigerant_Tdew [K] = Dew-point temperature at pressure Pa
726 | 'INPUTS:
727 | '- Refrigerant [string] = Refrigerant ASHRAE-code e.g. "R410a"
728 | '- Pa [Pa] = Fluid pressure
729 | 'SOURCE: Fitted to tables in ASHRAE Handbook Fundamentals, 2017, Chapter 30
730 | 'NOTE: Equations generated by symbolic regression with https://github.com/SchildCode/RatFun-Regression:
731 | ' Average statistics for all 9 refrigerants: R² = 0.9999959, Max Absolute Error = ±1.02% over the whole temperature range
732 | 'AUTHOR: P.G.Schild, 2020
733 |
734 | Dim LnP# 'Natural logarithm of pressure
735 | Dim Tr# 'Complement to 1 of reducted temperature, i.e. 1 - (T [K] / Tcritical [K]), where Tcritical is the refrigerant's critical point => T = (1-Tr)*Tcritical
736 |
737 | LnP = Log(Pa)
738 | Select Case Refrigerant
739 | Case "R32" 'CAS# 75-10-5: HFC "Difluoromethane", https://echa.europa.eu/substance-information/-/substanceinfo/100.000.764
740 | Tr = (0.679844283196794 + LnP * (-5.58845879396756E-02 + 7.83846230683479E-04 * LnP)) / (1 + LnP * (-0.058449789491908 + 3.39983403637178E-05 * LnP * LnP))
741 | Refrigerant_Tdew = (1 - Tr) * 351.26
742 | Case "R134a" 'CAS# 811-97-2: HFC "Norflurane" aka 1,1,1,2-Tetrafluoroethane, https://echa.europa.eu/substance-information/-/substanceinfo/100.011.252
743 | Tr = (0.667225210249668 + LnP * (-6.06969167260545E-02 + 1.1065288032365E-03 * LnP)) / (1 + LnP * (-6.35333949333943E-02 + 4.54252966222158E-05 * LnP * LnP))
744 | Refrigerant_Tdew = (1 - Tr) * 374.21
745 | Case "R290" 'CAS# 74-98-6: HC Propane, https://echa.europa.eu/substance-information/-/substanceinfo/100.000.753
746 | Tr = (0.710757891310966 + LnP * (-6.85824911274988E-02 + 1.44282118828316E-03 * LnP)) / (1 + LnP * (-0.068752540282851 + 5.88631458267534E-05 * LnP * LnP))
747 | Refrigerant_Tdew = (1 - Tr) * 369.89
748 | Case "R407c" 'Zerotropic HFC blend R-32+125+134a (23±2/25±2/52±2%), https://en.wikipedia.org/wiki/R-407C
749 | Tr = (0.709718826194877 + LnP * (-8.28796136812859E-02 + 2.38656642321597E-03 * LnP)) / (1 + LnP * (-7.94321671852964E-02 + 8.16006897603657E-05 * LnP * LnP))
750 | Refrigerant_Tdew = (1 - Tr) * 359.18
751 | Case "R410a" 'Zerotropic HFC blend R-32+125 (50+.5,–1.5/50+1.5,–.5%), https://en.wikipedia.org/wiki/R-410A
752 | Tr = (0.706776530734329 + LnP * (-7.37091423758357E-02 + 1.80629447790992E-03 * LnP)) / (1 + LnP * (-7.14304225592101E-02 + 6.27474930697395E-05 * LnP * LnP))
753 | Refrigerant_Tdew = (1 - Tr) * 344.51
754 | Case "R600" 'CAS# 106-97-8: Butane, https://echa.europa.eu/substance-information/-/substanceinfo/100.003.136
755 | Tr = (0.687113813033299 + LnP * (-5.77922827938379E-02 + 8.19787892432219E-04 * LnP)) / (1 + LnP * (-6.01713491355452E-02 + 3.63711221709102E-05 * LnP * LnP))
756 | Refrigerant_Tdew = (1 - Tr) * 425.13
757 | Case "R600a" 'CAS# 75-28-5: Isobutane, https://echa.europa.eu/substance-information/-/substanceinfo/100.000.780
758 | Tr = (0.695367804879725 + LnP * (-6.18585825495433E-02 + 1.04667667420318E-03 * LnP)) / (1 + LnP * (-6.31658257395192E-02 + 4.3238673435457E-05 * LnP * LnP))
759 | Refrigerant_Tdew = (1 - Tr) * 407.81
760 | Case "R717" 'CAS# 7664-41-7: Ammonia (NH3), https://echa.europa.eu/substance-information/-/substanceinfo/100.028.760
761 | Tr = (0.720965429266934 + LnP * (-6.78109905326274E-02 + 1.44191817852209E-03 * LnP)) / (1 + LnP * (-6.53266151696419E-02 + 4.80245842200671E-05 * LnP * LnP))
762 | Refrigerant_Tdew = (1 - Tr) * 405.4
763 | Case "R744" 'CAS# 124-38-9: Carbon dioxide (CO2), https://echa.europa.eu/substance-information/-/substanceinfo/100.004.271
764 | Tr = (0.796087533695876 + LnP * (-9.46618938968321E-02 + 2.80263824593801E-03 * LnP)) / (1 + LnP * (-7.98925937377127E-02 + 7.70146828321376E-05 * LnP * LnP))
765 | Refrigerant_Tdew = (1 - Tr) * 304.13
766 | Case Else
767 | MsgBox "Refrigerant '" & Refrigerant & "' is not in database", vbExclamation
768 | End Select
769 | End Function
770 |
771 | Function Refrigerant_Pdew#(Refrigerant$, TK#)
772 | 'Refrigerant_Pdew [Pa] = Stauration pressure given dew-point temperature
773 | 'INPUTS:
774 | '- Refrigerant [string] = Refrigerant ASHRAE-code e.g. "R410a"
775 | '- TK [K] = Refrigerant temperature at dew-point [K]
776 | 'SOURCE: Fitted to tables in ASHRAE Handbook Fundamentals, 2017, Chapter 30
777 | 'NOTE: Equations generated by symbolic regression with https://github.com/SchildCode/RatFun-Regression:
778 | ' Average statistics for all 9 refrigerants: R² = 0.99998, Max Absolute Error = ±2.5% over the whole temperature range
779 | 'AUTHOR: P.G.Schild, 2020
780 |
781 | Dim Tr# 'Complement to 1 of reducted temperature, i.e. 1 - (T [K] / Tcritical [K]), where Tcritical is the refrigerant's critical point
782 |
783 | Select Case Refrigerant
784 | Case "R32" 'CAS# 75-10-5: HFC "Difluoromethane", https://echa.europa.eu/substance-information/-/substanceinfo/100.000.764
785 | Tr = usrMaxDbl(0, 1 - TK / 351.26)
786 | Refrigerant_Pdew = Exp((15.5679015085583 + Tr * (-25.4660296027275 + 3.41848099187946 * Tr)) / (1 + Tr * (-1.17781759148254 + 0.199106729606217 * Tr * Tr)))
787 | Case "R134a" 'CAS# 811-97-2: HFC "Norflurane" aka 1,1,1,2-Tetrafluoroethane, https://echa.europa.eu/substance-information/-/substanceinfo/100.011.252
788 | Tr = usrMaxDbl(0, 1 - TK / 374.21)
789 | Refrigerant_Pdew = Exp((15.2139089053916 + Tr * (-25.5779302544142 + 3.41000371520309 * Tr)) / (1 + Tr * (-1.20224568507009 + 0.219248651387827 * Tr * Tr)))
790 | Case "R290" 'CAS# 74-98-6: HC Propane, https://echa.europa.eu/substance-information/-/substanceinfo/100.000.753
791 | Tr = usrMaxDbl(0, 1 - TK / 369.89)
792 | Refrigerant_Pdew = Exp((15.2724550053966 + Tr * (-25.7351896405739 + 5.65883114288467 * Tr)) / (1 + Tr * (-1.2400437455292 + 0.405468927677945 * Tr * Tr)))
793 | Case "R407c" 'Zerotropic HFC blend R-32+125+134a (23±2/25±2/52±2%), https://en.wikipedia.org/wiki/R-407C
794 | Tr = usrMaxDbl(0, 1 - TK / 359.18)
795 | Refrigerant_Pdew = Exp((15.3325241166998 + Tr * (-27.1862368342962 + 6.42493846609803 * Tr)) / (1 + Tr * (-1.26428115966836 + 0.542121403495998 * Tr * Tr)))
796 | Case "R410a" 'Zerotropic HFC blend R-32+125 (50+.5,–1.5/50+1.5,–.5%), https://en.wikipedia.org/wiki/R-410A
797 | Tr = usrMaxDbl(0, 1 - TK / 344.51)
798 | Refrigerant_Pdew = Exp((15.4031140650565 + Tr * (-25.4339253254685 + 3.46422969441002 * Tr)) / (1 + Tr * (-1.18439981904375 + 0.229629594514814 * Tr * Tr)))
799 | Case "R600" 'CAS# 106-97-8: Butane, https://echa.europa.eu/substance-information/-/substanceinfo/100.003.136
800 | Tr = usrMaxDbl(0, 1 - TK / 425.13)
801 | Refrigerant_Pdew = Exp((15.146247415958 + Tr * (-24.3915197064474 + 2.97147304394632 * Tr)) / (1 + Tr * (-1.16842463610541 + 0.158007448008371 * Tr * Tr)))
802 | Case "R600a" 'CAS# 75-28-5: Isobutane, https://echa.europa.eu/substance-information/-/substanceinfo/100.000.780
803 | Tr = usrMaxDbl(0, 1 - TK / 407.81)
804 | Refrigerant_Pdew = Exp((15.1025063119411 + Tr * (-24.204066495443 + 2.91816443423455 * Tr)) / (1 + Tr * (-1.16617077579373 + 0.165662127255591 * Tr * Tr)))
805 | Case "R717" 'CAS# 7664-41-7: Ammonia (NH3), https://echa.europa.eu/substance-information/-/substanceinfo/100.028.760
806 | Tr = usrMaxDbl(0, 1 - TK / 405.4)
807 | Refrigerant_Pdew = Exp((16.2418828732019 + Tr * (-25.7300624977046 + 3.02815984009489 * Tr)) / (1 + Tr * (-1.15415860983025 + 0.185327253381788 * Tr * Tr)))
808 | Case "R744" 'CAS# 124-38-9: Carbon dioxide (CO2), https://echa.europa.eu/substance-information/-/substanceinfo/100.004.271
809 | Tr = usrMaxDbl(0, 1 - TK / 304.13)
810 | Refrigerant_Pdew = Exp((15.8130484066556 + Tr * (-22.1723126027072 + 2.6653067678616 * Tr)) / (1 + Tr * (-0.971305513436541 + 0.54929879404179 * Tr * Tr)))
811 | Case Else
812 | MsgBox "Refrigerant '" & Refrigerant & "' is not in database", vbExclamation
813 | End Select
814 | End Function
815 |
816 | '----------------------------
817 | 'DRY AIR
818 | '----------------------------
819 |
820 | Public Function DryAir_Cp#(ByVal Tdry_K#)
821 | 'DryAir_Cp [J/kgK] = Specific heat capacity of dry air, valid at standard atmospheric pressure (101325 Pa)
822 | 'INPUTS: Tdry_K [K] = Air dry-bulb temperature
823 | 'NOTE: This is a fundamental property, based on empirical data
824 |
825 | If Tdry_K < 223.15 Or 473.15 < Tdry_K Then
826 | DryAir_Cp = ErrorMsg("Tdry_K out of range in DryAir_Cp. Tdry_K = " & Tdry_K & " K")
827 | Else
828 | 'REFERENCE: www.engineeringtoolbox.com
829 | 'Fitted by symbolic regression to a rational function using https://github.com/SchildCode/RatFun-Regression
830 | 'Statistics: R²=0.999160, Max deviation = ±0.379 J/kgK in the range 223K to 473K
831 | DryAir_Cp = (1 + Tdry_K ^ 2 * (-1.34590696095301E-04 - 6.28356110944288E-08 * Tdry_K)) / (Tdry_K * (1.18980667754983E-05 - 1.81101111121264E-07 * Tdry_K))
832 | End If
833 | End Function
834 |
835 | Public Function DryAir_Conduct#(ByVal Tdry_K#)
836 | 'DryAir_Conduct [W/mK] = Specific heat capacity of dry air, valid at standard atmospheric pressure (101325 Pa)
837 | 'INPUTS: Tdry_K [K] = Air dry-bulb temperature
838 | 'NOTE: This is a fundamental property, based on empirical data
839 |
840 | If Tdry_K < 225 Or 375 < Tdry_K Then
841 | DryAir_Conduct = ErrorMsg("Tdry_K out of range in DryAir_Conduct. Tdry_K = " & Tdry_K & " K")
842 | Else
843 | 'REFERENCE: www.engineeringtoolbox.com
844 | 'Fitted by symbolic regression to a rational function using https://github.com/SchildCode/RatFun-Regression
845 | 'Statistics: R²=0.999991, Max deviation = ±2.3E-05 W/mK in the range 225K to 375K
846 | DryAir_Conduct = Tdry_K * (9.72161872452033E-05 - 3.26055249878836E-08 * Tdry_K)
847 | End If
848 | End Function
849 |
850 | Public Function DryAir_DynaVisc#(ByVal Tdry_K#)
851 | 'DryAir_DynaVisc [Pa·s] = Dynamic viscosity of dry air, valid at standard atmospheric pressure (101325 Pa)
852 | 'INPUTS: Tdry_K [K] = Air dry-bulb temperature
853 | 'NOTE: This is a fundamental thermophysical property, based on empirical data, because it directly relates to the molecular characteristics and interactions in a fluid, independent of its density
854 |
855 | If Tdry_K < 223.15 Or 373.15 < Tdry_K Then
856 | DryAir_DynaVisc = ErrorMsg("Tdry_K out of range in DryAir_DynaVisc. Tdry_K = " & Tdry_K & " K")
857 | Else
858 | 'REFERENCE: www.engineeringtoolbox.com
859 | 'Fitted by symbolic regression to a rational function using https://github.com/SchildCode/RatFun-Regression
860 | 'Statistics: R²=0.9999925, Max deviation = ±1.27796E-08 Pa·s in the range 223K to 373K
861 | DryAir_DynaVisc = 7.95801050867814E-08 * Tdry_K / (1 + 9.7958282877158E-04 * Tdry_K)
862 | End If
863 | End Function
864 |
865 | Public Function DryAir_KineVisc#(ByVal Tdry_K#)
866 | 'DryAir_KineVisc [m²/s] = Kinematic viscosity of dry air, valid at standard atmospheric pressure (101325 Pa)
867 | 'INPUTS: Tdry_K [K] = Air dry-bulb temperature
868 | 'NOTE: This is strictly a derived property, governed by v = µ / rho, where v=kinematic viscosity [m²/s], µ=dynamic viscosity [Pa·s], rho=density [kg/m³]. However an explicit correlation is given here for efficiency, to avoid having to calculate v(T)=µ(T)/rho(T)
869 |
870 | If Tdry_K < 223.15 Or 373.15 < Tdry_K Then
871 | DryAir_KineVisc = ErrorMsg("Tdry_K out of range in DryAir_KineVisc. Tdry_K = " & Tdry_K & " K")
872 | Else
873 | 'REFERENCE: www.engineeringtoolbox.com
874 | 'Fitted by symbolic regression to a rational function using https://github.com/SchildCode/RatFun-Regression
875 | 'Statistics: R²=0.9999991, Max deviation = ±9.07384E-09 m²/s in the range 223K to 373K
876 | DryAir_KineVisc = 2.27048032645291E-10 * Tdry_K ^ 2 / (1 + 1.0085092689335E-03 * Tdry_K)
877 | End If
878 | End Function
879 |
880 | Public Function DryAir_Pr#(ByVal Tdry_K#)
881 | 'DryAir_Pr [-] = Prandtl number of dry air, valid at standard atmospheric pressure (101325 Pa)
882 | 'INPUTS: Tdry_K [K] = Air dry-bulb temperature
883 | 'NOTE: This is strictly a derived property, governed by:
884 | ' Pr = µ cp / k
885 | 'where:
886 | ' µ = absolute or dynamic viscosity [kg/(m s)]
887 | ' cp = specific heat [J/(kg K)]
888 | ' k = thermal conductivity [W/(m K)]
889 | 'However, an explicit correlation is given here for efficiency, to avoid having to calculate Pr(T) = µ(T)*cp(T)/k(T)
890 |
891 | If Tdry_K < 225 Or 375 < Tdry_K Then
892 | DryAir_Pr = ErrorMsg("Tdry_K out of range in DryAir_Pr. Tdry_K = " & Tdry_K & " K")
893 | Else
894 | 'REFERENCE: https://www.engineeringtoolbox.com/
895 | 'Fitted by symbolic regression to a rational function using https://github.com/SchildCode/RatFun-Regression
896 | 'Statistics: R²=0.99954, Max deviation = ±0.00045 in the range 225K to 375K
897 | DryAir_Pr = (1 + Tdry_K * (3.93117404779956E-02 - 4.19374808883644E-09 * Tdry_K ^ 2)) / 5.97982860437876E-02 * Tdry_K
898 | End If
899 | End Function
900 |
901 | Public Function DryAir_thermDiff#(ByVal Tdry_K#)
902 | 'DryAir_thermDiff [m²/s] = Thermal diffusivity of dry air at standard atmospheric pressure (101325 Pa)
903 | 'INPUTS: Tdry_K [K] = Air dry-bulb temperature
904 | 'NOTE: This is a derived thermophysical property:
905 | ' a = k/(rho·Cp) where a=thermal diffusivity [m²/s], k=thermal conductivity [W/(m·K)], rho=density [kg/m³], Cp=specific heat capacity [J/(kg·K)]
906 |
907 | If Tdry_K < 225 Or 375 < Tdry_K Then
908 | DryAir_thermDiff = ErrorMsg("Tw out of range in DryAir_thermDiff. Tw = " & Tdry_K & " K")
909 | Else
910 | DryAir_thermDiff = DryAir_Conduct(Tdry_K) / (Air_DensH(Tdry_K, 0#, 101325#) * DryAir_Cp(Tdry_K))
911 | End If
912 | End Function
913 |
914 | '----------------------------
915 | 'MOIST AIR
916 | '----------------------------
917 |
918 | Public Function Air_Cp#(ByVal Tdry_K#, ByVal HumidRatio#)
919 | 'Air_Cp [J/kgK] = Specific heat capacity of moist air
920 | 'INPUTS:
921 | '- Tdry_K [K] = Air dry-bulb temperature
922 | '- HumidRatio [kg/kg] = Humidity ratio [kg water vapour / kg dry air]
923 |
924 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, page 1.9, Eqn.(27)
925 | Air_Cp = DryAir_Cp(Tdry_K) + HumidRatio * Vapour_Cp(Tdry_K) '[J/kgK]
926 | End Function
927 |
928 | Public Function Air_Enth#(ByVal Tdry_K#, ByVal HumidRatio#)
929 | 'Air_Enth [J/kg dry air] = Air specific enthalpy per kg dry air
930 | 'INPUTS:
931 | '- Tdry_K [K] = Air dry-bulb temperature
932 | '- HumidRatio [kg/kg] = Humidity ratio [kg water vapour / kg dry air]
933 | 'NOTE: This is strictly a derived thermophysical property, based on integrating dh = cp·dT over over the temperature range from reference state (T=0°C) to T_K. This is complicated by the fact that cp is itself a non-linear function of temperature. Therefore a dedicated correlation is given here
934 |
935 | Dim Tdry_C#
936 |
937 | Tdry_C = Tdry_K - ZeroC
938 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, Page 1.2 and page 1.9 Eqn.(30)
939 | Air_Enth = (1.006 * Tdry_C + HumidRatio * (2501 + 1.86 * Tdry_C)) * 1000 '[J/kg]
940 | End Function
941 |
942 | Public Function Air_DryBulb#(ByVal Enthalpy_Jkg#, ByVal HumidRatio#)
943 | 'Air_DryBulb [K] = Dry-bulb air temperature
944 | 'INPUTS:
945 | '- Enthalpy_Jkg [J/kg] = Air total enthalpy
946 | '- HumidRatio [kg/kg]= Humidity ratio [kg water vapour / kg dry air]
947 |
948 | Dim Tdry_C#
949 |
950 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, page 1.2 and page 1.9 Eqn.(30) inverted
951 | Tdry_C = (Enthalpy_Jkg - HumidRatio * 2501000#) / (1006# + HumidRatio * 1860)
952 | Air_DryBulb = Tdry_C + ZeroC '[degrees Kelvin]
953 | End Function
954 |
955 | Public Function Air_DensH#(ByVal Tdry_K#, ByVal HumidRatio#, ByVal Patm_Pa#)
956 | 'Air_DensH [kg/m³] = Air density, given humidity ratio
957 | 'INPUTS:
958 | '- Tdry_K [K] = Air dry-bulb temperature
959 | '- HumidRatio [kg/kg] = Humidity ratio [kg water vapour / kg dry air]
960 | '- Patm_Pa [Pa] = Atmospheric pressure
961 |
962 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, eqns (9b) and (26)
963 | 'Possible alternative: R.S. Davis, "Equation for the Determination of the Density of Moist Air (1981/91)", Metrologia, 1992, iop.org
964 | Air_DensH = Patm_Pa / (287.042 * Tdry_K * (1 + 1.607858 * HumidRatio)) * (1 + HumidRatio) '[kg/m3]
965 | End Function
966 |
967 | Public Function Air_DensR#(ByVal Tdry_K#, ByVal RH#, ByVal Patm_Pa#)
968 | 'Air_DensR [kg/m³] = Air density, given RH
969 | 'INPUTS:
970 | '- Tdry_K [K] = Air dry-bulb temperature
971 | '- RH [-] = Relative humidity [0 <= fraction <= 1]
972 | '- Patm_Pa [Pa] = Atmospheric pressure
973 |
974 | Dim HumidRatio#
975 |
976 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017
977 | HumidRatio = Air_HumidRatioR(Tdry_K, RH, Patm_Pa) '[kg/kg]
978 | Air_DensR = Air_DensH(Tdry_K, HumidRatio, Patm_Pa) '[kg/m3]
979 | End Function
980 |
981 | Public Function Air_TdewP#(ByVal Tdry_K#, ByVal Pv_Pa#)
982 | 'Air_TdewP [K] = Dew-point (or frost-point) temperature, given parial pressure of vapour
983 | 'NOTE: This function is basically an inverse of function Vapour_Pws(), using Newton Raphson iteration
984 | 'INPUTS:
985 | '- Tdry_K [K] = Air dry-bulb temperature. Used here only as first guess of Tdew
986 | '- Pv_Pa [Pa] = Water vapour partial pressure
987 |
988 | Dim LnP#
989 | Dim iter&
990 | Dim T0#
991 | Dim T1#
992 | Dim f0#
993 | Dim f1# 'deviation Vapour_Pws(Td1)-Pv_Pa [Pa]
994 |
995 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, page 1.10 Eqn.(37) & (38) and refined by root-finding function Vapour_Pws() with Secant method
996 | 'First approximation of Tdew
997 | LnP = Log(Pv_Pa * 0.001)
998 | If Tdry_K < ZeroC Then
999 | T1 = ZeroC + 6.09 + LnP * (12.608 + LnP * 0.4959) 'Eqn.(38) below 0°C
1000 | Else
1001 | T1 = ZeroC + 6.54 + LnP * (14.526 + LnP * (0.7389 + LnP * 0.09486)) + 0.4569 * (Pv_Pa * 0.001) ^ 0.1984 'Eqn.(37) between 0°C and 93°C
1002 | End If
1003 | 'Now refine using Secant method
1004 | 'Benefits of Secant method: (i) almost quadratic convergence, (ii) no need to calculate derivatives, and (iii) converges from a wider range of starting points than Newton't method
1005 | T0 = Tdry_K 'upper limit of Tdew
1006 | f0 = Vapour_Pws(T0) - Pv_Pa
1007 | f1 = Vapour_Pws(T1) - Pv_Pa
1008 | For iter = 1 To 100 'Typically only 4 iterations needed
1009 | Air_TdewP = T1 - f1 * (T1 - T0) / (f1 - f0) 'Secant correction, in a form that minimizes roundoff error
1010 | If Tdry_K < Air_TdewP Then Air_TdewP = Tdry_K
1011 | If Abs(T1 - T0) < 0.001 Then Exit For
1012 | T0 = T1
1013 | T1 = Air_TdewP
1014 | f0 = f1
1015 | f1 = Vapour_Pws(Air_TdewP) - Pv_Pa
1016 | Next
1017 | End Function
1018 |
1019 | Public Function Air_TdewH#(ByVal Tdry_K#, ByVal HumidRatio#, ByVal Patm_Pa#)
1020 | 'Air_TdewH [K] = Dew-point (or frost-point) temperature, given humidity ratio
1021 | 'INPUTS:
1022 | '- Tdry_K [K] = Air dry-bulb temperature
1023 | '- HumidRatio [kg/kg] = Humidity ratio [kg water vapour / kg dry air]
1024 | '- Patm_Pa [Pa] = Atmospheric pressure
1025 |
1026 | Dim Pv# 'Vapour pressure (saturation pressure at dew-point)
1027 |
1028 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, page 1.10 Eqn.(36)
1029 | Pv = Patm_Pa * HumidRatio / (0.621945 + HumidRatio)
1030 | Air_TdewH = Air_TdewP(Tdry_K, Pv)
1031 | End Function
1032 |
1033 | Public Function Air_TdewR#(ByVal Tdry_K#, ByVal RH#)
1034 | 'Air_TdewR [K] = Dew-point (or frost-point) temperature, given RH
1035 | 'INPUTS:
1036 | '- Tdry_K [K] = Air dry-bulb temperature
1037 | '- RH [-] = Relative humidity = Vapour_Pws(Tdew) / Vapour_Pws(Ta) => Vapour_Pws(Tdew) = Vapour_Pws(Ta) * RH => Tdew = Air_TdewP[Vapour_Pws(Tdew)]
1038 |
1039 | Dim Pv# '[Pa] Vapour pressure
1040 |
1041 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, page 1.8 Eqn.(12)
1042 | Pv = Vapour_Pws(Tdry_K) * RH
1043 | Air_TdewR = Air_TdewP(Tdry_K, Pv)
1044 | End Function
1045 |
1046 | Public Function Air_TdewW#(ByVal Tdry_K#, ByVal Twet_K#, ByVal Patm_Pa#)
1047 | 'Air_TdewW [K] = Dew-point (or frost-point) temperature, given wet-bulb temperature
1048 | 'INPUTS:
1049 | '- Tdry_K [K] = Air dry-bulb temperature
1050 | '- Twet_K [K] = Wet-bulb temperature
1051 | '- Patm_Pa [Pa] = Atmospheric air pressure
1052 |
1053 | Dim HumidRatio# '[-] = W = [kg water vapour / kg dry air]
1054 |
1055 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017
1056 | HumidRatio = Air_HumidRatioW(Tdry_K, Twet_K, Patm_Pa)
1057 | Air_TdewW = Air_TdewH(Tdry_K, HumidRatio, Patm_Pa)
1058 | End Function
1059 |
1060 | Public Function Air_HumidRatioR#(ByVal Tdry_K#, ByVal RH#, ByVal Patm_Pa#)
1061 | 'Air_HumidRatioR [kg water vapour / kg dry air] = Humidity ratio of moist air, given RH
1062 | 'INPUTS:
1063 | '- Tdry_K [K] = dry-bulb air temperature
1064 | '- RH [-] = Relative humidity (over liquid water)
1065 | '- Patm_Pa [Pa] = Atmospheric air pressure
1066 |
1067 | Dim Pv# '[Pa] Vapour pressure
1068 |
1069 | If RH <= 0 Then
1070 | Air_HumidRatioR = 0#
1071 | Else
1072 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, page 1.9 Eqn.(20)
1073 | Pv = RH * Vapour_Pws(Tdry_K)
1074 | Air_HumidRatioR = 0.621945 * Pv / (Patm_Pa - Pv)
1075 | End If
1076 | End Function
1077 |
1078 | Public Function Air_HumidRatioD#(ByVal Tdew_K#, ByVal Patm_Pa#)
1079 | 'Air_HumidRatioD [kg water vapour / kg dry air] = Humidity ratio of moist air, given dew-point temperature
1080 | 'INPUTS:
1081 | '- Tdew_K [K] = Air dew-point (or frost-point if over ice below 0°C) temperature
1082 | '- Patm_Pa [Pa] = Atmospheric air pressure
1083 |
1084 | Dim Pvs# 'Saturated vapour pressure at dew-point [Pa]
1085 |
1086 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, page 1.9 Eqn.(20)
1087 | Pvs = Vapour_Pws(Tdew_K, False) '[Pa] Option TRUE if Tdew_K is measured with a chilled mirror hygrometer, as ice can form below 0°C. Default is FALSE
1088 | Air_HumidRatioD = 0.621945 * Pvs / (Patm_Pa - Pvs)
1089 | End Function
1090 |
1091 | Public Function Air_HumidRatioW#(ByVal Tdry_K#, ByVal Twet_K#, ByVal Patm_Pa#)
1092 | 'Air_HumidRatioW [kg water vapour / kg dry air] = Humidity ratio of moist air, given wet-bulb tempeature
1093 | 'INPUTS:
1094 | '- Tdry_K [K] = Air dry-bulb temperature
1095 | '- Twet_K [K] = Air wet-bulb temperature
1096 | '- Patm_Pa [Pa] = Atmospheric air pressure
1097 |
1098 | Dim HumidRatio#
1099 | Dim Wsat# 'Humidity ratio at saturation, at given web bulb temp.
1100 | Dim Pvs#
1101 | Dim Tdry_C#
1102 | Dim Twet_C#
1103 |
1104 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, page 1.9 Eqn.(33) & (35)
1105 | Tdry_C = Tdry_K - ZeroC
1106 | Twet_C = Twet_K - ZeroC
1107 | Pvs = Vapour_Pws(Twet_K) '[Pa] Saturation vapour pressure at wet-bulb temperature
1108 | Wsat = 0.621945 * Pvs / (Patm_Pa - Pvs) '[kg/kg] eqn.(21)
1109 | If Twet_K < 273.16 Then
1110 | 'Alternative formulation for ice-bulb temperature
1111 | Air_HumidRatioW = ((2830 - 0.24 * Twet_C) * Wsat - 1.006 * (Tdry_C - Twet_C)) / (2830 + 1.86 * Tdry_C - 2.1 * Twet_C) 'eqn.(35)
1112 | Else
1113 | 'Note: equation is strictly for water, as is the convention for meteo calculations.
1114 | Air_HumidRatioW = ((2501 - 2.326 * Twet_C) * Wsat - 1.006 * (Tdry_C - Twet_C)) / (2501 + 1.86 * Tdry_C - 4.186 * Twet_C) 'eqn.(33)
1115 | End If
1116 | End Function
1117 |
1118 | Public Function Air_HumidRatioX#(ByVal SpecificHumid#)
1119 | 'Air_HumidRatioX [kg water vapour / kg dry air] = Humidity ratio of moist air, given specific humidity
1120 | 'INPUTS: SpecificHumidity [kg/kg] = X = [kg water vapour / kg moist air]
1121 |
1122 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, page 1.8 Eqn.(9b)
1123 | Air_HumidRatioX = SpecificHumid / (1# - SpecificHumid)
1124 | End Function
1125 |
1126 | Public Function Air_RHd#(ByVal Tdry_K#, ByVal Tdew_K#, Optional ice As Boolean = False)
1127 | 'Air_RHd [-] = Relative humidity (over liquid water), given dew-point temperature
1128 | 'INPUTS:
1129 | '- Tdry_K [K] = Air dry-bulb temperature
1130 | '- Tdew_K [K] = Air dew-point temperature (or frost-point when below 0°C, if option "ice"=TRUE)
1131 | '- ice = TRUE if over ice when below 0°C (e.g. chilled mirror hygrometer), default is FALSE (Meteo data is always over liquid water)
1132 | 'NOTE: This routine applies the fundamental definition of relative humidity.
1133 |
1134 | Dim Pv# 'Vapour pressure (partial pressure at Tdry) = Saturation vapour pressure at dew-point (or frost-point)
1135 | Dim Pvs# 'Saturation vapour pressure
1136 |
1137 | 'Note on Vapour_Pws#(Tdew_K, TRUE or FALSE):
1138 | ' FALSE (default): In meteorology, RH is always defined as humidity over a plane of liquid water (not ice).
1139 | ' TRUE if Tdew is measured with a chilled mirror hygrometer, as ice can form below 0°C.
1140 | 'REFERENCE: Richardson, Knuteson & Tobin, "A Chilled Mirror Dew-point Hygrometer for Field Use", 9th ARM Science Team Meeting Proceedings, San Antonio, Texas, March 22-26, 1999
1141 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, page 1.8 Eqn.(12)
1142 | Pv = Vapour_Pws(Tdew_K, False) 'Option TRUE if Tdew is measured with a chilled mirror hygrometer, as ice can form below 0°C. Default is FALSE
1143 | Pvs = Vapour_Pws(Tdry_K)
1144 | Air_RHd = Pv / Pvs
1145 | End Function
1146 |
1147 | Public Function Air_RHh#(ByVal Tdry_K#, ByVal HumidRatio#, ByVal Patm_Pa#)
1148 | 'Air_RHh [-] = Relative humidity (over liquid water), given humidity ratio
1149 | 'INPUTS:
1150 | '- Tdry_K [K] = Air dry-bulb temperature
1151 | '- Humidratio [kg/kg] = [kg water vapour / kg dry air]
1152 | '- Patm_Pa [Pa] = Atmospheric air pressure
1153 |
1154 | Dim Pv# 'Vapour pressure (partial pressure at Tdry) = Saturation vapour pressure at dew-point (or frost-point)
1155 | Dim Pvs# 'Vapour pressure at saturation
1156 |
1157 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, page 1.8 Eqn.(12) and (20)
1158 | Pv = Patm_Pa * HumidRatio / (0.621945 + HumidRatio)
1159 | Pvs = Vapour_Pws(Tdry_K)
1160 | Air_RHh = Pv / Pvs
1161 | End Function
1162 |
1163 | Public Function Air_RHw#(ByVal Tdry_K#, ByVal Twet_K#, ByVal Patm_Pa#)
1164 | 'Air_RHw [-] = Relative humidity (over liquid water), given wet-bulb temperature
1165 | 'INPUTS:
1166 | '- Tdry_K [K] = Air dry-bulb temperature
1167 | '- Twet_K [K] = Air wet-bulb temperature
1168 | '- Patm_Pa [Pa] = Atmospheric air pressure
1169 |
1170 | Dim HumidRatio# 'Humidity ratio [kg water vapour / kg dry air]
1171 |
1172 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017
1173 | HumidRatio = Air_HumidRatioW(Tdry_K, Twet_K, Patm_Pa)
1174 | Air_RHw = Air_RHh(Tdry_K, HumidRatio, Patm_Pa)
1175 | End Function
1176 |
1177 | Public Function Air_TwetH#(ByVal Tdry_K#, ByVal HumidRatio#, ByVal Patm_Pa#)
1178 | 'Air_TwetH [K] = Wet-bulb temperature, given humidity ratio. Fast iterative reverse calculation by secant method
1179 | 'INPUTS:
1180 | '- Tdry_K [K] = Air dry-bulb temperature
1181 | '- HumidRatio [kg/kg] = [kg water vapour / kg dry air]
1182 | '- Patm_Pa [Pa] = Atmospheric air pressure
1183 |
1184 | Dim Tdew_K#
1185 | Dim iter&
1186 | Dim T0# 'Twet guess [K]
1187 | Dim T1# 'Twet guess [K]
1188 | Dim f0# 'Error function Air_HumidRatioW(T0) - HumidRatio
1189 | Dim f1# 'Error function Air_HumidRatioW(T1) - HumidRatio
1190 | Dim f2# 'Error function Air_HumidRatioW(Air_TwetH) - HumidRatio
1191 |
1192 | Tdew_K = Air_TdewH(Tdry_K, HumidRatio, Patm_Pa)
1193 | If Tdry_K < Tdew_K Then
1194 | Air_TwetH = ErrorMsg("Tdry_K is lower than Tdew_K in Function Air_TwetH")
1195 | Else
1196 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017
1197 | 'We can safely use the Secant method on well-behaved function Vapour_Pws
1198 | 'Benefits of Secant method: (i) almost quadratic convergence, (ii) no need to calculate derivatives, and (iii) converges from a wider range of starting points than Newton't method
1199 | T0 = Tdew_K 'lower bound
1200 | T1 = 0.5 * (Tdew_K + Tdry_K) '2nd guess
1201 | f0 = Air_HumidRatioW(Tdry_K, T0, Patm_Pa) - HumidRatio
1202 | f1 = Air_HumidRatioW(Tdry_K, T1, Patm_Pa) - HumidRatio
1203 | For iter = 1 To 100 'Typically only 4 iterations needed, a limit of 100 absolutely guarantees convergence
1204 | Air_TwetH = T1 - f1 * (T1 - T0) / (f1 - f0) 'Secant correction, in a form that minimizes roundoff error
1205 | If Abs(T1 - T0) < 0.001 Then Exit For
1206 | T0 = T1
1207 | T1 = Air_TwetH
1208 | f0 = f1
1209 | f1 = Air_HumidRatioW(Tdry_K, Air_TwetH, Patm_Pa) - HumidRatio
1210 | Next
1211 | End If
1212 | End Function
1213 |
1214 | Public Function Air_TwetR#(ByVal Tdry_K#, ByVal RH#, ByVal Patm_Pa#)
1215 | 'Air_TwetR [K] = Wet-bulb temperature, given RH
1216 | 'INPUTS:
1217 | '- Tdry_K [K] = Air dry-bulb temperature
1218 | '- RH [-] = Relative humidity
1219 | '- Patm_Pa [Pa] = Atmospheric air pressure
1220 |
1221 | Dim HumidRatio# 'HumidRatio = W = [kg water vapour / kg dry air]
1222 |
1223 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017
1224 | HumidRatio = Air_HumidRatioR(Tdry_K, RH, Patm_Pa)
1225 | Air_TwetR = Air_TwetH(Tdry_K, HumidRatio, Patm_Pa)
1226 | End Function
1227 |
1228 | Public Function Air_TwetD#(ByVal Tdry_K#, ByVal Tdew_K#, ByVal Patm_Pa#)
1229 | 'Air_TwetD [K] = Wet-bulb temperature, given dew-point temperature
1230 | 'INPUTS:
1231 | '- Tdry_K [K] = Air dry-bulb temperature
1232 | '- Tdew_K [K] = Air dew-point temperature
1233 | '- Patm_Pa [Pa] = Atmospheric air pressure
1234 |
1235 | Dim HumidRatio# 'HumidRatio = W = [kg water vapour / kg dry air]
1236 |
1237 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017
1238 | HumidRatio = Air_HumidRatioD(Tdew_K, Patm_Pa)
1239 | Air_TwetD = Air_TwetH(Tdry_K, HumidRatio, Patm_Pa)
1240 | End Function
1241 |
1242 | '------------------------------
1243 | 'CLIMATE/ATMOSPHERIC PROPERTIES
1244 | '------------------------------
1245 |
1246 | Public Function Atmos_Pa#(ByVal Height_over_sea_level_m#)
1247 | 'Atmos_Pa [Pa] = Estimate of standard-atmosphere barometric pressure as a function of height over sea level
1248 | 'INPUTS: Height_over_sea_level_m [m], e.g. height of building or meteo station
1249 |
1250 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, page 1.1, Eqn.(3)
1251 | Atmos_Pa = 101325 * (1 - 0.0000225577 * Height_over_sea_level_m) ^ 5.2559 'Curve fitted to NASA tabulated values at 0m and 11km
1252 | End Function
1253 |
1254 | Public Function Atmos_Pa2#(ByVal Atmos_Pa1#, ByVal Atmos_T1#, ByVal Altitude1_m#, ByVal Altitude2_m#)
1255 | 'Atmos_Pa2 [Pa] = Estimate of atmospheric pressure at altitude 1 (e.g. sea level, og building site) given pressure and temperature at Altitude2 (e.g. station altitude)
1256 | 'NOTE: It takes into account vertical temperature profile, assuming typical moisture content (unsaturated environmental lapse rate).
1257 | 'INPUTS:
1258 | '- Atmos_Pa1 [Pa] = Measured barometric pressure at Altitude1
1259 | '- Atmos_T1 [K] = Measured dry-bulb temperature at Altitude1
1260 | '- Altitude1_m [m] = Altitude at which Atmos_Pa1 and Atmos_T1 are measured
1261 | '- Altitude2_m [m] = Altitude for which you wish to estimate the barometric pressure. Can be higher or lower than Altitude1
1262 | 'REFERENCE: https://en.wikipedia.org/wiki/Barometric_formula
1263 |
1264 | Const ELR# = -0.0065 'Environmental lapse rate, 0.65°C per 100 m in troposhere according to International Standard Atmosphere (https://en.wikipedia.org/wiki/International_Standard_Atmosphere)
1265 | Const molM# = 0.0289644 'molar mass of Earth's air: 0.0289644 kg/mol
1266 | Const uniR# = 8.3144598 'Universal gas constant: 8.3144598 J /mol/K
1267 | Dim Tdry2_K#
1268 |
1269 | Tdry2_K = Atmos_T2(Atmos_T1, Altitude1_m, ByVal Altitude2_m)
1270 | 'Estimates barometric pressure as a function of height over sea level. valid in troposhere, up to 11 km.
1271 | Atmos_Pa2 = Atmos_Pa1 * (Atmos_T1 / Tdry2_K) ^ (9.80665 * molM / (uniR * ELR)) 'barometric formula
1272 | End Function
1273 |
1274 | Public Function Atmos_T#(ByVal Height_over_sea_level_m#)
1275 | 'Atmos_T [K] = Estimate temperature as a function of height over sea level. Valid in troposphere (<11km)
1276 | 'INPUTS: Height_over_sea_level_m [m], e.g. height of building or meteo station
1277 | 'NOTE: This assumes typical moisture content (unsaturated adiabatic lapse rate)
1278 | ' Dry adiabatic lapse rate (DALR) is steeper = g/cp = 9.81/1.006 = 0.009748 °C/m, or about 1 °C/100m
1279 | 'REFERENCE: ASHRAE Handbook Fundamentals 2017, page 1.1 Eqn.(4)
1280 |
1281 | Const ELR# = -0.0065 'Environmental lapse rate, 0.65°C per 100 m in troposhere according to International Standard Atmosphere (https://en.wikipedia.org/wiki/International_Standard_Atmosphere)
1282 |
1283 | Atmos_T = 288.14 + ELR * Height_over_sea_level_m
1284 | End Function
1285 |
1286 | Public Function Atmos_T2#(ByVal Atmos_T1, ByVal Altitude1_m#, ByVal Altitude2_m#)
1287 | 'Atmos_T2 [K] = Estimate of dry-bulb temperature at Altitude2_m given Tdry1_K at Altitude1_m. Assumes Environmental Lapse Rate (ELR)
1288 | 'INPUTS:
1289 | '- Atmos_T1 [K] = Measured dry-bulb temperature at Altitude1
1290 | '- Altitude1_m [m] = Altitude at which Atmos_T1 is measured
1291 | '- Altitude2_m [m] = Altitude for which you wish to estimate temperature Atmos_T2 . Can be higher or lower than Altitude1
1292 | 'REFERENCE: ASbHRAE Handbook Fundamentals 2017, page 1.1 Eqn.(4)
1293 |
1294 | Const ELR# = -0.0065 'Environmental lapse rate, 0.65°C per 100 m in troposhere according to International Standard Atmosphere (https://en.wikipedia.org/wiki/International_Standard_Atmosphere)
1295 |
1296 | Atmos_T2 = Atmos_T1 + ELR * (Altitude2_m - Altitude1_m)
1297 | End Function
1298 |
1299 | Public Function Wind_Loc2_ms#(ByVal Wind_Loc1_ms#, ByVal Alpha_Loc1#, ByVal Alpha_Loc2#, ByVal Height_Loc2_m#)
1300 | 'Wind_Loc2_ms [m/s] = Wind speed at Location 2 given wind speed from 10 m high weather station at Location1.
1301 | 'INPUTS:
1302 | '- Wind_Loc1_ms [m/s] = Wind velocity at location 1 (weather station) at height 10m
1303 | '- Alpha_Loc1 [-] = Power-law wind profile exponent at location 1 (weather station)
1304 | '- Alpha_Loc2 [-] = Power-law wind profile exponent at location 1 (local site)
1305 | '- Height_Loc2_m [m = Height above ground of wind speed at location 2
1306 | 'NOTE: Assumes power-law wind profile. Assumes that all profiles have same gradient wind velocity above boundary layer, over approx 400 m
1307 | ' Not quite as accurate as log-law wind velocity profile, but good for practical use
1308 | 'REFERENCE:
1309 | '- http://en.wikipedia.org/wiki/Wind_profile_power_law
1310 |
1311 | 'Alpha =
1312 | '0.100 Ocean or other body of water with at least 5km of unrestricted expanse
1313 | '0.118 Flat terrain - no obstacles, beach, ice plain, snow field
1314 | '0.149 Open terrain - low grass, field without crop (fallow land)
1315 | '0.150 Flat terrain with some isolated ostacles, e.g. buildings/trees well separated from each other
1316 | '0.160 Flat open country
1317 | '0.170 Open flat country
1318 | '0.182 Roughly open - low crops, low hedges, few trees, very few houses
1319 | '0.200 Rural/countrside with scattered wind breaks (e.g. low buildings, trees)
1320 | '0.218 Rough - high and low crops, large obstacles at distances 15*H, rows of trees, low orchards
1321 | '0.220 Rolling or level surface broken by numerous obstructions, such as trees or small houses
1322 | '0.250 Urban, industrial or forrest landscape
1323 | '0.257 Very rough - obstacles at distances of 10*H, spread wood, farm buildings, vineyards
1324 | '0.313 Closed landscape
1325 | '0.330 City landscape
1326 | '0.350 Centre of large city
1327 | '0.377 City centre - alternated low and highrise
1328 |
1329 | Dim Hg1# 'Gradient height at met station [m]
1330 | Dim Hg2# 'Gradient height at building site [m]
1331 |
1332 | '(1) Estimate gradient heights. Correlation based on Davenport data from 1960, also used in Standard ASCE 7
1333 | Hg1 = -2012.1 * Alpha_Loc1 ^ 2 + 1919.4 * Alpha_Loc1 + 42.444
1334 | Hg2 = -2012.1 * Alpha_Loc2 ^ 2 + 1919.4 * Alpha_Loc2 + 42.444
1335 | '(2) Calculate local velocity at given building height
1336 | Wind_Loc2_ms = Wind_Loc1_ms * (Hg1 / 10) ^ Alpha_Loc1 * (Height_Loc2_m / Hg2) ^ Alpha_Loc2
1337 | End Function
1338 |
1339 | '----------------------------
1340 | 'FLUID FLOW
1341 | '----------------------------
1342 |
1343 | Public Function OrificeMassFlow_m3s(Tappings_str$, DuctDia_m#, OrificeDia_m#, Tdry_K#, RH#, Patm_Pa#, dP_Pa#) As Variant
1344 | 'OrificeMassFlow_m3s [m³/s] = Volumetric air flow rate measured by means of pressure drop over an orifice plate
1345 | 'INPUTS:
1346 | '- Tappings_str = "Corner" for corner tappings, "D & D/2" for D & D/2 tappings, "Flange" for flange tappings
1347 | '- DuctDia_m [m] = Upstream internal duct diameter at working conditions (D)
1348 | '- OrificeDia_m [m] = Diameter of ISO 5167-1 standard orifice at working conditions (d)
1349 | '- Tdry_K [K] = Dry-bulb air temperature upstream of ISO orifice plate
1350 | '- RH [-] = Relative humidity upstream of ISO orifice plate [0 to 1]
1351 | '- Patm_Pa [Pa] = Atmospheric air pressure upstream of ISO orifice plate
1352 | '- dP_Pa [Pa] = Differential pressure measured over ISO standard orifice
1353 | 'REFERENCE: ISO/FDIS 5167-2:2002
1354 | 'Author: Peter.Schild@oslomet.no, 2020
1355 |
1356 | Const Kappa# = 1.4 'Isentropic exponent of air [-]
1357 | Dim e# 'Expansibility factor upstream [-]
1358 | Dim Beta# 'Diameter ratio [-]
1359 | Dim mu# 'Dynamic viscosity upstream of ISO orifice plate [Pa·s]
1360 | Dim rho# 'Air density upstream of ISO orifice plate [kg/m³]
1361 | Dim HumidRatio# 'Humidity ratio upstream of ISO orifice plate [kg/kg]
1362 | Dim C# 'Discharge coefficient for ISO orifice plate, calculated using Reader-Harris/Gallagher equation, depends on Re [-]
1363 | Dim C_infinite# 'Discharge coefficient for ISO orifice plate, when Re is infinite [-]
1364 | Dim L1# 'Quotient of distance of upstream tapping from upstream orifice face, and pipe diameter [m]
1365 | Dim L2# 'Quotient of distance of downstream tapping from downstream orifice face, and pipe diameter [m]
1366 | Dim dummy# 'Dummy variable
1367 | Dim Re# 'Reynolds no. at flow diameter DuctDia_m [nondimensional]
1368 | Dim Invariant# 'Used to speed up iteration loop
1369 | Dim a# 'Parameter in Reader-Harris/Gallaghet equation (C)
1370 | Dim M2# 'Parameter in Reader-Harris/Gallaghet equation (C)
1371 | Dim ErrTxt$ 'Error message
1372 |
1373 | 'Pre-checks for limits of applicability
1374 | ErrTxt = ""
1375 | If OrificeDia_m = 0 Then ErrTxt = "Dia?" 'This row is empty. Just skip
1376 | If DuctDia_m < 0.05 Then ErrTxt = "D<5cm!"
1377 | If 1 < DuctDia_m Then ErrTxt = "D>1m!"
1378 | If OrificeDia_m < 0.0125 Then ErrTxt = "d<12.5cm!"
1379 | If ErrTxt <> "" Then GoTo jumpErr
1380 | Beta = OrificeDia_m / DuctDia_m
1381 | If Beta < 0.1 Then ErrTxt = "d/D< 0.1!"
1382 | If 0.75 < Beta Then ErrTxt = "d/D>0.75!"
1383 | If (Patm_Pa - dP_Pa) / Patm_Pa < 0.75 Then ErrTxt = "high dP!"
1384 | If ErrTxt <> "" Then GoTo jumpErr
1385 |
1386 | 'Precalculations
1387 | e = 1# - (0.351 + 0.256 * Beta ^ 4# + 0.93 * Beta ^ 8#) * (1# - ((Patm_Pa - dP_Pa) / Patm_Pa) ^ (1# / 1.4))
1388 | HumidRatio = Air_HumidRatioR(Tdry_K, RH, Patm_Pa)
1389 | rho = Air_DensH(Tdry_K, HumidRatio, Patm_Pa)
1390 | mu = DryAir_DynaVisc(Tdry_K)
1391 | Invariant = e * OrificeDia_m ^ 2 * Sqr(2 * dP_Pa * rho) / (mu * DuctDia_m * Sqr(1 - Beta ^ 4))
1392 | Select Case Tappings_str
1393 | Case "Corner" 'Corner tappings
1394 | L1 = 0
1395 | L2 = 0
1396 | Case "D & D/2" 'D & D/2' tappings
1397 | L1 = 1
1398 | L2 = 0.47
1399 | Case "Flange" 'Flange tappings
1400 | L1 = 0.0254 / DuctDia_m
1401 | L2 = L1
1402 | Case Else 'error
1403 | ErrTxt = "Tapping type?"
1404 | GoTo jumpErr
1405 | End Select
1406 | M2 = 2# * L2 / (1# - Beta)
1407 | dummy = (0.043 + 0.08 * Exp(-10# * L1) - 0.123 * Exp(-7# * L1)) * Beta ^ 4 / (1# - Beta ^ 4#)
1408 | C_infinite = 0.5961 + 0.0261 * Beta ^ 2# - 0.216 * Beta ^ 8# + dummy - 0.031 * (M2 - 0.8 * M2 ^ 1.1) * Beta ^ 1.3
1409 | If DuctDia_m < 0.07112 Then C_infinite = C_infinite + 0.011 * (0.75 - Beta) * (2.8 - DuctDia_m / 0.0254)
1410 | 'First guess of C, assuming Re is infinite
1411 | C = C_infinite
1412 |
1413 | 'Iteration
1414 | Do
1415 | Re = C * Invariant 'Reynolds number of flow at diameter DuctDia_m
1416 | a = (19000 * Beta / Re) ^ 0.8
1417 | 'Next guess of C, assuming Re
1418 | C = C_infinite + 0.000521 * (1000000# * Beta / Re) ^ 0.7 + (0.0188 + 0.0063 * a) * Beta ^ 3.5 * (1000000# / Re) ^ 0.3 + -0.11 * a * dummy
1419 | Loop Until Abs((Invariant - Re / C) / Invariant) < 0.00000001
1420 |
1421 | 'Post-checks for limits of applicability for Re
1422 | Select Case Tappings_str
1423 | Case "Corner", "D & D/2" 'Corner' or 'D & D/2' tappings
1424 | If Beta < 0.56 Then
1425 | If Re < 5000 Then ErrTxt = "Re<5000!"
1426 | Else
1427 | dummy = 16000 * Beta ^ 2
1428 | If Re < dummy Then ErrTxt = "Re<" & CStr(Int(dummy)) & "!"
1429 | End If
1430 | Case Else 'Flange' tappings
1431 | If Re < 5000 Then
1432 | ErrTxt = "Re<5000!"
1433 | Else
1434 | dummy = 170 * Beta ^ 2 * (DuctDia_m * 1000#)
1435 | If Re < dummy Then ErrTxt = "Re<" & CStr(Int(dummy)) & "!"
1436 | End If
1437 | End Select
1438 | jumpErr:
1439 | If ErrTxt = "" Then
1440 | OrificeMassFlow_m3s = CDbl(onePi * mu * DuctDia_m * Re / (4 * rho)) 'volumetric units
1441 | 'OrificeMassFlow_kgps = CDbl(onePi * mu * DuctDia_m * Re / 4) 'gravimetric units
1442 | Else
1443 | OrificeMassFlow_m3s = CVar(ErrTxt)
1444 | End If
1445 | End Function
1446 |
1447 | Public Function Air_DuctFriction#(FlowRate_m3s#, Diam_m#, Roughness_m#, Tdry_K#, RH#, Patm_Pa#)
1448 | 'Air_DuctFriction [Pa/m] = Pressure drop per meter duct, for airflow in ducts
1449 | 'INPUTS:
1450 | '- FlowRate_m3s [m³/s] = Air volume flow
1451 | '- Diam_m [m] = Internal diameter of round duct (or hydraulic diameter of non-round duct)
1452 | '- Roughness_m [m] = RMS surface roughness of duct
1453 | '- Tdry_K [K] = Dry-bulb air temperature of bulk air flow
1454 | '- RH [-] = Relative humidity upstream of bulk air flow
1455 | '- Patm_Pa [Pa] = Static pressure in duct
1456 | 'Note: To get standard a density of 1.2 kg/m³, use Tdry=293.15, Patm=101325, and RH=0.395122
1457 | 'Note: Typical spiro-duct roughness: 3.53E-7 m for ducts <= 200 mm diameter, and 1.77E-4 for ducts > 200 mm
1458 | 'Author: Peter.Schild@oslomet.no, 2020
1459 |
1460 | Dim ff# 'Darcy friction factor [-]
1461 | Dim Pdyn# 'Dynamic pressure [Pa]
1462 | Dim Re# 'Reynolds number [-]
1463 | Dim darea# 'circulat pipe or duct cross sectionsl flow area [m²]
1464 | Dim rho# 'Density of air [kg/m³]
1465 | Dim HumidRatio# 'Humidity ratio [-]
1466 | Dim vv# 'Kinematic viscosity [m²/s]
1467 | Dim uu# 'Velocity [m/s]
1468 |
1469 | 'Air properties
1470 | HumidRatio = Air_HumidRatioR(Tdry_K, RH, Patm_Pa)
1471 | rho = Air_DensH(Tdry_K, HumidRatio, Patm_Pa)
1472 | vv = DryAir_KineVisc(Tdry_K)
1473 |
1474 | 'Flow properties
1475 | darea = 0.25 * onePi * Diam_m * Diam_m 'Cross section area [m²]
1476 | uu = FlowRate_m3s / darea 'nominal velocity [m/s]
1477 | Re = uu * Diam_m / vv 'Reynolds number [-]
1478 | ff = FrictionFactor(Re, Roughness_m / Diam_m) 'Darcy friction factor [-]
1479 | Pdyn = 0.5 * rho * uu * uu 'Dynamic pressure [Pa]
1480 | Air_DuctFriction = ff * Pdyn / Diam_m '[Pa/m]. Darcy-Weisbach equation: dP/L = f/D*Pdyn
1481 | End Function
1482 |
1483 | Public Function Water_PipeFriction#(FlowRate_m3s#, Diam_m#, Roughness_m#, T_K#)
1484 | 'Water_PipeFriction_Pa [Pa/m] = Pressure drop per meter pipe, for water flow in pipes
1485 | 'INPUTS:
1486 | '- FlowRate_m3s [m³/s] = Water volume flow
1487 | '- Diam_m [m] = Internal diameter of round pipe (or hydraulic diameter of non-round pipe)
1488 | '- Roughness_m [m] = RMS surface roughness of pipe
1489 | '- T_K [K] = Temperature of bulk water flow
1490 | 'Author: Peter.Schild@oslomet.no, 2020
1491 |
1492 | Dim ff# 'Darcy friction factor [-]
1493 | Dim Pdyn# 'Dynamic pressure [Pa]
1494 | Dim Re# 'Reynolds number [-]
1495 | Dim darea# 'circulat pipe or pipe cross sectionsl flow area [m²]
1496 | Dim rho# 'Density of water [kg/m³]
1497 | Dim HumidRatio# 'Humidity ratio [-]
1498 | Dim vv# 'Kinematic viscosity [m²/s]
1499 | Dim uu# 'Velocity [m/s]
1500 |
1501 | 'Water properties
1502 | rho = Water_Dens(T_K)
1503 | vv = Water_KineVisc(T_K)
1504 |
1505 | 'Flow properties
1506 | darea = 0.25 * onePi * Diam_m * Diam_m 'Cross section area [m²]
1507 | uu = FlowRate_m3s / darea 'nominal velocity [m/s]
1508 | Re = uu * Diam_m / vv 'Reynolds number [-]
1509 | ff = FrictionFactor(Re, Roughness_m / Diam_m) 'Darcy friction factor [-]
1510 | Pdyn = 0.5 * rho * uu * uu 'Dynamic pressure [Pa]
1511 | Water_PipeFriction = ff * Pdyn / Diam_m '[Pa/m]. Darcy-Weisbach equation: dP/L = f/D*Pdyn
1512 | End Function
1513 |
1514 | Public Function FrictionFactor#(Re#, relRough#)
1515 | 'FrictionFactor [-] = Darcy friction factor for laminar or turbulent flow calculated with the Colebrook-White equation.
1516 | 'INPUTS:
1517 | '- Re [-] = Reynolds number
1518 | '- relRough [-] = Relative roughness = (RMS roughness, mm) / (Pipe internal diameter, mm)
1519 | 'NOTE: This algorithm has been tested against, and proved simpler and faster than two 3-log-call iterative methods: Serghides's
1520 | 'solution (Steffensen's method), Neta (desctibed by Praks & Brkic), and is more accurate than Serghides.
1521 | 'The reason this method appears to be quicker is that it uses Secant correction already after two logarithms.
1522 | 'Author: Peter.Schild@oslomet.no, 2020
1523 |
1524 | Const TransRe# = 2300
1525 | Const pre1# = 0.868588963806504 '= 2*Log10(e) = 2/Ln(10) Used in solution of turbulent friction factor
1526 | Const epsFA# = 0.000000001 'Absolute limit for convergence
1527 | Dim iter& 'iteration number
1528 | Dim x0# '= 1 / SQRT(ff[n-2])
1529 | Dim x1# '= 1 / SQRT(ff[n-1])
1530 | Dim x2# '= 1 / SQRT(ff[n])
1531 | Dim f0# '=x1-x0
1532 | Dim f1# '=x2-x1
1533 | Dim pre2# 'Precalculated parameter = 2.51 / Re
1534 | Dim pre3# 'Precalculated parameter = (Relative roughness) / 3.71
1535 |
1536 | If Re <= TransRe Then 'Laminar flow
1537 | FrictionFactor = 64# / Re 'Darcy friction factor for laminar flow
1538 | Else 'Turbulent flow
1539 | pre2 = 2.51 / Re
1540 | pre3 = relRough * 0.269541778975741
1541 | 'Quick estimate of initial value of x2=1/SQRT(f) without logarithms or powers. Fitted using Eureka in region 3E3