Various.TankWithLevelMsrmnt can use a calibration table loaded from a CSV file.

This commit is contained in:
Milan Hanajik
2018-10-25 15:34:46 +02:00
parent ac2ac82187
commit 3725e238fc
4 changed files with 158 additions and 29 deletions
@@ -2,9 +2,13 @@
/// Copyright (c) 2018 Sensus Slovensko a.s.
///
using System;
using System.Globalization;
using System.IO;
using System.Text;
using log4net;
using TBF.Boxes;
using TBF.BenchControl.Generic;
using System.Collections.Generic;
namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
{
@@ -17,8 +21,11 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
private static readonly ILog log = LogManager.GetLogger(typeof(Tank));
public override string ToString() { return string.Format("TankWithLevelMsrmnt({0})", Cfg.ToString(1)); }
protected readonly TankCfg tankCfg;
readonly TankCfg tankCfg;
bool useCalibTable;
double[] calibHeight;
double[] calibVolume;
public enum CurrentOp
{
@@ -89,7 +96,11 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
///
/// IDevice interface (required to call base and initialize 'DrainValve')
///
public void Initialize() { base.Initalize(); }
public void Initialize()
{
base.Initalize();
useCalibTable = LoadCalibrationTable(tankCfg.CalibrationTable);
}
public void RunDeviceBefore() { }
public void RunDeviceAfter() { }
public void StopDevice() { }
@@ -101,9 +112,70 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
return false;
}
/// <summary>
/// Loads a calibration table in CSV format (column1 = height[mm], column2 = volume[l]).
/// </summary>
/// <param name="pathName">Path name of the CSV file</param>
/// <returns>true when loaded successfully</returns>
bool LoadCalibrationTable(string pathName)
{
try
{
IList<double> heights = new List<double>();
IList<double> volumes = new List<double>();
using (TextReader reader = new StreamReader(pathName))
{
while (true)
{
double h, v;
string line = reader.ReadLine();
if (line == null) break;
string[] columns = line.Split(new char[] { ';' });
if (columns.Length != 2 ||
!double.TryParse(columns[0], NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out h) ||
!double.TryParse(columns[1], NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out v))
{
break;
}
if (heights.Count > 0 && h <= heights[heights.Count - 1])
{
throw new Exception("Calibration file content error: height is not monotonically increasing");
}
heights.Add(h);
volumes.Add(v);
}
}
if ((heights.Count == 0) || (heights.Count != volumes.Count))
{
throw new Exception("No data in the calibration file");
}
calibHeight = new double[heights.Count];
calibVolume = new double[heights.Count];
for (int i = 0; i < heights.Count; i++)
{
calibHeight[i] = heights[i];
calibVolume[i] = volumes[i];
}
log.WarnFormat("calibration table {0} was successfully loaded.", pathName);
return true;
}
catch (Exception)
{
log.Warn("calibration table was NOT loaded.");
return false;
}
}
/// <summary>
/// Converts water level height to volume.
/// Converts water level to volume.
/// Tank capcacity is used o distinguish bettween existing tanks:
/// CEVAL small tank: Capacity = 2000 .. 2220
/// CEVAL large tank: Capacity = 10000 .. 10850
@@ -112,7 +184,11 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
/// <returns>Volume in l</returns>
double Level2Volume(double h)
{
if (Capacity >= 2000 && Capacity <= 2220)
if (useCalibTable)
{
return Level2VolumeTable(h);
}
else if (Capacity >= 2000 && Capacity <= 2220)
{
return Level2VolumeCevakSmall(h);
}
@@ -127,7 +203,32 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
}
/// <summary>
/// Converts water level height to volume.
/// Converts water level to volume using calibration table.
/// </summary>
/// <param name="h">Height in mm</param>
/// <returns>Volume in l</returns>
double Level2VolumeTable(double h)
{
if (h <= calibHeight[0]) return calibVolume[0];
for (int i = 1; i < calibHeight.Length; i++)
{
if (h <= calibHeight[i])
{
double h1 = calibHeight[i - 1];
double h2 = calibHeight[i];
double v1 = calibVolume[i - 1];
double v2 = calibVolume[i];
return v1 + (v2 - v1) * (h - h1) / (h2 - h1);
}
}
return calibVolume[calibHeight.Length - 1];
}
/// <summary>
/// Converts water level to volume for 2000 liter water tank in CEVAK Ceske Budejovice.
/// </summary>
/// <param name="h">Height in mm</param>
/// <returns>Volume in l</returns>
@@ -148,7 +249,7 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
}
/// <summary>
/// Converts water level height to volume.
/// Converts water level to volume for 10000 liter water tank in CEVAK Ceske Budejovice.
/// </summary>
/// <param name="h">Height in mm</param>
/// <returns>Volume in l</returns>
@@ -32,8 +32,9 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
private int drainTimeSec;
public int DrainTimeSec { get { return drainTimeSec; } set { drainTimeSec = value; } }
public string LevelMeasurement;
public string LevelMeasurement; /// Name of a level measurement component, 'Various.ManualLevelMsrmnt' is used when left empty.
public string CalibrationTable; /// Path name of a calibration table in CSV format (column1 = height[mm], column2 = volume[l])
/// Volume calculation using formulas for std. tanks in Level2Volume() is used when left empty.
/// Private parameterless constructor invoked by all other (public) constructors
TankCfg()
@@ -58,12 +59,13 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
DrainValve = "VB1";
DrainTimeSec = 180;
LevelMeasurement = string.Empty;
CalibrationTable = string.Empty;
}
public string ToString(int i)
{
return string.Format("Name={0}, {1}l, empty={2}l, drainVlv={3}, drainTm={4}s",
Name, Capacity, Empty, DrainValve, DrainTimeSec);
return string.Format("Capacity={0}l, empty={1}l, drainValve={2}, drainTime={3}s, levelMsrmnt={4}, cal.table={5}",
Capacity, Empty, DrainValve, DrainTimeSec, LevelMeasurement, CalibrationTable);
}
}
}
@@ -76,6 +76,7 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
drainValveComboBox.Text = string.IsNullOrEmpty(config.DrainValve) ? "---" : config.DrainValve;
drainTimeTextBox.Text = config.DrainTimeSec.ToString();
levelMeasurementComboBox.Text = string.IsNullOrEmpty(config.LevelMeasurement) ? "---" : config.LevelMeasurement;
calibrationTableTextBox.Text = config.CalibrationTable;
}
public void Unlock()
@@ -86,6 +87,7 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
drainValveComboBox.Enabled = true;
drainTimeTextBox.Enabled = true;
levelMeasurementComboBox.Enabled = true;
calibrationTableTextBox.Enabled = true;
}
public CfgUpdateFlags VerifyCfg(ref string message)
@@ -135,6 +137,7 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
config.DrainTimeSec = int.Parse(drainTimeTextBox.Text);
config.DrainValve = drainValveComboBox.Text.Equals("---") ? string.Empty : drainValveComboBox.Text;
config.LevelMeasurement = levelMeasurementComboBox.Text.Equals("---") ? string.Empty : drainValveComboBox.Text;
config.CalibrationTable = calibrationTableTextBox.Text;
return flags;
}
@@ -47,12 +47,14 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
this.drainValveLabel = new System.Windows.Forms.Label();
this.levelMeasurementComboBox = new System.Windows.Forms.ComboBox();
this.levelMeasurementLabel = new System.Windows.Forms.Label();
this.calibrationTableTextBox = new System.Windows.Forms.TextBox();
this.calibrationTableLabel = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// nameTextBox
//
this.nameTextBox.Enabled = false;
this.nameTextBox.Location = new System.Drawing.Point(137, 37);
this.nameTextBox.Location = new System.Drawing.Point(127, 33);
this.nameTextBox.Name = "nameTextBox";
this.nameTextBox.Size = new System.Drawing.Size(142, 20);
this.nameTextBox.TabIndex = 2;
@@ -60,7 +62,7 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
// nameLabel
//
this.nameLabel.AutoSize = true;
this.nameLabel.Location = new System.Drawing.Point(26, 40);
this.nameLabel.Location = new System.Drawing.Point(16, 36);
this.nameLabel.Name = "nameLabel";
this.nameLabel.Size = new System.Drawing.Size(35, 13);
this.nameLabel.TabIndex = 1;
@@ -69,7 +71,7 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
// classNameLabel
//
this.classNameLabel.AutoSize = true;
this.classNameLabel.Location = new System.Drawing.Point(134, 16);
this.classNameLabel.Location = new System.Drawing.Point(124, 12);
this.classNameLabel.Name = "classNameLabel";
this.classNameLabel.Size = new System.Drawing.Size(89, 13);
this.classNameLabel.TabIndex = 0;
@@ -78,7 +80,7 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
// capacityLabel
//
this.capacityLabel.AutoSize = true;
this.capacityLabel.Location = new System.Drawing.Point(26, 76);
this.capacityLabel.Location = new System.Drawing.Point(16, 72);
this.capacityLabel.Name = "capacityLabel";
this.capacityLabel.Size = new System.Drawing.Size(75, 13);
this.capacityLabel.TabIndex = 5;
@@ -87,7 +89,7 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
// capacityTextBox
//
this.capacityTextBox.Enabled = false;
this.capacityTextBox.Location = new System.Drawing.Point(137, 73);
this.capacityTextBox.Location = new System.Drawing.Point(127, 69);
this.capacityTextBox.Name = "capacityTextBox";
this.capacityTextBox.Size = new System.Drawing.Size(43, 20);
this.capacityTextBox.TabIndex = 6;
@@ -95,7 +97,7 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(183, 76);
this.label2.Location = new System.Drawing.Point(173, 72);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(23, 13);
this.label2.TabIndex = 7;
@@ -104,7 +106,7 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(183, 98);
this.label3.Location = new System.Drawing.Point(173, 94);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(23, 13);
this.label3.TabIndex = 10;
@@ -113,7 +115,7 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
// emptyTextBox
//
this.emptyTextBox.Enabled = false;
this.emptyTextBox.Location = new System.Drawing.Point(137, 95);
this.emptyTextBox.Location = new System.Drawing.Point(127, 91);
this.emptyTextBox.Name = "emptyTextBox";
this.emptyTextBox.Size = new System.Drawing.Size(43, 20);
this.emptyTextBox.TabIndex = 9;
@@ -121,7 +123,7 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
// emptyLabel
//
this.emptyLabel.AutoSize = true;
this.emptyLabel.Location = new System.Drawing.Point(26, 98);
this.emptyLabel.Location = new System.Drawing.Point(16, 94);
this.emptyLabel.Name = "emptyLabel";
this.emptyLabel.Size = new System.Drawing.Size(109, 13);
this.emptyLabel.TabIndex = 8;
@@ -130,7 +132,7 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(186, 143);
this.label4.Location = new System.Drawing.Point(176, 139);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(24, 13);
this.label4.TabIndex = 17;
@@ -139,7 +141,7 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
// drainTimeTextBox
//
this.drainTimeTextBox.Enabled = false;
this.drainTimeTextBox.Location = new System.Drawing.Point(137, 140);
this.drainTimeTextBox.Location = new System.Drawing.Point(127, 136);
this.drainTimeTextBox.Name = "drainTimeTextBox";
this.drainTimeTextBox.Size = new System.Drawing.Size(43, 20);
this.drainTimeTextBox.TabIndex = 16;
@@ -147,7 +149,7 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(26, 143);
this.label5.Location = new System.Drawing.Point(16, 139);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(54, 13);
this.label5.TabIndex = 15;
@@ -157,7 +159,7 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
//
this.drainValveComboBox.Enabled = false;
this.drainValveComboBox.FormattingEnabled = true;
this.drainValveComboBox.Location = new System.Drawing.Point(137, 117);
this.drainValveComboBox.Location = new System.Drawing.Point(127, 113);
this.drainValveComboBox.Name = "drainValveComboBox";
this.drainValveComboBox.Size = new System.Drawing.Size(143, 21);
this.drainValveComboBox.TabIndex = 14;
@@ -165,7 +167,7 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
// drainValveLabel
//
this.drainValveLabel.AutoSize = true;
this.drainValveLabel.Location = new System.Drawing.Point(26, 120);
this.drainValveLabel.Location = new System.Drawing.Point(16, 116);
this.drainValveLabel.Name = "drainValveLabel";
this.drainValveLabel.Size = new System.Drawing.Size(61, 13);
this.drainValveLabel.TabIndex = 13;
@@ -175,7 +177,7 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
//
this.levelMeasurementComboBox.Enabled = false;
this.levelMeasurementComboBox.FormattingEnabled = true;
this.levelMeasurementComboBox.Location = new System.Drawing.Point(137, 176);
this.levelMeasurementComboBox.Location = new System.Drawing.Point(127, 172);
this.levelMeasurementComboBox.Name = "levelMeasurementComboBox";
this.levelMeasurementComboBox.Size = new System.Drawing.Size(143, 21);
this.levelMeasurementComboBox.TabIndex = 32;
@@ -183,16 +185,35 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
// levelMeasurementLabel
//
this.levelMeasurementLabel.AutoSize = true;
this.levelMeasurementLabel.Location = new System.Drawing.Point(26, 179);
this.levelMeasurementLabel.Location = new System.Drawing.Point(16, 175);
this.levelMeasurementLabel.Name = "levelMeasurementLabel";
this.levelMeasurementLabel.Size = new System.Drawing.Size(99, 13);
this.levelMeasurementLabel.TabIndex = 31;
this.levelMeasurementLabel.Text = "Level measurement";
//
// calibrationTableTextBox
//
this.calibrationTableTextBox.Enabled = false;
this.calibrationTableTextBox.Location = new System.Drawing.Point(127, 207);
this.calibrationTableTextBox.Name = "calibrationTableTextBox";
this.calibrationTableTextBox.Size = new System.Drawing.Size(244, 20);
this.calibrationTableTextBox.TabIndex = 34;
//
// calibrationTableLabel
//
this.calibrationTableLabel.AutoSize = true;
this.calibrationTableLabel.Location = new System.Drawing.Point(16, 210);
this.calibrationTableLabel.Name = "calibrationTableLabel";
this.calibrationTableLabel.Size = new System.Drawing.Size(82, 13);
this.calibrationTableLabel.TabIndex = 33;
this.calibrationTableLabel.Text = "Calibration table";
//
// TankCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.calibrationTableTextBox);
this.Controls.Add(this.calibrationTableLabel);
this.Controls.Add(this.levelMeasurementComboBox);
this.Controls.Add(this.levelMeasurementLabel);
this.Controls.Add(this.drainValveComboBox);
@@ -210,7 +231,7 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
this.Controls.Add(this.nameLabel);
this.Controls.Add(this.classNameLabel);
this.Name = "TankCfgCtrl";
this.Size = new System.Drawing.Size(327, 250);
this.Size = new System.Drawing.Size(415, 250);
this.Load += new System.EventHandler(this.BalanceCfgCtrl_Load);
this.ResumeLayout(false);
this.PerformLayout();
@@ -235,5 +256,7 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt
private System.Windows.Forms.Label drainValveLabel;
private System.Windows.Forms.ComboBox levelMeasurementComboBox;
private System.Windows.Forms.Label levelMeasurementLabel;
private System.Windows.Forms.TextBox calibrationTableTextBox;
private System.Windows.Forms.Label calibrationTableLabel;
}
}