├── FluidProps_v240508.xlsb ├── README.md └── FluidProps.bas /FluidProps_v240508.xlsb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SchildCode/FluidProps/HEAD/FluidProps_v240508.xlsb -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FluidProps [![DOI](https://zenodo.org/badge/260344331.svg)](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