tbf/TestBenchFramework/BenchControl/Formulas.cs

152 lines
5.3 KiB
C#
Raw Normal View History

///
/// Copyright (c) 2013-2015 Sensus Metering Systems
///
using System;
using System.Collections.Generic;
namespace TBF.BenchControl
{
public static class Formulas
{
/// <summary>
/// Calculate density of distilled water from temperature
/// </summary>
/// <param name="t">Temperature in [degC]</param>
/// <returns>Density in [kg/m3]</returns>
public static float 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 (float)(((((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 float WaterDensityFromTemp(float t)
{
float realDensity = Program.LocalSettings.RealDensity;
float atTemperature = Program.LocalSettings.AtTemperature;
float 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 float VolumeFromPulses(int pulses, float pulsesPerLiter)
{
if (pulsesPerLiter <= float.Epsilon) return 0;
return Convert.ToSingle(pulses) / pulsesPerLiter;
}
/// <summary>
/// Calculate the error in % from 'measured' and 'true' volume, prevent division by zero
/// </summary>
public static float ErrorFromVolumes(float measuredVolume, float trueVolume)
{
if (trueVolume <= float.Epsilon)
{
if (measuredVolume <= float.Epsilon) return 0;
return 100.0f;
}
return 100.0f * (measuredVolume - trueVolume) / trueVolume;
}
/// <summary>
/// Calcuate progress of the test while setting the flow.
/// </summary>
/// <param name="currentTime">Current time from the beginning in [s]</param>
/// <param name="flowSetTime">Estimated time to set the flow in [s]</param>
/// <param name="testTime">Estimated test time in [s]</param>
/// <returns>Test progress 0 .. 1.0f</returns>
public static float TestProgress(float currentTime, float flowSetTime, float testTime)
{
// Never return more then 'fixedPart'
if (flowSetTime <= float.Epsilon) return 0;
float fixedPart = flowSetTime / (flowSetTime + testTime);
return (currentTime < flowSetTime) ? (currentTime / flowSetTime) * fixedPart : fixedPart;
}
/// <summary>
/// Calculate progress of the test during measurement.
/// </summary>
/// <param name="refPulses">Current number of reference pulses</param>
/// <param name="totalPulses">Total number of reference pulses to complete the test</param>
/// <param name="flowSetTime">Estimated time to set the flow in [s]</param>
/// <param name="testTime">Estimated test time in [s]</param>
/// <returns>Test progress 0 .. 1.0f</returns>
public static float TestProgress(int refPulses, int totalPulses, float flowSetTime, float testTime)
{
// Never return less then 'fixedPart' and more then 1.0f
if (refPulses > totalPulses) refPulses = totalPulses;
float fixedPart = flowSetTime / (flowSetTime + testTime);
return fixedPart + (1.0f - fixedPart) * Convert.ToSingle(refPulses) / Convert.ToSingle(totalPulses);
}
/// <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 float CorrectedValue(float rawValue, IList<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)
{
float d1 = rawValue - corrections[i-1].Measurement;
float d2 = corrections[i].Measurement - rawValue;
float corr;
if (d1 + d2 <= float.Epsilon)
{
corr = (corrections[i - 1].Correction + corrections[i].Correction) / 2.0f;
}
else
{
corr = (corrections[i - 1].Correction * d2 + corrections[i].Correction * d1) / (d1 + d2);
}
return rawValue + corr;
}
}
return rawValue + corrections[count - 1].Correction;
}
}
}