251 lines
9.2 KiB
C#
251 lines
9.2 KiB
C#
///
|
|
/// Copyright (c) 2013-2015 Sensus Metering Systems
|
|
///
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using log4net;
|
|
|
|
namespace TBF.BenchControl
|
|
{
|
|
public static class Formulas
|
|
{
|
|
private static readonly ILog log = LogManager.GetLogger(typeof(Formulas));
|
|
|
|
///
|
|
/// Tables to calculate specific enthalpy
|
|
///
|
|
private static readonly int[] Ii;
|
|
private static readonly int[] Ji;
|
|
private static readonly double[] ni;
|
|
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
static Formulas()
|
|
{
|
|
///
|
|
/// Initialize tables to calculate specific enthalpies
|
|
///
|
|
Ii = new int[34] { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 8, 8, 21, 23, 29, 30, 31, 32 };
|
|
Ji = new int[34] { -2, -1, 0, 1, 2, 3, 4, 5, -9, -7, -1, 0, 1, 3, -3, 0, 1, 3, 17, -4, 0, 6, -5, -2, 10, -8, -11, -6, -29, -31, -38, -39, -40, -41 };
|
|
ni = new double[34] {
|
|
0.14632971213167, /// 1
|
|
-0.84548187169114, /// 2
|
|
-0.37563603672040E1, /// 3
|
|
0.33855169168385E1, /// 4
|
|
-0.95791963387872, /// 5
|
|
0.15772038513228, /// 6
|
|
-0.16616417199501E-1, /// 7
|
|
0.81214629983568E-3, /// 8
|
|
0.28319080123804E-3, /// 9
|
|
-0.60706301565874E-3, /// 10
|
|
-0.18990068218419E-1, /// 11
|
|
-0.32529748770505E-1, /// 12
|
|
-0.21841717175414E-1, /// 13
|
|
-0.52838357969930E-4, /// 14
|
|
-0.47184321073267E-3, /// 15
|
|
-0.30001780793026E-3, /// 16
|
|
0.47661393906987E-4, /// 17
|
|
-0.44141845330846E-5, /// 18
|
|
-0.72694996297594E-15, /// 19
|
|
-0.31679644845054E-4, /// 20
|
|
-0.28270797985312E-5, /// 21
|
|
-0.85205128120103E-9, /// 22
|
|
-0.22425281908000E-5, /// 23
|
|
-0.65171222895601E-6, /// 24
|
|
-0.14341729937924E-12, /// 25
|
|
-0.40516996860117E-6, /// 26
|
|
-0.12734301741641E-8, /// 27
|
|
-0.17424871230634E-9, /// 28
|
|
-0.68762131295531E-18, /// 29
|
|
0.14478307828521E-19, /// 30
|
|
0.26335781662795E-22, /// 31
|
|
-0.11947622640071E-22, /// 32
|
|
0.18228094581404E-23, /// 33
|
|
-0.93537087292458E-25, /// 34
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculate density of distilled water from temperature
|
|
/// </summary>
|
|
/// <param name="t">Temperature in [degC]</param>
|
|
/// <returns>Density in [kg/m3]</returns>
|
|
public static double DistilledWaterDensityFromTemp(float t)
|
|
{
|
|
double tt = (double)t;
|
|
const double a0 = 999.842594;
|
|
const double a1 = 0.06793952;
|
|
const double a2 = -0.00909529;
|
|
const double a3 = 0.0001001685;
|
|
const double a4 = -0.000001120083;
|
|
const double a5 = 6.536332e-09;
|
|
|
|
return ((((a5 * tt + a4) * tt + a3) * tt + a2) * tt + a1) * tt + a0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculate corrected (real) water density from temperature
|
|
/// </summary>
|
|
/// <param name="t">Temperature in [degC]</param>
|
|
/// <returns>Density in [kg/m3]</returns>
|
|
public static double WaterDensityFromTemp(float t)
|
|
{
|
|
double realDensity = Program.LocalSettings.RealDensity;
|
|
float atTemperature = Program.LocalSettings.AtTemperature;
|
|
|
|
double c_rho = realDensity / DistilledWaterDensityFromTemp(atTemperature);
|
|
|
|
return c_rho * DistilledWaterDensityFromTemp(t);
|
|
}
|
|
|
|
|
|
public static float AirDensityFromAmbientVales(float tempC, float pressureBar, float humiPct)
|
|
{
|
|
double pressurePa = 100000.0 * (double)pressureBar; /// [Pa]
|
|
double tempKelvin = 273.15 + (double)tempC;
|
|
double coef1 = 1.2811805 / 10000.0 * tempKelvin * tempKelvin
|
|
- 1.950987 / 100.0 * tempKelvin
|
|
+ 34.04926034
|
|
- 6.353631 * 1000.0 / tempKelvin;
|
|
double coef3 = humiPct / 100.0 * System.Math.Exp(coef1) / pressurePa;
|
|
double airDensityKgm3 = 0.00348353 * pressurePa * (1.0 - 0.378 * coef3) / tempKelvin; /// kg/m3
|
|
return (float)airDensityKgm3;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert 'pulses' to 'volume', prevent division by zero
|
|
/// </summary>
|
|
public static double VolumeFromPulses(int pulses, double pulsesPerLiter)
|
|
{
|
|
if (pulsesPerLiter <= double.Epsilon) return 0;
|
|
return Convert.ToDouble(pulses) / pulsesPerLiter;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculate the error in % from 'measured' and 'true' volume, prevent division by zero
|
|
/// </summary>
|
|
public static double ErrorFromVolumes(double measuredVolume, double trueVolume)
|
|
{
|
|
if (trueVolume <= float.Epsilon)
|
|
{
|
|
if (measuredVolume <= float.Epsilon)
|
|
{
|
|
log.WarnFormat("ErrorFromVolumes({0},{1}) returns {2}", measuredVolume, trueVolume, 99.0);
|
|
return 99.0;
|
|
}
|
|
|
|
log.WarnFormat("ErrorFromVolumes({0},{1}) returns {2}", measuredVolume, trueVolume, 99.0);
|
|
return 99.0;
|
|
}
|
|
double error = 100.0 * (measuredVolume - trueVolume) / trueVolume;
|
|
log.InfoFormat("ErrorFromVolumes({0},{1}) returns {2}", measuredVolume, trueVolume, error);
|
|
return error;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates corrected value form a list of corrections by interpolation.
|
|
/// It is assumed that values in the list 'corrections' are sorted.
|
|
/// </summary>
|
|
/// <param name="rawMeasurement">Raw uncorrected value</param>
|
|
/// <param name="corrections">Sorted (value, correction) pairs</param>
|
|
/// <returns>Corrected value</returns>
|
|
public static double CorrectedValue(double rawValue, IList<Config.Entities.MeasurementCorrection> corrections)
|
|
{
|
|
if (corrections == null || corrections.Count == 0) return rawValue;
|
|
|
|
if (rawValue < corrections[0].Measurement)
|
|
{
|
|
return rawValue + corrections[0].Correction;
|
|
}
|
|
|
|
int count = corrections.Count;
|
|
for (int i = 1; i < count; i++)
|
|
{
|
|
if (rawValue < corrections[i].Measurement)
|
|
{
|
|
double d1 = rawValue - corrections[i-1].Measurement;
|
|
double d2 = corrections[i].Measurement - rawValue;
|
|
|
|
double corr;
|
|
if (d1 + d2 <= float.Epsilon)
|
|
{
|
|
corr = (corrections[i - 1].Correction + corrections[i].Correction) / 2.0;
|
|
}
|
|
else
|
|
{
|
|
corr = (corrections[i - 1].Correction * d2 + corrections[i].Correction * d1) / (d1 + d2);
|
|
}
|
|
return rawValue + corr;
|
|
}
|
|
}
|
|
|
|
return rawValue + corrections[count - 1].Correction;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Calculates the heat coefficient for water
|
|
/// </summary>
|
|
/// <param name="pressure">Pressure [bar]</param>
|
|
/// <param name="T_in">Inlet temperature [C]</param>
|
|
/// <param name="T_out">Outlet temperature [C]</param>
|
|
/// <param name="flowMeasuredAtInlet">true = flow measured @inlet, false = flow measured @outlet</param>
|
|
/// <returns> Heat coefficient for water [J/(m3 K)]</returns>
|
|
public static double HeatCoefficientWater(double pressure, double T_in, double T_out, bool flowMeasuredAtInlet)
|
|
{
|
|
if (T_in == T_out) return 0;
|
|
|
|
const double R = 461.526; /// [J kg^-1 K^-1]
|
|
const double p_star_Pa = 16.53E6; /// [Pa] (=16.53 MPa)
|
|
const double T_star = 1386.0; /// [K]
|
|
|
|
double T_in_K = Config.Units.ConvertTo(Config.Unit.K, T_in);
|
|
double T_out_K = Config.Units.ConvertTo(Config.Unit.K, T_out);
|
|
double tau_in = T_star / T_in_K;
|
|
double tau_out = T_star / T_out_K;
|
|
double pi = Config.Units.ConvertTo(Config.Unit.Pa, pressure) / p_star_Pa;
|
|
|
|
double h_in = tau_in * GammaTau(pi, tau_in) * R * T_in_K;
|
|
double h_out = tau_out * GammaTau(pi, tau_out) * R * T_out_K;
|
|
|
|
double ni = flowMeasuredAtInlet ? GammaPi(pi, tau_in) * R * T_in_K / p_star_Pa
|
|
: GammaPi(pi, tau_out) * R * T_out_K / p_star_Pa;
|
|
|
|
return (h_in - h_out) / (ni * (T_in - T_out));
|
|
}
|
|
|
|
/// <summary>
|
|
/// gamma(pi) see also STN EN 1434-1 Annex A (A.4)
|
|
/// </summary>
|
|
/// <param name="pi">pi = p / p* where p* = 16.53 MPa</param>
|
|
/// <param name="tau">tau = T* / T where T* = 1386 K</param>
|
|
/// <returns>gamma(pi)</returns>
|
|
static double GammaPi(double pi, double tau)
|
|
{
|
|
double result = 0;
|
|
for (int i = 0; i < 34; i++)
|
|
{
|
|
result -= ni[i] * Ii[i] * Math.Pow(7.1 - pi, Ii[i] - 1) * Math.Pow(tau - 1.222, Ji[i]);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// gamma(tau) see also STN EN 1434-1 Annex A (A.7)
|
|
/// </summary>
|
|
/// <param name="pi">pi = p / p* where p* = 16.53 MPa</param>
|
|
/// <param name="tau">tau = T* / T where T* = 1386 K</param>
|
|
/// <returns>gamma(tau)</returns>
|
|
static double GammaTau(double pi, double tau)
|
|
{
|
|
double result = 0;
|
|
for (int i = 0; i < 34; i++)
|
|
{
|
|
result += ni[i] * Math.Pow(7.1 - pi, Ii[i]) * Ji[i] * Math.Pow(tau - 1.222, Ji[i] - 1);
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
}
|