645 lines
37 KiB
C#
645 lines
37 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.IO;
|
|
using DTS.Common.Classes.Sensors;
|
|
using DTS.Common.DAS.Concepts;
|
|
using DTS.Common.Enums.Sensors;
|
|
|
|
namespace DTS.SensorDB
|
|
{
|
|
/// <summary>
|
|
/// class for to and from Sensor Information Files (*.SIF)
|
|
/// These are TDC sensor information files
|
|
/// </summary>
|
|
public class SensorInformationFile
|
|
{
|
|
/// <summary>
|
|
/// just chose this out of the latest version of TDAS I have's .ini (which is actually 7.1.1x)
|
|
/// as far as I know it doesn't need to be set, it may just be for informational purposes
|
|
/// </summary>
|
|
public const string LASTKNOWN_TDCSOFTWAREVERSION = "7.1.1w";
|
|
|
|
/// <summary>
|
|
/// The SIF is a linear text file, with either a blank line, or a header, or a data entry
|
|
/// on each line
|
|
/// here are all the possible headers/lines we can find,
|
|
/// we probably expect to see all of them, but it's probably not fatal if we don't see
|
|
/// say description or something
|
|
/// </summary>
|
|
public enum Fields
|
|
{
|
|
SoftwareVersion,
|
|
DummyLine1,
|
|
ChannelDescription,
|
|
SerialNumber,
|
|
OffsetLowTol,
|
|
OffsetHighTol,
|
|
CalMode,
|
|
CalStep,
|
|
ShuntValue,
|
|
ProportionalToExcitation,
|
|
Sensitivity,
|
|
Gain,
|
|
ExcitationVoltage,
|
|
EngUnits,
|
|
SoftwareFilter,
|
|
InvertData,
|
|
ZeroReference,
|
|
DesiredMaxRangeInEU,
|
|
CalibrationDate,
|
|
RemoveNaturalSensorOffset,
|
|
InitialEUValue,
|
|
SensorIDType,
|
|
SensorID,
|
|
ISOCode,
|
|
SensorCategory
|
|
}
|
|
/// <summary>
|
|
/// saves a sensor calibration and sensor data entry to a SIF
|
|
/// will back up the file first before saving it
|
|
/// </summary>
|
|
/// <param name="sd">input sensor data</param>
|
|
/// <param name="sc">input sensor calibration</param>
|
|
/// <param name="filename">the filename including path to save to</param>
|
|
/// <param name="errors">any errors or warnings during the export</param>
|
|
/// <returns>true if the file was saved, false if the file was not saved</returns>
|
|
public static bool SaveSIF(SensorData sd, SensorCalibration sc, string filename, ref List<string> errors)
|
|
{
|
|
try
|
|
{
|
|
BackupFile(filename);
|
|
WriteSIF(filename, sd, sc, ref errors);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
errors.Add(ex.Message);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
public const string ERROR_SEPARATOR = " - ";
|
|
/// <summary>
|
|
/// retrieves a sensor from a SIF
|
|
/// </summary>
|
|
/// <param name="filename">filename and full path to file to read</param>
|
|
/// <param name="sd">sensor data (may be null if file could not be processed)</param>
|
|
/// <param name="sc">sensor calibration (may be ull if file could not be processed)</param>
|
|
/// <param name="errors">any warnings or errors that occurred during processing the file</param>
|
|
/// <returns>true if sensor was read, false if sensor could not be read</returns>
|
|
public static bool LoadFromSIF(string filename, out SensorData sd, out SensorCalibration sc, ref List<string> errors)
|
|
{
|
|
sd = null;
|
|
sc = null;
|
|
try
|
|
{
|
|
//check the file exists
|
|
if (!File.Exists(filename)) { return false; }
|
|
|
|
var lines = File.ReadAllLines(filename);
|
|
sd = new SensorData();
|
|
sc = new SensorCalibration();
|
|
var category = TDCSensorCategory.Normal;
|
|
var sensitivities = new List<double>();
|
|
|
|
//go through all the lines in the file, a lot of times we'll jump two lines
|
|
//but we don't assume that, we just assume one line then jump two when we need to
|
|
for (var i = 0; i < lines.Length; i++)
|
|
{
|
|
var field = GetFieldForTag(lines[i]);
|
|
int y = 0;
|
|
switch (field)
|
|
{
|
|
case Fields.CalibrationDate:
|
|
{
|
|
i++;//also handle the data line
|
|
var tokens = lines[i].Split(new[] { "_" }, StringSplitOptions.None);
|
|
if (3 != tokens.Length) { throw new InvalidDataException(field.ToString()); }
|
|
|
|
if (!int.TryParse(tokens[0], System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out int m))
|
|
{ throw new InvalidDataException(field.ToString()); }
|
|
if (!int.TryParse(tokens[1], System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out int d))
|
|
{ throw new InvalidDataException(field.ToString()); }
|
|
if (!int.TryParse(tokens[2], System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out y))
|
|
{ throw new InvalidDataException(field.ToString()); }
|
|
|
|
sc.CalibrationDate = new DateTime(y, m, d);
|
|
}
|
|
break;
|
|
case Fields.CalMode:
|
|
{
|
|
i++; //also handle the data line
|
|
var cm = new CalMode(lines[i]);
|
|
|
|
sd.Shunt = cm.ShuntCheck ? ShuntMode.Emulation : ShuntMode.None;
|
|
|
|
sd.Bridge = cm.FullBridge ? SensorConstants.BridgeType.FullBridge : SensorConstants.BridgeType.HalfBridge;
|
|
|
|
sd.ByPassFilter = !cm.Filter;
|
|
}
|
|
break;
|
|
case Fields.CalStep: i++; break;//not used by datapro
|
|
case Fields.ChannelDescription:
|
|
{
|
|
i++; //also handle the data line
|
|
sd.Comment = lines[i];
|
|
}
|
|
break;
|
|
case Fields.DesiredMaxRangeInEU:
|
|
{
|
|
i++; //also handle the data line
|
|
if (double.TryParse(lines[i], System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out double d))
|
|
{
|
|
//the SIF doesn't have ranges in it, so we just set all the ranges to one value to avoid confusion
|
|
sd.Capacity = d;
|
|
sd.RangeHigh = d;
|
|
sd.RangeMedium = d;
|
|
sd.RangeLow = d;
|
|
}
|
|
else { throw new InvalidDataException(field + ERROR_SEPARATOR + lines[i]); }
|
|
}
|
|
break;
|
|
case Fields.DummyLine1: break; //empty line
|
|
case Fields.EngUnits:
|
|
{
|
|
i++; //also handle the data line
|
|
|
|
|
|
// This call insures that the display unit will be added to the list.
|
|
MeasurementUnitList.GetMeasurementUnit(lines[i]);
|
|
|
|
//store EU into both storage areas. DataPRO has display units and cal units
|
|
//so we just set both to the same unit since SIF only has one
|
|
sd.DisplayUnit = lines[i];
|
|
Array.ForEach(sc.Records.Records, record => record.EngineeringUnits = lines[i]); //FB16398: set units on all records, not just first
|
|
|
|
}
|
|
break;
|
|
case Fields.ExcitationVoltage:
|
|
{
|
|
i++; //also handle the data line
|
|
if (double.TryParse(lines[i], System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out double d))
|
|
{
|
|
var excitation = Test.Module.Channel.Sensor.GetExcitationVoltageEnumFromMagnitude(d);
|
|
sd.SupportedExcitation = new[] { excitation };
|
|
sc.Records.Records[0].Excitation = excitation;
|
|
}
|
|
else { throw new InvalidDataException(field + ERROR_SEPARATOR + lines[i]); }
|
|
}
|
|
break;
|
|
case Fields.Gain: i++; break;//not used
|
|
case Fields.InitialEUValue:
|
|
{
|
|
i++; //also handle the data line
|
|
if (double.TryParse(lines[i], System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out double d))
|
|
{
|
|
sc.InitialOffsets = new InitialOffsets(new InitialOffset(d));
|
|
}
|
|
else { throw new InvalidDataException(field + ERROR_SEPARATOR + lines[i]); }
|
|
}
|
|
break;
|
|
case Fields.InvertData:
|
|
{
|
|
i++; //also handle the data line
|
|
switch (lines[i].ToUpper())
|
|
{
|
|
case "0":
|
|
case "N":
|
|
case "F":
|
|
sd.Invert = false;
|
|
break;
|
|
default:
|
|
sd.Invert = true;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case Fields.ISOCode:
|
|
{
|
|
i++; //also handle the data line
|
|
sd.ISOCode = sd.BuildIsoCodeFromFilter(lines[i], sd.Filter.FClass);
|
|
}
|
|
break;
|
|
case Fields.OffsetHighTol:
|
|
{
|
|
i++; //also handle the data line
|
|
if (double.TryParse(lines[i], System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out double d))
|
|
{
|
|
sd.OffsetToleranceHigh = d;
|
|
}
|
|
else { throw new InvalidDataException(field + ERROR_SEPARATOR + lines[i]); }
|
|
}
|
|
break;
|
|
case Fields.OffsetLowTol:
|
|
{
|
|
i++; //also handle the data line
|
|
if (double.TryParse(lines[i], System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out double d))
|
|
{
|
|
sd.OffsetToleranceLow = d;
|
|
}
|
|
else { throw new InvalidDataException(field + ERROR_SEPARATOR + lines[i]); }
|
|
}
|
|
break;
|
|
case Fields.ProportionalToExcitation:
|
|
{
|
|
i++; //also handle the data line
|
|
switch (lines[i].ToUpper())
|
|
{
|
|
case "0":
|
|
case "N":
|
|
case "F":
|
|
sc.IsProportional = false;
|
|
break;
|
|
default:
|
|
sc.IsProportional = true;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case Fields.RemoveNaturalSensorOffset:
|
|
{
|
|
i++; //also handle the data line
|
|
switch (lines[i].ToUpper())
|
|
{
|
|
case "0":
|
|
case "N":
|
|
case "F":
|
|
sc.RemoveOffset = false;
|
|
break;
|
|
default:
|
|
sc.RemoveOffset = true;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case Fields.Sensitivity:
|
|
{
|
|
i++; //also handle the data line
|
|
|
|
//sensitivities in the SIF can vary based on software version, some versions may only have one decimal
|
|
//some will have 4 (polynomial) note that having 4 entries doesn't mean that all 4 entries are used
|
|
var tokens = lines[i].Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);
|
|
sensitivities.Clear();
|
|
foreach (var t in tokens)
|
|
{
|
|
if (double.TryParse(t, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out double d))
|
|
{
|
|
sensitivities.Add(d);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case Fields.SensorCategory:
|
|
{
|
|
i++; //also handle the data line
|
|
|
|
if (int.TryParse(lines[i], System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out int temp))
|
|
{
|
|
category = (TDCSensorCategory)temp;
|
|
}
|
|
else
|
|
{
|
|
throw new InvalidDataException(field + ERROR_SEPARATOR + lines[i]);
|
|
}
|
|
}
|
|
break;
|
|
case Fields.SensorID:
|
|
{
|
|
i++; //also handle the data line
|
|
sd.EID = lines[i];
|
|
if (sd.EID.ToLower().Contains("none")) { sd.EID = ""; }
|
|
}
|
|
break;
|
|
case Fields.SensorIDType: i++; break;//not used currently
|
|
case Fields.SerialNumber:
|
|
{
|
|
i++; //also handle the data line
|
|
sd.SerialNumber = lines[i];
|
|
sc.SerialNumber = lines[i];
|
|
}
|
|
break;
|
|
case Fields.ShuntValue:
|
|
{
|
|
i++; //also handle the data line
|
|
if (double.TryParse(lines[i], System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out double d))
|
|
{
|
|
sd.BridgeResistance = d;
|
|
}
|
|
else { throw new InvalidDataException(field + ERROR_SEPARATOR + lines[i]); }
|
|
}
|
|
break;
|
|
case Fields.SoftwareFilter:
|
|
{
|
|
i++; //also handle the data line
|
|
if (string.IsNullOrEmpty(lines[i]))
|
|
{
|
|
sd.Filter.FClass = FilterClassType.None;
|
|
}
|
|
else if (double.TryParse(lines[i], System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out double d))
|
|
{
|
|
sd.Filter = new FilterClass(d);
|
|
}
|
|
else { throw new InvalidDataException(field + ERROR_SEPARATOR + lines[i]); }
|
|
}
|
|
break;
|
|
case Fields.SoftwareVersion:
|
|
if (false == string.IsNullOrEmpty(lines[i + 1]))
|
|
{
|
|
//need to read advance the line if the version is on the next line
|
|
if (int.TryParse(lines[i + 1][0].ToString(), out var notUsed)) { i++; }
|
|
}
|
|
break;
|
|
case Fields.ZeroReference:
|
|
{
|
|
i++; //also handle the data line
|
|
//note that the SIF doesn't contain the average window start/stop for average over time
|
|
var zr = new ZeroRef(lines[i]);
|
|
switch (zr.ZeroMethod)
|
|
{
|
|
case ZeroRef.ZeroType.AverageOverTime:
|
|
sc.ZeroMethods.Methods[0].Method = ZeroMethodType.AverageOverTime;
|
|
break;
|
|
case ZeroRef.ZeroType.UsePreEventDiagnostics:
|
|
sc.ZeroMethods.Methods[0].Method = ZeroMethodType.UsePreEventDiagnosticsZero;
|
|
break;
|
|
case ZeroRef.ZeroType.UseZeroMv:
|
|
sc.ZeroMethods.Methods[0].Method = ZeroMethodType.None;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
default: throw new NotSupportedException("unknown field: " + field);
|
|
}
|
|
}
|
|
//now set the sensitivities based on what the sensor category is
|
|
switch (category)
|
|
{
|
|
case TDCSensorCategory.IRTracc:
|
|
if (2 > sensitivities.Count) { throw new NotSupportedException(category + ERROR_SEPARATOR + "requires 2 sensitivity entries"); }
|
|
sc.NonLinear = true;
|
|
if (sc.Records.Records[0].Poly.NonLinearStyle == NonLinearStyles.IRTraccAverageOverTime)
|
|
{
|
|
sc.Records.Records[0].Poly.NonLinearStyle = NonLinearStyles.IRTraccAverageOverTime;
|
|
sc.ZeroMethods.Methods[0].Method = ZeroMethodType.AverageOverTime;
|
|
sc.Records.Records[0].Poly.MMPerV = 1000D / sensitivities[0];
|
|
sc.Records.Records[0].Poly.LinearizationExponent = sensitivities[1];
|
|
}
|
|
break;
|
|
case TDCSensorCategory.Normal:
|
|
case TDCSensorCategory.POT:
|
|
sc.Records.Records[0].Sensitivity = sensitivities[0]; break;
|
|
case TDCSensorCategory.Polynomial:
|
|
if (8 != sensitivities.Count) { throw new InvalidDataException(category + ERROR_SEPARATOR + "requires 4 sensitivity entries"); }
|
|
sc.NonLinear = true;
|
|
sc.Records.Records[0].Poly.NonLinearStyle = NonLinearStyles.Polynomial;
|
|
sc.Records.Records[0].Poly.SetCoefficient(3D, sensitivities[2]);
|
|
sc.Records.Records[0].Poly.SetCoefficient(2D, sensitivities[3]);
|
|
sc.Records.Records[0].Poly.SetCoefficient(1D, sensitivities[4]);
|
|
sc.Records.Records[0].Poly.SetCoefficient(0D, sensitivities[5]);
|
|
sc.ZeroMethods.Methods[0].Method = ZeroMethodType.None;
|
|
|
|
break;
|
|
default: throw new NotSupportedException("unknown category: " + category);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
errors.Add(ex.Message);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
/// <summary>
|
|
/// returns the string header for a given field
|
|
/// </summary>
|
|
/// <param name="field"></param>
|
|
/// <returns></returns>
|
|
public static string GetTagForField(Fields field)
|
|
{
|
|
//treating these as all hardcoded as they are in TDC
|
|
switch (field)
|
|
{
|
|
case Fields.CalibrationDate: return "---- Calibration Date M_D_Y ----";
|
|
case Fields.CalMode: return "---- Cal Mode - I=Voltage Insertion, S=Shunt ----";
|
|
case Fields.CalStep: return "---- Cal Step - shunt resistor (Ohms) ----";
|
|
case Fields.ChannelDescription: return "---- Channel Description ----";
|
|
case Fields.DesiredMaxRangeInEU: return "---- Desired Max Range in Eng Units ----";
|
|
case Fields.DummyLine1: return "";
|
|
case Fields.EngUnits: return "---- Eng Unit ----";
|
|
case Fields.ExcitationVoltage: return "---- Excitation Voltage must be a valid voltage from list ----";
|
|
case Fields.Gain: return "---- Gain - must be a valid gain from list ----";
|
|
case Fields.InitialEUValue: return "---- Initial EU Value ----";
|
|
case Fields.InvertData: return "---- Invert Data - 0=no invert, 1=yes invert ----";
|
|
case Fields.ISOCode: return "---- ISO Code ----";
|
|
case Fields.OffsetHighTol: return "---- Offset High Tol (mV) ----";
|
|
case Fields.OffsetLowTol: return "---- Offset Low Tol (mV) ----";
|
|
case Fields.ProportionalToExcitation: return "---- Proportional to Excitation ----";
|
|
case Fields.RemoveNaturalSensorOffset: return "---- Remove Natural Sensor Offset? ----";
|
|
case Fields.Sensitivity: return "---- Sensitivity (mV/V/eng unit) ----";
|
|
case Fields.SensorCategory: return "---- Sensor Category (Use 0 for most sensors) ----";
|
|
case Fields.SensorID: return "---- Sensor ID No ----";
|
|
case Fields.SensorIDType: return "---- Sensor ID Type ----";
|
|
case Fields.SerialNumber: return "---- Serial Number ----";
|
|
case Fields.ShuntValue: return "---- Shunt Value - corresponding value of shunt resistor in Eng Units ----";
|
|
case Fields.SoftwareFilter: return "---- Software Filter, -3dB point (Hz) ----";
|
|
case Fields.SoftwareVersion: return "Software Version: ";
|
|
case Fields.ZeroReference: return "---- Zero Reference - 0=use 30 msec avg, 1=use prezero, 2=equals zero mV ----";
|
|
default:
|
|
throw new NotSupportedException("unknown field: " + field);
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// returns a field given a header line
|
|
/// </summary>
|
|
/// <param name="tag"></param>
|
|
/// <returns></returns>
|
|
public static Fields GetFieldForTag(string tag)
|
|
{
|
|
if (tag.StartsWith(GetTagForField(Fields.SoftwareVersion))) { return Fields.SoftwareVersion; }
|
|
switch (tag)
|
|
{
|
|
case "---- Calibration Date M_D_Y ----": return Fields.CalibrationDate;
|
|
case "---- Cal Mode - I=Voltage Insertion, S=Shunt ----": return Fields.CalMode;
|
|
case "---- Cal Step - shunt resistor (Ohms) ----": return Fields.CalStep;
|
|
case "---- Channel Description ----": return Fields.ChannelDescription;
|
|
case "---- Desired Max Range in Eng Units ----": return Fields.DesiredMaxRangeInEU;
|
|
case "": return Fields.DummyLine1;
|
|
case "---- Eng Unit ----": return Fields.EngUnits;
|
|
case "---- Excitation Voltage must be a valid voltage from list ----": return Fields.ExcitationVoltage;
|
|
case "---- Gain - must be a valid gain from list ----": return Fields.Gain;
|
|
case "---- Initial EU Value ----":
|
|
case "---- Initial EU Value": // Older TDC sifs have this
|
|
return Fields.InitialEUValue;
|
|
case "---- Invert Data - 0=no invert, 1=yes invert ----": return Fields.InvertData;
|
|
case "---- ISO Code ----": return Fields.ISOCode;
|
|
case "---- Offset High Tol (mV) ----": return Fields.OffsetHighTol;
|
|
case "---- Offset Low Tol (mV) ----": return Fields.OffsetLowTol;
|
|
case "---- Proportional to Excitation ----": return Fields.ProportionalToExcitation;
|
|
case "---- Remove Natural Sensor Offset? ----": return Fields.RemoveNaturalSensorOffset;
|
|
case "---- Sensitivity (mV/V/eng unit) ----": return Fields.Sensitivity;
|
|
case "---- Sensor Category (Use 0 for most sensors) ----": return Fields.SensorCategory;
|
|
case "---- Sensor ID No ----": return Fields.SensorID;
|
|
case "---- Sensor ID Type ----": return Fields.SensorIDType;
|
|
case "---- Serial Number ----": return Fields.SerialNumber;
|
|
case "---- Shunt Value - corresponding value of shunt resistor in Eng Units ----": return Fields.ShuntValue;
|
|
case "---- Software Filter, -3dB point (Hz) ----":
|
|
case "---- Software Filter, -3dB point (HZ) ----": // Older TDC sifs have this
|
|
return Fields.SoftwareFilter;
|
|
case "Software Version: ":
|
|
case "Software Version:": // Older TDC sifs have this
|
|
return Fields.SoftwareVersion;
|
|
case "---- Zero Reference - 0=use 30 msec avg, 1=use prezero, 2=equals zero mV ----": return Fields.ZeroReference;
|
|
default:
|
|
throw new NotSupportedException("unknown field: " + tag);
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// moves file to a backup destination location
|
|
/// will delete existing backup if it's already present
|
|
/// </summary>
|
|
/// <param name="fileName"></param>
|
|
private static void BackupFile(string fileName)
|
|
{
|
|
if (File.Exists(fileName))
|
|
{
|
|
var fi = new FileInfo(fileName);
|
|
var backupName = fileName.Replace(fi.Extension, ".BAK");
|
|
if (File.Exists(backupName)) { File.Delete(backupName); }
|
|
File.Move(fileName, backupName);
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// these are constants from TDAS Control for the field SensorCategory
|
|
/// </summary>
|
|
public enum TDCSensorCategory
|
|
{
|
|
Normal = 0,
|
|
POT = 1,
|
|
IRTracc = 2,
|
|
Polynomial = 3
|
|
}
|
|
/// <summary>
|
|
/// Writes a sensor entry and calibration to a Sensor Information File (SIF)
|
|
/// </summary>
|
|
/// <param name="filename">filename and full path to file to write</param>
|
|
/// <param name="sd"></param>
|
|
/// <param name="sc"></param>
|
|
/// <param name="errors">any errors or warnings that occurred during writing</param>
|
|
private static void WriteSIF(string filename, SensorData sd, SensorCalibration sc, ref List<string> errors)
|
|
{
|
|
var sb = new StringBuilder(1500);
|
|
var fields = Enum.GetValues(typeof(Fields)).Cast<Fields>().ToArray();
|
|
|
|
var capacity = sd.Capacity * MeasurementUnitList.GetMeasurementUnit(sc.Records.Records[0].EngineeringUnits).GetScalerConversionFrom(sd.DisplayUnit);
|
|
var excitation = Test.Module.Channel.Sensor.GetExcitationVoltageMagnitudeFromEnum(sd.SupportedExcitation[0]);
|
|
|
|
var calmode = new CalMode() { Filter = !sd.ByPassFilter, FullBridge = sd.Bridge == SensorConstants.BridgeType.FullBridge, ShuntCheck = sd.Shunt == ShuntMode.Emulation };
|
|
|
|
ZeroRef zeroref = null;
|
|
//TODO: linear/nonlinear
|
|
switch (sc.ZeroMethods.Methods[0].Method)
|
|
{
|
|
case ZeroMethodType.AverageOverTime: zeroref = new ZeroRef(ZeroRef.ZeroType.AverageOverTime); break;
|
|
case ZeroMethodType.None: zeroref = new ZeroRef(ZeroRef.ZeroType.UseZeroMv); break;
|
|
case ZeroMethodType.UsePreEventDiagnosticsZero: zeroref = new ZeroRef(ZeroRef.ZeroType.UsePreEventDiagnostics); break;
|
|
default: throw new NotSupportedException("unknown zero method type: " + sc.ZeroMethods.Methods[0].Method);
|
|
}
|
|
foreach (var f in fields)
|
|
{
|
|
if (f == Fields.SoftwareVersion)
|
|
{
|
|
sb.AppendFormat("{0}{1}\n", GetTagForField(f), LASTKNOWN_TDCSOFTWAREVERSION);
|
|
}
|
|
else
|
|
{
|
|
var tag = GetTagForField(f);
|
|
sb.AppendLine(tag);
|
|
|
|
switch (f)
|
|
{
|
|
case Fields.CalibrationDate: sb.AppendFormat("{0}_{1}_{2}\n", sc.CalibrationDate.Month, sc.CalibrationDate.Day, sc.CalibrationDate.Year); break;
|
|
case Fields.CalMode: sb.AppendLine(calmode.ToString()); break;
|
|
case Fields.CalStep: sb.AppendLine("-1"); break;//for now we only support emulation?
|
|
case Fields.ChannelDescription: sb.AppendLine(sd.Comment); break;
|
|
case Fields.DesiredMaxRangeInEU: sb.AppendLine(capacity.ToString(System.Globalization.CultureInfo.InvariantCulture)); break;
|
|
case Fields.DummyLine1: break;
|
|
case Fields.EngUnits: sb.AppendLine(sc.Records.Records[0].EngineeringUnits); break;
|
|
case Fields.ExcitationVoltage: sb.AppendFormat("{0:0.0}", excitation); break;
|
|
case Fields.Gain: sb.AppendFormat("1.0"); break;//not used in datapro ... maybe we need to calculate it
|
|
case Fields.InitialEUValue: sb.Append(SensorData.GetInitialEUValue(sc, sd.SupportedExcitation[0], sc.InitialOffsets.Offsets[0]).ToString(System.Globalization.CultureInfo.InvariantCulture)); break;
|
|
case Fields.InvertData:
|
|
if (sd.Invert) { sb.AppendLine("1"); }
|
|
else { sb.AppendLine("0"); }
|
|
break;
|
|
case Fields.ISOCode: sb.AppendLine(sd.ISOCode); break;
|
|
case Fields.OffsetHighTol: sb.AppendLine(sd.OffsetToleranceHigh.ToString(System.Globalization.CultureInfo.InvariantCulture)); break;
|
|
case Fields.OffsetLowTol: sb.AppendLine(sd.OffsetToleranceLow.ToString(System.Globalization.CultureInfo.InvariantCulture)); break;
|
|
case Fields.ProportionalToExcitation:
|
|
if (sc.IsProportional) { sb.AppendLine("Y"); }
|
|
else { sb.AppendLine("N"); }
|
|
break;
|
|
case Fields.RemoveNaturalSensorOffset:
|
|
if (sc.RemoveOffset) { sb.AppendLine("Y"); }
|
|
else { sb.AppendLine("N"); }
|
|
break;
|
|
case Fields.Sensitivity:
|
|
if (sc.NonLinear)
|
|
{
|
|
double d1 = 1, d2 = 0, d3 = 0, d4 = 0, d5 = 0, d6 = 0, d7 = 0, d8 = 0;
|
|
|
|
if (sc.Records.Records[0].Poly.NonLinearStyle == NonLinearStyles.Polynomial)
|
|
{
|
|
d8 = sc.Records.Records[0].Poly.GetCoefficient(5D);
|
|
d7 = sc.Records.Records[0].Poly.GetCoefficient(4D);
|
|
d6 = sc.Records.Records[0].Poly.GetCoefficient(3D);
|
|
d5 = sc.Records.Records[0].Poly.GetCoefficient(2D);
|
|
d4 = sc.Records.Records[0].Poly.GetCoefficient(1D);
|
|
d3 = sc.Records.Records[0].Poly.GetCoefficient(0D);
|
|
}
|
|
else
|
|
{
|
|
d1 = sc.Records.Records[0].Poly.MMPerV / 1000D;
|
|
d2 = sc.Records.Records[0].Poly.LinearizationExponent;
|
|
}
|
|
sb.AppendFormat("{0},{1},{2},{3},{4},{5},{6},{7}\n",
|
|
d1.ToString("F12", System.Globalization.CultureInfo.InvariantCulture),
|
|
d2.ToString("F12", System.Globalization.CultureInfo.InvariantCulture),
|
|
d3.ToString("F12", System.Globalization.CultureInfo.InvariantCulture),
|
|
d4.ToString("F12", System.Globalization.CultureInfo.InvariantCulture),
|
|
d5.ToString("F12", System.Globalization.CultureInfo.InvariantCulture),
|
|
d6.ToString("F12", System.Globalization.CultureInfo.InvariantCulture),
|
|
d7.ToString("F12", System.Globalization.CultureInfo.InvariantCulture),
|
|
d8.ToString("F12", System.Globalization.CultureInfo.InvariantCulture));
|
|
}
|
|
else { sb.AppendLine(sc.Records.Records[0].Sensitivity.ToString("F12", System.Globalization.CultureInfo.InvariantCulture)); }
|
|
break;
|
|
case Fields.SensorCategory:
|
|
var cat = TDCSensorCategory.Normal;
|
|
if (sc.NonLinear)
|
|
{
|
|
if (sc.Records.Records[0].Poly.NonLinearStyle == NonLinearStyles.Polynomial)
|
|
{
|
|
cat = TDCSensorCategory.Polynomial;
|
|
}
|
|
else { cat = TDCSensorCategory.IRTracc; }
|
|
}
|
|
sb.AppendLine(((int)cat).ToString(System.Globalization.CultureInfo.InvariantCulture));
|
|
break;
|
|
case Fields.SensorID: sb.AppendLine(sd.EID); break;
|
|
case Fields.SensorIDType: sb.AppendLine("Dallas"); break; //D or S?
|
|
case Fields.SerialNumber: sb.AppendLine(sd.SerialNumber); break;
|
|
case Fields.ShuntValue: sb.AppendLine(sd.BridgeResistance.ToString(System.Globalization.CultureInfo.InvariantCulture)); break;
|
|
case Fields.SoftwareFilter: sb.AppendLine(sd.Filter.Frequency.ToString("F0", System.Globalization.CultureInfo.InvariantCulture)); break;
|
|
case Fields.SoftwareVersion: break;
|
|
case Fields.ZeroReference: sb.AppendLine(zeroref.ToString()); break;
|
|
default:
|
|
throw new NotSupportedException("unsupported field: " + f);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|