From 3725e238fc2191f66b399da0b800fd509e35a525 Mon Sep 17 00:00:00 2001 From: Milan Hanajik Date: Thu, 25 Oct 2018 14:56:22 +0200 Subject: [PATCH] Various.TankWithLevelMsrmnt can use a calibration table loaded from a CSV file. --- .../Various/TankWithLevelMsrmnt/Tank.cs | 113 +++++++++++++++++- .../Various/TankWithLevelMsrmnt/TankCfg.cs | 10 +- .../TankWithLevelMsrmnt/TankCfgCtrl.cs | 7 +- .../TankCfgCtrl.designer.cs | 57 ++++++--- 4 files changed, 158 insertions(+), 29 deletions(-) diff --git a/TBF/BenchControl/Various/TankWithLevelMsrmnt/Tank.cs b/TBF/BenchControl/Various/TankWithLevelMsrmnt/Tank.cs index 1a81f7ef9..c510f2f94 100644 --- a/TBF/BenchControl/Various/TankWithLevelMsrmnt/Tank.cs +++ b/TBF/BenchControl/Various/TankWithLevelMsrmnt/Tank.cs @@ -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; } + /// + /// Loads a calibration table in CSV format (column1 = height[mm], column2 = volume[l]). + /// + /// Path name of the CSV file + /// true when loaded successfully + bool LoadCalibrationTable(string pathName) + { + try + { + IList heights = new List(); + IList volumes = new List(); + + 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; + } + } /// - /// 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 /// Volume in l 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 } /// - /// Converts water level height to volume. + /// Converts water level to volume using calibration table. + /// + /// Height in mm + /// Volume in l + 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]; + } + + /// + /// Converts water level to volume for 2000 liter water tank in CEVAK Ceske Budejovice. /// /// Height in mm /// Volume in l @@ -148,7 +249,7 @@ namespace TBF.BenchControl.Various.TankWithLevelMsrmnt } /// - /// Converts water level height to volume. + /// Converts water level to volume for 10000 liter water tank in CEVAK Ceske Budejovice. /// /// Height in mm /// Volume in l diff --git a/TBF/BenchControl/Various/TankWithLevelMsrmnt/TankCfg.cs b/TBF/BenchControl/Various/TankWithLevelMsrmnt/TankCfg.cs index 7f36b4486..03473974f 100644 --- a/TBF/BenchControl/Various/TankWithLevelMsrmnt/TankCfg.cs +++ b/TBF/BenchControl/Various/TankWithLevelMsrmnt/TankCfg.cs @@ -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); } } } diff --git a/TBF/BenchControl/Various/TankWithLevelMsrmnt/TankCfgCtrl.cs b/TBF/BenchControl/Various/TankWithLevelMsrmnt/TankCfgCtrl.cs index 3765f812b..84651a0bf 100644 --- a/TBF/BenchControl/Various/TankWithLevelMsrmnt/TankCfgCtrl.cs +++ b/TBF/BenchControl/Various/TankWithLevelMsrmnt/TankCfgCtrl.cs @@ -76,7 +76,8 @@ 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,7 +87,8 @@ 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; } diff --git a/TBF/BenchControl/Various/TankWithLevelMsrmnt/TankCfgCtrl.designer.cs b/TBF/BenchControl/Various/TankWithLevelMsrmnt/TankCfgCtrl.designer.cs index fb7251518..645372f63 100644 --- a/TBF/BenchControl/Various/TankWithLevelMsrmnt/TankCfgCtrl.designer.cs +++ b/TBF/BenchControl/Various/TankWithLevelMsrmnt/TankCfgCtrl.designer.cs @@ -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; } }