Files
DP44/DataPRO/SensorDB/SensorInformationFile.cs
2026-04-17 14:55:32 -04:00

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);
}
}
}
}
}
}