This commit is contained in:
2026-04-17 14:55:32 -04:00
commit bc3ac1d4c9
18017 changed files with 4371742 additions and 0 deletions

View File

@@ -0,0 +1 @@
12

View File

@@ -0,0 +1 @@
12

View File

@@ -0,0 +1,142 @@
/*
* IArmable.cs
*
* Copyright © 2010
* Diversified Technical Systems, Inc.
* All Rights Reserved.
*/
namespace DTS.DAS.Concepts
{
/// <summary>
/// different possible arm modes
/// </summary>
public enum AvailableArmModes
{
LowPower,
CircularBuffer,
};
/// <summary>
/// different possible armstatus
/// </summary>
public enum ArmStatus
{
Disarming,
Disarmed,
Arming,
Armed,
Recording, // Extra statuses (chuck's mail)
}
///
/// <summary>
/// Formal description of the ability to "arm".
/// </summary>
///
public interface IArmable
{
void Arm();
void Disarm();
ArmStatus ArmStatus { get; }
AvailableArmModes ArmMode { get; }
}
}
//Like Rollin said, NGI will (for now) be orphaned. NASCAR is in for sure. TSR6DX is really TSRPRO, I think. RateTestTSR==BlastTestTSR and needs to be flattened. TSR==TSRBasic. The missing one in that list is HEADSII.
//NASCAR is 3 16-bit channels using a 216 daughterboard.
//TSRPRO is 6 channels, 3 16-bit on a 216 daughterboard, 3 12-bit on the 215 motherboard
//BlastTestTSR is 7 channels, 4 12-bit on the 215 motherboard, 3 16-bit on a hacked daughterboard
//TSRBasic is 3 12-bit channels on the 215 motherboard
//HEADSII is 7 12-bit channels on the 221 board
//The other missing component to some of what you sent earlier is that some of these systems have multiple sample rates. BlastTestTSR will have the 4 12-bit channels @ 40ksps and the 3 16-bit channels @ 1ksps. NGI had 2 24-bit channels @ 1ksps and 2 16-bit (?? can't remember for sure) channels @ 1sps. As it stands now we have the lower level download code just interpolate slow data to fast data and then everything has the "same" sample rate at the upper level, but it might be nice to deal with it more formally since that creates some funny edge cases we have to deal with by limiting the download to occur in sample number chunks that are a multiple of the fast rate divided by the slow rate.
//On 8/12/2010 11:12 AM, Paul Hrissikopoulos wrote:
//> By the way, the types that the switches currently in the TSR2 code seem to think important are:
//>
//> TSRModel.NASCARIDR:
//> TSRModel.TSR6DX:
//> TSRModel.RateTestTSR:
//> TSRModel.BlastTSR:
//> TSRModel.TSR:
//> TSRModel.NGIPrototype:
//>
//> Are we going to want all of those? Some of those? Those and then some?
//>
//> On 8/12/2010 11:07 AM, Paul Hrissikopoulos wrote:
//>> I guess in theory the software should be able to deal with the multiplicity of device types as it sees fit -- some code, definitely including parts of the UI, will need to be able to actively discriminate between types before doing something type-specific, but I think the hope is that the bulk should be able to use it in a more generic sense (arm the same, download the same, realtime the same, etc.). But still maybe that's a valid point -- do we foresee a ton of cases where we'll be doing interface is/as and/or typefield checks before doing something?
//>>
//>> On 8/12/2010 10:50 AM, Tadd Seiff wrote:
//>>> I like this.
//>>>
//>>> My approach at the moment is immediately how to use this as a HEADS device. My understanding is that the device will surface through the factory which will populate things such as TSR.Channel[] Channels which can then be accessed safely only with RunTime checks like if (HEADS == unit.TSRModel) {...}. Does this put us in the same position being at the mercy of switch statements at a higher level? This is just my knee-jerk reaction.
//>>>
//>>> On 8/12/2010 10:08 AM, Paul Hrissikopoulos wrote:
//>>>> My reordering is attached. Search it for "?" for some open questions. Please let me know if you think I'm missing anything major (or minor) or am entirely on the wrong track.
//>>>>
//>>>> On 8/9/2010 10:26 PM, Rollin White wrote:
//>>>>> Here's an update with a channel class.
//>>>>>
//>>>>> Please voice concerns, opinions, etc. This is just my simple view of the task.
//>>>>>
//>>>>> On 8/9/2010 3:02 PM, Rollin White wrote:
//>>>>>> Here's my first cut at the interface description for the next generation TSR class. The interface is meant to describe the features common to all models.
//>>>>>>
//>>>>>> In addition to what's here, there needs to be significant definition of the channel class. Finally, there are probably a few interfaces that need to be defined that class implementers would optionally implement. For example, ISupportsDynamicEventLength.
//>>>>>>
//>>>>>> This is simply a starting point. Comments welcome.
//>>>>
//>>>
//>>
//>
//>
//--
//Chuck Gillen-O'Neel
//Diversified Technical Systems, Inc.
//909 Electric Avenue, Suite 206
//Seal Beach, CA 90740
//Telephone: (562) 493-0158
//Email: chuck.go@dtsweb.com
// My comments:
// * For sensitivity we should either have mv/count and eu/mv for each channel OR have eu/count for each channel. Obviously the former is more flexible, but also a little more complicated and maybe unneeded for 95-99% of TSR/HEADS applications.
// * OffsetCounts in IChannel should be signed. We nearly always need to make offsets signed. I'm speaking from my own mistakes here ... !!! :)
// * We need to think about the arm states a bit more. There have been a couple of cases where having a Disarming state, in addition to Disarmed, has been nice.
// * For GPIOs we might as well surface (and extend the firmware a bit to support this) the fact that IOs can be inputs as well as high/low outputs. So, rather than just returning a bool we might want to return a state enum. It's already there in the interface for SetGPIO since the GPIOPin.Direction enum has input and output and if it's set to input the State parameter is effectively a no-op.
// * The question of a good interface for Calibration is still unanswered. The interface as shown is obviously fine for doing those three readings, but I'm not sure how truly useful that is in a generic sense. I have a feeling that this is a place where we'll be hooking in model checks, etc. etc. Maybe that's okay and can be limited to the cal software.
//On 8/12/2010 10:50 AM, Tadd Seiff wrote:
//> I like this.
//>
//> My approach at the moment is immediately how to use this as a HEADS device. My understanding is that the device will surface through the factory which will populate things such as TSR.Channel[] Channels which can then be accessed safely only with RunTime checks like if (HEADS == unit.TSRModel) {...}. Does this put us in the same position being at the mercy of switch statements at a higher level? This is just my knee-jerk reaction.
//>
//> On 8/12/2010 10:08 AM, Paul Hrissikopoulos wrote:
//>> My reordering is attached. Search it for "?" for some open questions. Please let me know if you think I'm missing anything major (or minor) or am entirely on the wrong track.
//>>
//>> On 8/9/2010 10:26 PM, Rollin White wrote:
//>>> Here's an update with a channel class.
//>>>
//>>> Please voice concerns, opinions, etc. This is just my simple view of the task.
//>>>
//>>> On 8/9/2010 3:02 PM, Rollin White wrote:
//>>>> Here's my first cut at the interface description for the next generation TSR class. The interface is meant to describe the features common to all models.
//>>>>
//>>>> In addition to what's here, there needs to be significant definition of the channel class. Finally, there are probably a few interfaces that need to be defined that class implementers would optionally implement. For example, ISupportsDynamicEventLength.
//>>>>
//>>>> This is simply a starting point. Comments welcome.
//>>
//>
//--
//Chuck Gillen-O'Neel
//Diversified Technical Systems, Inc.
//909 Electric Avenue, Suite 206
//Seal Beach, CA 90740
//Telephone: (562) 493-0158
//Email: chuck.go@dtsweb.com

View File

@@ -0,0 +1,682 @@
using DTS.Common.Enums.Sensors;
using System;
using System.Collections.Generic;
using System.Text;
namespace DTS.Common.DAS.Concepts
{
public class LinearizationFormula
{
private bool _bIsValid;
public bool IsValid() { return _bIsValid; }
public void MarkValid(bool bValid)
{
_bIsValid = bValid;
}
// Translation
public NonLinearSLICEWareStyles NonLinearSliceWareStyle
{
get => (NonLinearSLICEWareStyles)NonLinearStyle;
set => NonLinearStyle = (NonLinearStyles)value;
}
public NonLinearStyles NonLinearStyle { get; set; } = NonLinearStyles.Polynomial; // Dont make the default style one that locks a specific zero-method FB 10323
public double PolynomialSensitivity { get; set; } = 1D;
public double LinearizationExponent { get; set; } = 1D;
/// <summary>
/// THIS IS MM/V, (UI has already been updated, we need to update the variable name)
/// </summary>
private double _mmPerMV;
public double MMPerV
{
get => _mmPerMV;
set => _mmPerMV = value;
}
public double MVAt0MM { get; set; }
public double Slope { get; set; }
public double Intercept { get; set; }
public double CalibrationFactor { get; set; }
public double ZeroPositionIntercept { get; set; }
public LinearizationFormula()
{
ZeroPositionIntercept = 0D;
CalibrationFactor = 0D;
Intercept = 0D;
_coefficients = new List<double>(new double[] { 0, 0, 0, 0 });
_exponents = new List<double>(new double[] { 0, 1, 2, 3 });
}
public LinearizationFormula(LinearizationFormula copy)
{
UsemVOverVForPolys = copy.UsemVOverVForPolys;
_bIsValid = copy._bIsValid;
_coefficients = new List<double>(copy._coefficients.ToArray());
_exponents = new List<double>(copy._exponents.ToArray());
Intercept = copy.Intercept;
LinearizationExponent = copy.LinearizationExponent;
_mmPerMV = copy._mmPerMV;
MVAt0MM = copy.MVAt0MM;
Slope = copy.Slope;
NonLinearStyle = copy.NonLinearStyle;
_coefficients = new List<double>(copy._coefficients);
_exponents = new List<double>(copy._exponents);
PolynomialSensitivity = copy.PolynomialSensitivity;
ZeroPositionIntercept = copy.ZeroPositionIntercept;
CalibrationFactor = copy.CalibrationFactor;
}
public double GetCoefficient(double exponent)
{
for (var i = 0; i < _exponents.Count && i < _coefficients.Count; i++)
{
if (_exponents[i] == exponent) { return _coefficients[i]; }
}
return 0;
}
public void SetCoefficient(double exponent, double coefficient)
{
for (var i = 0; i < _exponents.Count && i < _coefficients.Count; i++)
{
if (_exponents[i] == exponent) { _coefficients[i] = coefficient; return; }
}
}
public double GetLinearizedValue(double input, double excitation)
{
if (NonLinearStyle != NonLinearStyles.Polynomial && input <= 0)
{
//ir-tracc should never be < 0, however we may get readings less than zero due to
//noise and other factors, treat these as positive near to zero
input = .001;
}
//first linearize
input /= 1000D;//assume input is in mV and we want it in Volts
input = Math.Pow(input, LinearizationExponent);
switch (NonLinearStyle)
{
case NonLinearStyles.IRTraccDiagnosticsZero:
return GetEUDiagnosticsZero(input);
case NonLinearStyles.IRTraccManual:
return GetEUIRTraccManual(input);
case NonLinearStyles.IRTraccZeroMMmV:
return GetEUZeroMMmV(input);
case NonLinearStyles.IRTraccAverageOverTime:
return GetEUAverageOverTime(input);
case NonLinearStyles.Polynomial:
return GetEUPolynomial(input, excitation);
case NonLinearStyles.IRTraccCalFactor:
return GetEUIRTraccCalFactor(input);
default:
throw new NotSupportedException("unknown format: " + NonLinearStyle);
}
}
private double GetEUIRTraccCalFactor(double volts)
{
return volts * CalibrationFactor + ZeroPositionIntercept;
}
private double GetEUIRTraccManual(double volts)
{
return (volts - Intercept) / Slope;
}
public bool UsemVOverVForPolys { get; set; }
private double GetEUZeroMMmV(double volts)
{
var input = MVAt0MM / 1000D;
input = Math.Pow(input, LinearizationExponent);
if (double.IsNaN(input) || double.IsNegativeInfinity(input) || double.IsPositiveInfinity(input))
{
return volts * MMPerV;
}
return (volts * MMPerV - MMPerV * input);
}
private List<double> _coefficients = new List<double>();
private List<double> _exponents = new List<double>();
private double GetEUPolynomial(double volts, double excitation)
{
//per J2517
//3.4 Use of the Calibration Coefficients
//The potentiometer assembly should be re-installed in the dummy without any mechanical adjustment of the
//potentiometer. Prior to a crash test, the original zero offset level must be preserved by either not zeroing the
//potentiometer (by signal conditioning or post-processing) or the amount that was zeroed must be added during postprocessing.
//During the test the absolute voltage output time history should be recorded. This voltage signal is then
//converted to engineering units by:
//1. Convert voltage signal to mV/V at the sensor. This is the sensor reading S.
//2. Convert the sensor reading S to displacement D by using the equation:
//D = A*S^3 + B*S^2 + C*S + M (Eq. 2)
//where:
//D is the displacement relative to the thorax design position in mm
//S is the sensor output reading in mV/V
//A, B, C, and M are the calibration coefficients
//NOTE: Make sure to use sufficient significant digits on all coefficients to assure accuracy of the conversion to
//engineering units. It is recommended to use 5 significant digits (example 0.000012345).
//double mV = volts * 1000D;
//double gain = 1D;
//mV = mV / (gain * excitation);
//if (0 != PolynomialSensitivity && 1!= PolynomialSensitivity) { mV /= PolynomialSensitivity; }
//double eu = 0D;
//for (int i = 0; i < _coefficients.Count && i < _exponents.Count; i++)
//{
// eu += _coefficients[i] * Math.Pow(mV, _exponents[i]);
//}
//return eu;
//CHANGED FOR GM TESTING
if (0 != PolynomialSensitivity && 1 != PolynomialSensitivity)
{
volts /= PolynomialSensitivity;
}
var voltsOverV = 0D;
if (UsemVOverVForPolys)
{
//convert to mV first
voltsOverV = (volts * 1000D) / excitation;
}
else
{
//used by GM
voltsOverV = volts / excitation;
}
double eu = 0;
for (var i = 0; i < _coefficients.Count && i < _exponents.Count; i++)
{
if (_exponents[i] != 0)
{
eu += _coefficients[i] * Math.Pow(voltsOverV, _exponents[i]);
}
else
{
eu += _coefficients[i];
}
}
return eu;
}
/// <summary>
/// MvAt0MM set at diagnostics
/// </summary>
/// <param name="volts"></param>
/// <returns></returns>
private double GetEUDiagnosticsZero(double volts)
{
//double input = MVAt0MM/1000D;
//input = System.Math.Pow(input,LinearizationExponent);
var input = double.NaN;
if (double.IsNaN(input) || double.IsPositiveInfinity(input) || double.IsNegativeInfinity(input))
{
return volts * MMPerV;
}
return volts * MMPerV - MMPerV * input;
}
/// <summary>
/// MVAt0MM set by diagnostics and then later on at
/// Average Over Time
/// </summary>
/// <param name="volts"></param>
/// <returns></returns>
private double GetEUAverageOverTime(double volts)
{
//double input = MVAt0MM / 1000D;
//input = System.Math.Pow(input, LinearizationExponent);
var input = double.NaN;
if (double.IsNaN(input) || double.IsNegativeInfinity(input) || double.IsPositiveInfinity(input))
{
return volts * MMPerV;
}
return volts * MMPerV - MMPerV * input;
}
public string ToSLICEWareSerializeString()
{
if (!_bIsValid) { return ""; }
var sb = new StringBuilder();
sb.AppendFormat("{0}_", NonLinearStyle);
switch (NonLinearStyle)
{
case NonLinearStyles.IRTraccDiagnosticsZero:
sb.Append(ToIRTraccDiagnosticZeroString());
break;
case NonLinearStyles.IRTraccManual:
sb.Append(ToIRTraccManualString());
break;
case NonLinearStyles.IRTraccZeroMMmV:
sb.Append(ToIRTraccZeroMMmVString());
break;
case NonLinearStyles.IRTraccAverageOverTime:
sb.Append(ToIRTraccAverageOverTimeString());
break;
case NonLinearStyles.Polynomial:
sb.Append(ToSLICEWarePolynomialString());
break;
case NonLinearStyles.IRTraccCalFactor:
throw new NotSupportedException("CalFactor not supported in SLICEWare");
default:
throw new NotSupportedException("unknown type: " + NonLinearStyle);
}
return sb.ToString();
}
/// <summary>
/// serializes to a string of the format "c0xe0 c1xe1...cnxen"
/// this will allow us arbitrary length polynomials and fractional exponents.
/// </summary>
/// <returns></returns>
public string ToSerializeString()
{
if (!_bIsValid) { return ""; }
var sb = new StringBuilder();
sb.AppendFormat("{0}_", NonLinearStyle);
switch (NonLinearStyle)
{
case NonLinearStyles.IRTraccDiagnosticsZero:
sb.Append(ToIRTraccDiagnosticZeroString());
break;
case NonLinearStyles.IRTraccManual:
sb.Append(ToIRTraccManualString());
break;
case NonLinearStyles.IRTraccZeroMMmV:
sb.Append(ToIRTraccZeroMMmVString());
break;
case NonLinearStyles.IRTraccAverageOverTime:
sb.Append(ToIRTraccAverageOverTimeString());
break;
case NonLinearStyles.Polynomial:
sb.Append(ToPolynomialString());
break;
case NonLinearStyles.IRTraccCalFactor:
sb.Append(ToIRTraccCalFactorString());
break;
default:
throw new NotSupportedException("unknown type: " + NonLinearStyle);
}
return sb.ToString();
}
public string ToIRTraccDiagnosticZeroString()
{
return $"{MMPerV.ToString(System.Globalization.CultureInfo.InvariantCulture)}x{LinearizationExponent.ToString(System.Globalization.CultureInfo.InvariantCulture)}";
}
public string ToIRTraccCalFactorString()
{
return $"{CalibrationFactor.ToString(System.Globalization.CultureInfo.InvariantCulture)}x{LinearizationExponent.ToString(System.Globalization.CultureInfo.InvariantCulture)}x{ZeroPositionIntercept.ToString(System.Globalization.CultureInfo.InvariantCulture)}";
}
public void FromIRTraccCalFactorString(string s, System.Globalization.CultureInfo culture)
{
var tokens = s.Split('x');
if (tokens.Length < 3) { throw new NotSupportedException("Invalid CalFactor format: " + s); }
CalibrationFactor = double.Parse(tokens[0], culture);
LinearizationExponent = double.Parse(tokens[1], culture);
ZeroPositionIntercept = double.Parse(tokens[2], culture);
}
public void FromIRTraccDiagnosticZeroString(string s, System.Globalization.CultureInfo culture)
{
var tokens = s.Split('x');
if (tokens.Length < 2) { throw new NotSupportedException("Invalid DiagnosticsZero format: " + s); }
MMPerV = double.Parse(tokens[0], culture);
LinearizationExponent = double.Parse(tokens[1], culture);
}
public string ToIRTraccManualString()
{
return $"{Slope.ToString(System.Globalization.CultureInfo.InvariantCulture)}x{Intercept.ToString(System.Globalization.CultureInfo.InvariantCulture)}x{LinearizationExponent.ToString(System.Globalization.CultureInfo.InvariantCulture)}";
}
public void FromIRTraccManualString(string s, System.Globalization.CultureInfo culture)
{
var tokens = s.Split('x');
if (tokens.Length < 3) { throw new NotSupportedException("Invalid IRTraccManual format: " + s); }
Slope = double.Parse(tokens[0], culture);
Intercept = double.Parse(tokens[1], culture);
LinearizationExponent = double.Parse(tokens[2], culture);
}
public string ToIRTraccZeroMMmVString()
{
return $"{MMPerV.ToString(System.Globalization.CultureInfo.InvariantCulture)}x{MVAt0MM.ToString(System.Globalization.CultureInfo.InvariantCulture)}x{LinearizationExponent.ToString(System.Globalization.CultureInfo.InvariantCulture)}";
}
public string ToSLICEWarePolynomialString()
{
//SLICEWare is the reverse order of our DataPRO Database
var sb = new StringBuilder();
for (var i = _exponents.Count - 1; i >= 0; i--)
{
if (i != _exponents.Count - 1) { sb.Append(","); }
sb.AppendFormat("{0}x{1}", _coefficients[i].ToString(System.Globalization.CultureInfo.InvariantCulture),
_exponents[i].ToString(System.Globalization.CultureInfo.InvariantCulture));
}
sb.AppendFormat(",S={0}", PolynomialSensitivity.ToString(System.Globalization.CultureInfo.InvariantCulture));
return sb.ToString();
}
public string ToPolynomialString()
{
var sb = new StringBuilder();
for (var i = 0; i < _coefficients.Count && i < _exponents.Count; i++)
{
if (i > 0) { sb.Append(","); }
sb.AppendFormat("{0}x{1}", _coefficients[i].ToString(System.Globalization.CultureInfo.InvariantCulture),
_exponents[i].ToString(System.Globalization.CultureInfo.InvariantCulture));
}
sb.AppendFormat(",S={0},mV={1}",
PolynomialSensitivity.ToString(System.Globalization.CultureInfo.InvariantCulture),
UsemVOverVForPolys.ToString(System.Globalization.CultureInfo.InvariantCulture));
return sb.ToString();
}
public double[] PolynomialCoefficients
{
get => _coefficients.ToArray();
set => _coefficients = new List<double>(value);
}
public double[] PolynomialExponents
{
get => _exponents.ToArray();
set => _exponents = new List<double>(value);
}
public string ToIRTraccAverageOverTimeString()
{
return $"{MMPerV.ToString(System.Globalization.CultureInfo.InvariantCulture)}x{LinearizationExponent.ToString(System.Globalization.CultureInfo.InvariantCulture)}";
}
public void FromIRTraccAverageOverTimeString(string s, System.Globalization.CultureInfo culture)
{
var tokens = s.Split('x');
if (tokens.Length < 2) { throw new NotSupportedException("Invalid IRTRaccAverageOverTime format: " + s); }
MMPerV = double.Parse(tokens[0], culture);
LinearizationExponent = double.Parse(tokens[1], culture);
}
public void FromIRTraccZeroMMmVString(string s, System.Globalization.CultureInfo culture)
{
var tokens = s.Split('x');
if (tokens.Length < 3) { throw new NotSupportedException("Invalid IRTraccZeroMMmV format: " + s); }
MMPerV = double.Parse(tokens[0], culture);
MVAt0MM = double.Parse(tokens[1], culture);
LinearizationExponent = double.Parse(tokens[2], culture);
}
public void FromPolynomialString(string s, System.Globalization.CultureInfo culture)
{
_coefficients.Clear();
_exponents.Clear();
var tokens = s.Split(',');
foreach (var t in tokens)
{
var subtokens = t.Split('x');
if (2 == subtokens.Length)
{
if (double.TryParse(subtokens[0], System.Globalization.NumberStyles.Float, culture, out var d))
{
_coefficients.Add(d);
_exponents.Add(double.Parse(subtokens[1], culture));
}
else
{
PolynomialSensitivity = double.Parse(subtokens[1], culture);
}
}
else
{
subtokens = t.Split('=');
if (subtokens.Length == 2)
{
switch (subtokens[0])
{
case "S":
PolynomialSensitivity = double.Parse(subtokens[1], culture);
break;
case "mV":
UsemVOverVForPolys = Convert.ToBoolean(subtokens[1], culture);
break;
}
}
}
}
}
public void FromSerializeString(string s, System.Globalization.CultureInfo culture)
{
if (string.IsNullOrEmpty(s)) { _bIsValid = false; return; }
if (s.Equals("1") || s.Equals("0") || s.Equals("1 ")) { _bIsValid = false; return; }
var tokens = s.Split('_');
if (tokens.Length < 2) { throw new NotSupportedException("unsupported Linearization Formula Format"); }
var style = (NonLinearStyles)Enum.Parse(typeof(NonLinearStyles), tokens[0], true);
NonLinearStyle = style;
switch (NonLinearStyle)
{
case NonLinearStyles.IRTraccDiagnosticsZero:
FromIRTraccDiagnosticZeroString(tokens[1], culture);
_bIsValid = true;
break;
case NonLinearStyles.IRTraccManual:
FromIRTraccManualString(tokens[1], culture);
_bIsValid = true;
break;
case NonLinearStyles.IRTraccZeroMMmV:
FromIRTraccZeroMMmVString(tokens[1], culture);
_bIsValid = true;
break;
case NonLinearStyles.Polynomial:
FromPolynomialString(tokens[1], culture);
_bIsValid = true;
break;
case NonLinearStyles.IRTraccAverageOverTime:
FromIRTraccAverageOverTimeString(tokens[1], culture);
_bIsValid = true;
break;
case NonLinearStyles.IRTraccCalFactor:
FromIRTraccCalFactorString(tokens[1], culture);
_bIsValid = true;
break;
default:
throw new NotSupportedException("Unknown format: " + NonLinearStyle);
}
}
public void FromSerializeString(string s)
{
FromSerializeString(s, System.Globalization.CultureInfo.InvariantCulture);
}
public void FromTDCSerializeString()
{
_bIsValid = true;
}
/// <summary>
/// Will return a display string for a nonlinear calibration based on N4 formating
/// </summary>
public string ToDisplayString()
{
return ToDisplayString("N4");
}
/// <summary>
/// Will return a display string for a nonlinear calibration based on 1st paramater formating string
/// </summary>
/// <param name="nonlinearFormat"></param>
/// <returns></returns>
public string ToDisplayString(string nonlinearFormat)
{
if (string.IsNullOrEmpty(nonlinearFormat)) { nonlinearFormat = "N4"; }
switch (NonLinearStyle)
{
case NonLinearStyles.Polynomial:
{
return ToPolynomial(nonlinearFormat);
}
case NonLinearStyles.IRTraccZeroMMmV:
{
return $"mV = {MVAt0MM:n4}, {MMPerV:n4}*(V^{ToSuperScript(LinearizationExponent.ToString(nonlinearFormat))})";
}
case NonLinearStyles.IRTraccManual:
{
return $"((V^{ToSuperScript(LinearizationExponent.ToString(nonlinearFormat))})-{Intercept:n4})/{Slope:n4}";
}
case NonLinearStyles.IRTraccDiagnosticsZero:
{
return $"{MMPerV:n4}*(V^{ToSuperScript(LinearizationExponent.ToString(nonlinearFormat))})";
}
case NonLinearStyles.IRTraccAverageOverTime:
{
return $"{MMPerV:n4}*(V^{ToSuperScript(LinearizationExponent.ToString(nonlinearFormat))})";
}
case NonLinearStyles.IRTraccCalFactor:
{
return $"{ZeroPositionIntercept:n4}+{CalibrationFactor:n4}*(V^{ToSuperScript(LinearizationExponent.ToString(nonlinearFormat))})";
}
default:
return string.Empty;
}
}
private string ToPolynomial(string nonlinearFormat)
{
if (string.IsNullOrEmpty(nonlinearFormat)) { nonlinearFormat = "N4"; }
var sb = new StringBuilder();
var termNumber = PolynomialCoefficients.Length - 1;
foreach (var x in PolynomialCoefficients)
{
if (PolynomialCoefficients[termNumber] != 0)
{
var coeff = PolynomialCoefficients[termNumber];
// Let the appended math symbol handle sign unless we're the first term.
if (termNumber != PolynomialCoefficients.Length - 1)
{
coeff = Math.Abs(coeff);
}
sb.Append(coeff.ToString(nonlinearFormat));
if (PolynomialExponents[termNumber] != 0)
{
sb.Append("x");
if (PolynomialExponents[termNumber] != 1)
{
sb.Append(ToSuperScript(PolynomialExponents[termNumber].ToString("N0")));
}
}
if (termNumber > 0)
{
// Coerricients are Displayed in absolute value. We need to combine the sign with the addition symbol
sb.Append(PolynomialCoefficients[termNumber - 1] > 0 ? " + " : " - ");
}
}
termNumber--;
}
return sb.ToString();
}
private string ToSuperScript(string source)
{
var superScript = new StringBuilder();
foreach (var c in source)
{
switch (c)
{
case '-':
superScript.Append('\u207B');
break;
case '.':
superScript.Append('\u00B7');
break;
case '1':
superScript.Append('\u00B9');
break;
case '2':
superScript.Append('\u00B2');
break;
case '3':
superScript.Append('\u00B3');
break;
case '4':
superScript.Append('\u2074');
break;
case '5':
superScript.Append('\u2075');
break;
case '6':
superScript.Append('\u2076');
break;
case '7':
superScript.Append('\u2077');
break;
case '8':
superScript.Append('\u2078');
break;
case '9':
superScript.Append('\u2079');
break;
case '0':
superScript.Append('\u2070');
break;
case '\'':
superScript.Append('\u02C8');
break;
case ',':
superScript.Append('\u22C5'); // there is no unicode superscript comma. this comes close
break;
case '\u00A0':
superScript.Append('\u2009'); // unicode 'thin' space
break;
default:
superScript.Append('\u207F');
break;
}
}
return superScript.ToString();
}
/*
* we are given an equation in the form of y = ax^1 + b, except x and y are backwards for us (y=V where we'd prefer X was voltage, so we switch it)
* y/a - b/a = x, and then switch y and x, (1/a)x^1 -(b/a)x^0 = y
* now we want to get the coefficient of the first equation, which is "a", we get this by taking the inverse
* we get b on the other hand by taking -1 * (b/a)*a. if we have the "coefficient", we have a
*/
/*
public double GetIRTraccCoefficient()
{
foreach (Factor f in Factors)
{
if (f.Exponent == 1D) { return System.Math.Pow(f.Coefficient, -1); }
}
return 1D; //0 doesn't make sense for ir
}
public double GetIRTraccConstant()
{
foreach (Factor f in Factors)
{
if (f.Exponent == 0D) { return -1D * GetIRTraccCoefficient() * f.Coefficient; }
}
return 0D;
}
public void SetIRTraccFactor(double coefficient, double constant)
{
if (0 == coefficient)
{
//well this doesn't make any sense ...
coefficient = 1;
}
Factors = new Factor[]
{
new Factor(1/coefficient,1),
new Factor(-constant/coefficient,0),
};
}*/
}
}

View File

@@ -0,0 +1,62 @@
/*
Test.Module.Channel.Sensor.ExcitationVoltage.cs
Copyright © 2008
Diversified Technical Systems, Inc.
All Rights Reserved
*/
using System.ComponentModel;
namespace DTS.DAS.Concepts
{
// *** see Test.cs ***
public partial class Test
{
/// <summary>
/// A container for DTS generic module concepts.
/// </summary>
public sealed partial class Module
{
// *** see Test.Module.Channel.cs ***
public partial class Channel
{
//*** see Test.Module.Channel.Sensor.cs ***
public partial class Sensor
{
/// <summary>
/// All available Sensitivity Unit types.
/// </summary>
public enum SensUnits
{
/// <summary>
/// No Sensitivity Units (Polynomial Sensor)
/// </summary>
[Description("NONE")]
NONE = 0,
/// <summary>
/// Sensitivity expressed in mV with output at Capacity EU
/// </summary>
[Description("mV")]
mV = 1,
/// <summary>
/// Excitation proportional sensitivity expressed in mV/V with output at Capacity EU
/// </summary>
[Description("mV/V")]
mVperV = 2,
/// <summary>
/// Excitation proportional sensitivity expressed in mV/V/EU
/// </summary>
[Description("mV/V/EU")]
mVperVperEU = 3,
/// <summary>
/// Sensitivity expressed in mV/EU
/// </summary>
[Description("mV/EU")]
mVperEU = 4
}
}
}
}
}
}

View File

@@ -0,0 +1,42 @@
/*
Test.Module.Channel.Sensor.ShuntModeType.cs
Copyright © 2010
Diversified Technical Systems, Inc.
All Rights Reserved
*/
using System.ComponentModel;
namespace DTS.Common.DAS.Concepts
{
// *** see Test.cs ***
public partial class Test
{
/// <summary>
/// A container for DTS generic module concepts.
/// </summary>
public sealed partial class Module
{
// *** see Test.Module.Channel.cs ***
public partial class Channel
{
//*** see DTS.Common.DAS.Concepts.Test.Module.Channel.Sensor.cs ***
public partial class Sensor
{
public enum ShuntModeType
{
[Description("Internal")]
Internal,
[Description("External")]
External,
[Description("Emulation")]
Emulation,
[Description("None")]
None
}
}
}
}
}
}

View File

@@ -0,0 +1,171 @@
/*
* DAS.Id.cs
* DTM - why does this class exist? it's only encapsulating a string
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
using System;
using DTS.Common.Utilities;
namespace DTS.Common.DAS.Concepts.DAS
{
/// <summary>
/// Representation of the DTS.Common.DAS.Concepts.DAS.Id type.
/// why does this class even exist?
/// </summary>
public sealed class Id : Exceptional, IComparable<Id>, IEquatable<Id>
{
/// <summary>
/// The Thing In Itself.
/// </summary>
private readonly string value;
/// <summary>
/// Initialize an instance of the DTS.Common.DAS.Concepts.DAS.Id class.
/// </summary>
public Id(string value)
{
this.value = value;
}
/// <summary>
/// Allow DTS.Common.DAS.Concepts.DAS.Ids to be implicitly converted to strings.
/// </summary>
///
/// <param name="id">
/// The <see cref="Id"/> id to be stringified.
/// </param>
///
/// <returns>
/// The <see cref="string"/> value of this DTS.Common.DAS.Concepts.DAS.Id.
/// </returns>
///
public static implicit operator string(Id id)
{
return id.ToString();
}
/// <summary>
/// Allow strings to be implicitly converted to DTS.Slice.Control.DAS.Ids.
/// </summary>
///
/// <param name="id">
/// The <see cref="string"/> value to be DTS.Slice.Control.DAS.Id-ified.
/// </param>
///
/// <returns>
/// The <see cref="Id"/> equivalent to the specified string.
/// </returns>
///
public static implicit operator Id(string id)
{
return new Id(id);
}
public override bool Equals(object obj)
{
if (obj is Id that) { return Equals(that); }
return string.Compare(ToString(), obj.ToString(), StringComparison.OrdinalIgnoreCase) == 0;
}
/// <summary>
/// Determine whether this object instance and the specified object instance are equal.
/// </summary>
///
/// <param name="that">
/// The <see cref="Id"/> to be compared to this object instance.
/// </param>
///
/// <returns>
/// <see cref="bool"/> true if this object is equal to the specified object; false otherwise.
/// </returns>
///
public bool Equals(Id that)
{
if (value == that.value) { return true; }
if (null == value) { return false; }
if (null == that.value) { return false; }
return value.Equals(that.value, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// Generate a comparison value between this object and another of it's type.
/// </summary>
///
/// <param name="that">
/// The <see cref="Id"/> to which this one is to be compared.
/// </param>
///
/// <returns>
/// An <see cref="int"/> value expressing the "similarity" between this object
/// and the one specified.
/// </returns>
///
public int CompareTo(Id that)
{
return Compare(this, that);
}
/// <summary>
/// Generate a string representation of this class.
/// </summary>
///
/// <returns>
/// The <see cref="string"/> representation of this object.
/// </returns>
///
public override string ToString()
{
return value;
}
/// <summary>
/// Generate a hash code for this instance.
/// </summary>
///
/// <returns>
/// The <see cref="int"/> hash code for this instance.
/// </returns>
///
public override int GetHashCode()
{
return value?.GetHashCode() ?? 0;
}
public static bool operator ==(Id left, Id right)
{
if (ReferenceEquals(left, null))
{
return ReferenceEquals(right, null);
}
return left.Equals(right);
}
public static int Compare(Id left, Id right)
{
if (left == right) { return 0; }
if (null == right) { return 1; }
if (null == left) { return -1; }
return string.Compare(left.ToString(), right.ToString(), StringComparison.OrdinalIgnoreCase);
}
public static bool operator >= (Id left, Id right)
{
return Compare(left, right) >= 0;
}
public static bool operator >(Id left, Id right)
{
return Compare(left, right) > 0;
}
public static bool operator <= (Id left, Id right)
{
return Compare(left, right) <= 0;
}
public static bool operator <(Id left, Id right)
{
return Compare(left, right) < 0;
}
public static bool operator !=(Id left, Id right)
{
return !(left == right);
}
}
}

View File

@@ -0,0 +1,230 @@
<?xml version="1.0" encoding="utf-8"?>
<ClassDiagram MajorVersion="1" MinorVersion="1">
<Class Name="DTS.Common.DAS.Concepts.DataScaler" Collapsed="true">
<Position X="11.75" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>yIIHsKRGAwEJpVQIBARAJBBuA1EgIBouDUBAUIBBABY=</HashCode>
<FileName>DataScaler.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="DTS.Common.DAS.Concepts.DigitalInputScaleMultiplier" Collapsed="true">
<Position X="13.5" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAgAAIAAAgAAAAAAAAAhAAIAAAAQEAEEAAAA=</HashCode>
<FileName>DigitalInputScaleMultiplier.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="DTS.Common.DAS.Concepts.RealtimeSample" Collapsed="true">
<Position X="11.75" Y="1.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAgAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\IRealtimeable.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="DTS.Common.DAS.Concepts.LinearizationFormula" Collapsed="true">
<Position X="10" Y="1.5" Width="1.5" />
<TypeIdentifier>
<HashCode>EBABiQDJAEEswAAoCAgAAQJCAYBXAKGgAABAAgKEMUA=</HashCode>
<FileName>LinearizationFormula.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="DTS.Common.DAS.Concepts.Test" Collapsed="true">
<Position X="13.5" Y="1.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>ShuntModeType.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="DTS.Common.DAS.Concepts.TsrEvent" Collapsed="true" BaseTypeListCollapsed="true">
<Position X="8.25" Y="2.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAABCwAAAAAAAAAAAAAAAAAAEoAAAAAAAAAAAEABA=</HashCode>
<FileName>TsrEvent.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" Collapsed="true" />
</Class>
<Class Name="DTS.Common.DAS.Concepts.DAS.Channel&lt;TDataType&gt;" Collapsed="true">
<Position X="8.25" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>DAS\Channel\Channel.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="DTS.Common.DAS.Concepts.DAS.Id" Collapsed="true" BaseTypeListCollapsed="true">
<Position X="8.25" Y="1.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAQIAAAAAAAAAQEgAAAAAAAAAAAAKAAAAAAAAAAAAA=</HashCode>
<FileName>DAS\DAS.Id.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" Collapsed="true" />
</Class>
<Class Name="DTS.Common.DAS.Concepts.DAS.Channel.Data&lt;TDatumType&gt;" Collapsed="true">
<Position X="10" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>DAS\Channel\Data.cs</FileName>
</TypeIdentifier>
</Class>
<Interface Name="DTS.Common.DAS.Concepts.IArmable" Collapsed="true">
<Position X="0.5" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAEAAAAAAAAAAAgIAAAABAAAAAAAA=</HashCode>
<FileName>Interfaces\IArmable.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.ICalibratable" Collapsed="true">
<Position X="8.25" Y="3.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAQAAAAAAADAAAAAAAAAAIAAEAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\ICalibratable.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.IDataCollectionEnabled" Collapsed="true">
<Position X="0.5" Y="1.75" Width="1.5" />
<TypeIdentifier>
<HashCode>BAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\IDataCollectionEnabled.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.IDownloadEnabled" Collapsed="true">
<Position X="3.5" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAACAAAAABAQAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\IDownloadEnabled.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.IGpioEnabled" Collapsed="true">
<Position X="8.25" Y="4.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABABAAAA=</HashCode>
<FileName>Interfaces\IGpioEnabled.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.IRealtimeable" Collapsed="true">
<Position X="11.75" Y="5.25" Width="1.5" />
<TypeIdentifier>
<HashCode>AIAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\IRealtimeable.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.ITriggerable" Collapsed="true">
<Position X="5.75" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\ITriggerable.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.DAS.Channel.ICalSignalAware" Collapsed="true">
<Position X="10" Y="3.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAACAAAAAA=</HashCode>
<FileName>Interfaces\DAS\Channel\ICalSignalAware.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.DAS.Channel.IDecimatable&lt;T&gt;" Collapsed="true">
<Position X="11.75" Y="3.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAACAgAAAAAAAAAAAgAAAAAAAAAIAA=</HashCode>
<FileName>Interfaces\DAS\Channel\IDecimatable.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.DAS.Channel.IEngineeringUnitAware" Collapsed="true">
<Position X="13.5" Y="3.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\DAS\Channel\IEngineeringUnitAware.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.DAS.Channel.IInversionAware" Collapsed="true">
<Position X="10" Y="4.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\DAS\Channel\IInversionAware.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.DAS.Channel.IIsoCodeAware" Collapsed="true">
<Position X="11.75" Y="4.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\DAS\Channel\IIsoCodeAware.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.DAS.Channel.ILevelTriggerable" Collapsed="true">
<Position X="8.25" Y="5.25" Width="1.5" />
<TypeIdentifier>
<HashCode>AAIAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAg=</HashCode>
<FileName>Interfaces\DAS\Channel\ILevelTriggerable.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.DAS.Channel.ILinearized" Collapsed="true">
<Position X="10" Y="5.25" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\DAS\Channel\ILinearized.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.DAS.Channel.ISerialNumberAware" Collapsed="true">
<Position X="13.5" Y="5.25" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\DAS\Channel\ISerialNumberAware.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.DAS.Channel.IShuntAware" Collapsed="true">
<Position X="8.25" Y="6" Width="1.5" />
<TypeIdentifier>
<HashCode>ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAA=</HashCode>
<FileName>Interfaces\DAS\Channel\IShuntAware.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.DAS.Channel.IVoltageInsertionAware" Collapsed="true">
<Position X="10" Y="6" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAEAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\DAS\Channel\IVoltageInsertAware.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.DAS.Channel.ILargeDataAware" Collapsed="true">
<Position X="13.5" Y="4.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\ILargeDataAware.cs</FileName>
</TypeIdentifier>
</Interface>
<Enum Name="DTS.Common.DAS.Concepts.ArmStatus" Collapsed="true">
<Position X="8.25" Y="7" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAIBAAAAAAAAAAAAAAAIBAAAAAAAAgAAAAA=</HashCode>
<FileName>ArmStatus.cs</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="DTS.Common.DAS.Concepts.AvailableArmModes" Collapsed="true">
<Position X="10" Y="7" Width="1.5" />
<TypeIdentifier>
<HashCode>AIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>AvailableArmModes.cs</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="DTS.Common.DAS.Concepts.DAS.DecimationMethod" Collapsed="true">
<Position X="11.75" Y="7" Width="1.5" />
<TypeIdentifier>
<HashCode>ACAAAAAAAAAAhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>DAS\DecimationMethod.cs</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="DTS.Common.DAS.Concepts.DAS.Channel.LevelTriggerTypes" Collapsed="true">
<Position X="8.25" Y="7.75" Width="1.5" />
<TypeIdentifier>
<HashCode>ACAAAAACACAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAACA=</HashCode>
<FileName>DAS\Channel\LevelTriggerTypes.cs</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="DTS.Common.Common.DAS.Concepts.GPIOPin.Directions" Collapsed="true">
<Position X="13.5" Y="7" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAYAAAAEAQAAAAAAAAAgAAAAAA=</HashCode>
<FileName>Interfaces\IGpioEnabled.cs</FileName>
</TypeIdentifier>
</Enum>
<Font Name="Segoe UI" Size="9" />
</ClassDiagram>

View File

@@ -0,0 +1,54 @@
/*
Test.Module.RecordingMode.cs
Copyright © 2008
Diversified Technical Systems, Inc.
All Rights Reserved
*/
using DTS.Common.Enums.DASFactory;
using System;
using System.ComponentModel;
namespace DTS.Common.DAS.Concepts
{
// *** see Test.cs ***
public partial class Test
{
/// <summary>
/// A container for DTS generic module concepts.
/// </summary>
public sealed partial class Module
{
/// <summary>
/// Convert a string representation of a recording mode enumeration into its corresponding
/// enumeration value.
/// </summary>
///
/// <param name="recordingMode">
/// The <see cref="string"/> representation to be converted.
/// </param>
///
/// <returns>
/// The <see cref="Test.Module.RecordingMode"/> value corresponding to the
/// specified string, if any. If not, an exception will be thrown.
/// </returns>
///
public static DFConstantsAndEnums.RecordingMode GetRecordingModeFromString(string recordingMode)
{
try
{
return (DFConstantsAndEnums.RecordingMode)Enum.Parse(typeof(DFConstantsAndEnums.RecordingMode), recordingMode);
}
catch (Exception ex)
{
throw new Exception("encountered problem getting recording mode from string representation " + (null != recordingMode ? "\"" + recordingMode + "\"" : "<<NULL>>"), ex);
}
}
}
}
}

View File

@@ -0,0 +1,23 @@
namespace DTS.Common.DAS.Concepts.DAS
{
/// <summary>
/// Methods for determining the value of the representative point for decimated sets.
/// </summary>
public enum DecimationMethod
{
/// <summary>
/// Use that value of the PointsPerPoint-th point as the representative value.
/// </summary>
Point,
/// <summary>
/// Use the average of the PointsPerPoint values as the representative value.
/// </summary>
Average,
/// <summary>
/// Use the peak magnitude value of the PointsPerPoint values as the representative value.
/// </summary>
PeakMagnitude,
}
}

View File

@@ -0,0 +1,172 @@
/*
Test.Module.Channel.Sensor.ExcitationVoltage.cs
Copyright © 2008
Diversified Technical Systems, Inc.
All Rights Reserved
*/
using System;
using System.ComponentModel;
using DTS.Utilities;
namespace DTS.DAS.Concepts
{
// *** see Test.cs ***
public partial class Test
{
/// <summary>
/// A container for DTS generic module concepts.
/// </summary>
public sealed partial class Module
{
// *** see Test.Module.Channel.cs ***
public partial class Channel
{
//*** see Test.Module.Channel.Sensor.cs ***
public partial class Sensor
{
/// <summary>
/// All available excitation voltages.
/// </summary>
public enum ExcitationVoltageOption
{
/// <summary>
/// undefined excitation voltage
/// </summary>
[VoltageMagnitude(0.0)]
[Description("Undefined")]
Undefined=1,
/// <summary>
/// 2V
/// </summary>
[VoltageMagnitude(2.0)]
[Description("2.0")]
Volt2=2,
/// <summary>
/// 2.5V
/// </summary>
[VoltageMagnitude(2.5)]
[Description("2.5")]
Volt2_5=4,
/// <summary>
/// 3.0V
/// </summary>
[VoltageMagnitude(3.0)]
[Description("3.0")]
Volt3=8,
/// <summary>
/// 5V
/// </summary>
[VoltageMagnitude( 5.0 )]
[Description("5.0")]
Volt5=16,
/// <summary>
/// 10V
/// </summary>
[VoltageMagnitude( 10.0 )]
[Description("10.0")]
Volt10=32,
/// <summary>
/// 1V
/// </summary>
[VoltageMagnitude(1.0)]
[Description("1.0")]
Volt1 = 64
}
/// <summary>
/// Converts a specified excitation voltage option into its associated numeric value.
/// </summary>
///
/// <param name="target">
/// The <see cref="DTS.DAS.Concepts.Test.Module.Channel.Sensor.ExcitationVoltageOption"/> value
/// to be converted.
/// </param>
///
/// <returns>
/// The <see cref="double"/> magnitude associated with the specified voltage option.
/// </returns>
///
public static double GetExcitationVoltageMagnitudeFromEnum( ExcitationVoltageOption target )
{
try
{
return new VoltageMagnitudeAttributeCoder( ).DecodeAttributeValue( target );
}
catch ( Exception ex )
{
throw new Exception( "encountered problem attempting to get excitation voltage magnitude from enum", ex );
}
}
/// <summary>
/// Converts a specified voltage magnitude to the associated numeric value (if it exists;
/// otherwise an exception is thrown).
/// </summary>
///
/// <param name="magnitude">
/// The <see cref="double"/> magnitude to be converted.
/// </param>
///
/// <returns>
/// The <see cref="DTS.DAS.Concepts.Test.Module.Channel.Sensor.ExcitationVoltageOption"/> value
/// associated with the specified magnitude (if it exists).
/// </returns>
///
public static ExcitationVoltageOption GetExcitationVoltageEnumFromMagnitude( double magnitude )
{
try
{
return new VoltageMagnitudeAttributeCoder( ).EncodeAttributeValue( magnitude );
}
catch ( System.Exception ex )
{
throw new NotSupportedException( "encountered problem attempting to get excitation voltage enum from magnitude", ex );
}
}
/// <summary>
/// Attribute for specifying the numerical magnitude of the attached field's
/// "representation". Intended to be used with enumerations whose members represent
/// voltage magnitude options so that the enum item can have a corresponding numerical
/// value that can be extracted and used in calculations.
/// </summary>
[AttributeUsage(AttributeTargets.Field)]
public class VoltageMagnitudeAttribute: System.Attribute
{
private readonly double _Value;
/// <summary>
/// returns voltage magnitude
/// </summary>
public double Value { get { return _Value; } }
/// <summary>
/// constructs a <see cref="DTS.DAS.Concepts.Test.Module.Channel.Sensor.VoltageMagnitudeAttribute" />
/// with a given value
/// </summary>
/// <param name="value"></param>
public VoltageMagnitudeAttribute(double value) { _Value = value; }
}
/// <summary>
/// Object for manipulating voltage option enumeration-attached
/// <see cref="double"/> magnitude values.
/// </summary>
public class VoltageMagnitudeAttributeCoder
: AttributeCoder<ExcitationVoltageOption, VoltageMagnitudeAttribute, double>
{
/// <summary>
/// Initializes a <see cref="DTS.DAS.Concepts.Test.Module.Channel.Sensor.VoltageMagnitudeAttributeCoder"/> object.
/// </summary>
public VoltageMagnitudeAttributeCoder()
: base(attribute => attribute.Value, null)
{
}
}
}
}
}
}
}

View File

@@ -0,0 +1,33 @@
/*
* IGpioEnabled.cs
*
* Copyright © 2010
* Diversified Technical Systems, Inc.
* All Rights Reserved.
*/
using DTS.Common.Common.DAS.Concepts.GPIOPin;
namespace DTS.Common.Common.DAS.Concepts.GPIOPin
{
public enum Directions
{
Output = 0x00, Peripheral = 0x01, Input = 0x02,
InputPulledUp = 0x03, InputPulledDown = 0x04
};
}
namespace DTS.Common.DAS.Concepts
{ ///
/// <summary>
/// Representation of GPIO functionality.
/// </summary>
///
public interface IGpioEnabled
{
// TODO: Well have to bring these in as soon as we figure out where to get that enum from.
void SetGpio(uint Port, uint Pin, Directions Direction, bool State);
bool GetGpio(uint Port, uint Pin);
}
}

View File

@@ -0,0 +1,35 @@
/*
* DTS.Common.DAS.Concepts.DAS.Channel.IVoltageInsertionAware.cs
*
* Copyright © 2012
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.Common.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of the concept of shunt-check awareness.
/// </summary>
public interface IVoltageInsertionAware
{
/// <summary>
/// Get/set this object's <see cref="double"/> measured shunt deflection value.
/// </summary>
double ExpectedGain
{
get;
set;
}
/// <summary>
/// Get/set this object's <see cref="double"/> target shunt deflection value.
/// </summary>
double MeasuredGain
{
get;
set;
}
}
}

View File

@@ -0,0 +1,25 @@
/*
* DTS.Common.DAS.Concepts.DAS.Channel.IIsoCodeAware.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.Common.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of the concept of ISO code awareness.
/// </summary>
public interface IIsoCodeAware
{
/// <summary>
/// Get/set this object's IsoCode <see cref="string"/>.
/// </summary>
string IsoCode
{
get;
set;
}
}
}

View File

@@ -0,0 +1,25 @@
/*
Test.Module.cs
Copyright © 2008
Diversified Technical Systems, Inc.
All Rights Reserved
*/
namespace DTS.DAS.Concepts
{
// *** see Test.cs ***
public partial class Test
{
/// <summary>
/// A container for DTS generic module concepts.
/// </summary>
public sealed partial class Module
{
/// <summary>
/// Class is not intended for instantiation.
/// </summary>
private Module( ) { }
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* DAS.Channel.IInversionAware.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of the concept of inversion awareness.
/// </summary>
public interface IInversionAware
{ ///
/// <summary>
/// Get/set this object's inversion state <see cref="bool"/>.
/// </summary>
///
bool IsInverted
{
get;
set;
}
}
public interface ILinearized
{
LinearizationFormula LinearizationFormula
{
get;
set;
}
}
}

View File

@@ -0,0 +1,24 @@
/*
* DTS.Common.DAS.Concepts.DAS.Channel.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
using DTS.Common.Utilities;
namespace DTS.Common.DAS.Concepts.DAS
{
/// <summary>
/// Slice control app's internal abstract representation of a DAS channel.
/// </summary>
///
/// <typeparam name="TDataType">
/// The "type" of the data contained by channels of this DAS.
/// </typeparam>
///
public abstract class Channel<TDataType> : Exceptional
{
}
}

View File

@@ -0,0 +1,175 @@
/*
Test.Module.Channel.Sensor.ExcitationVoltage.cs
Copyright © 2008
Diversified Technical Systems, Inc.
All Rights Reserved
*/
using System;
using System.ComponentModel;
using DTS.Common.Enums;
using DTS.Common.Utilities;
using DTS.Common.Utilities.Logging;
namespace DTS.Common.DAS.Concepts
{
// *** see Test.cs ***
public partial class Test
{
/// <summary>
/// A container for DTS generic module concepts.
/// </summary>
public sealed partial class Module
{
// *** see Test.Module.Channel.cs ***
public partial class Channel
{
//*** see DTS.Common.DAS.Concepts.Test.Module.Channel.Sensor.cs ***
public partial class Sensor
{
///// <summary>
///// All available excitation voltages.
///// </summary>
//public enum ExcitationVoltageOption
//{
// /// <summary>
// /// undefined excitation voltage
// /// </summary>
// [VoltageMagnitude(0.0)]
// [Description("Undefined")]
// Undefined=1,
// /// <summary>
// /// 2V
// /// </summary>
// [VoltageMagnitude(2.0)]
// [Description("2.0")]
// Volt2=2,
// /// <summary>
// /// 2.5V
// /// </summary>
// [VoltageMagnitude(2.5)]
// [Description("2.5")]
// Volt2_5=4,
// /// <summary>
// /// 3.0V
// /// </summary>
// [VoltageMagnitude(3.0)]
// [Description("3.0")]
// Volt3=8,
// /// <summary>
// /// 5V
// /// </summary>
// [VoltageMagnitude( 5.0 )]
// [Description("5.0")]
// Volt5=16,
// /// <summary>
// /// 10V
// /// </summary>
// [VoltageMagnitude( 10.0 )]
// [Description("10.0")]
// Volt10=32,
// /// <summary>
// /// 1V
// /// </summary>
// [VoltageMagnitude(1.0)]
// [Description("1.0")]
// Volt1 = 64
//}
/// <summary>
/// Converts a specified excitation voltage option into its associated numeric value.
/// </summary>
///
/// <param name="target">
/// The <see cref="ExcitationVoltageOptions.ExcitationVoltageOption"/> value
/// to be converted.
/// </param>
///
/// <returns>
/// The <see cref="double"/> magnitude associated with the specified voltage option.
/// </returns>
///
public static double GetExcitationVoltageMagnitudeFromEnum(ExcitationVoltageOptions.ExcitationVoltageOption target)
{
try
{
return new ExcitationVoltageOptions.VoltageMagnitudeAttributeCoder().DecodeAttributeValue(target);
}
catch (Exception ex)
{
throw new ArgumentException("encountered problem attempting to get excitation voltage magnitude from enum", ex);
}
}
/// <summary>
/// Converts a specified voltage magnitude to the associated numeric value (if it exists;
/// otherwise an exception is thrown).
/// </summary>
///
/// <param name="magnitude">
/// The <see cref="double"/> magnitude to be converted.
/// </param>
///
/// <returns>
/// The <see cref="ExcitationVoltageOptions.ExcitationVoltageOption"/> value
/// associated with the specified magnitude (if it exists).
/// </returns>
///
public static ExcitationVoltageOptions.ExcitationVoltageOption GetExcitationVoltageEnumFromMagnitude(double magnitude)
{
try
{
return new ExcitationVoltageOptions.VoltageMagnitudeAttributeCoder().EncodeAttributeValue(magnitude);
}
catch (Exception ex)
{
APILogger.Log("encountered problem attempting to get excitation voltage enum from magnitude", ex);
return ExcitationVoltageOptions.ExcitationVoltageOption.Undefined;
}
}
///// <summary>
///// Attribute for specifying the numerical magnitude of the attached field's
///// "representation". Intended to be used with enumerations whose members represent
///// voltage magnitude options so that the enum item can have a corresponding numerical
///// value that can be extracted and used in calculations.
///// </summary>
//[AttributeUsage(AttributeTargets.Field)]
//public class VoltageMagnitudeAttribute: Attribute
//{
// /// <summary>
// /// returns voltage magnitude
// /// </summary>
// public double Value { get; }
// /// <summary>
// /// constructs a <see cref="Test.Module.Channel.Sensor.VoltageMagnitudeAttribute" />
// /// with a given value
// /// </summary>
// /// <param name="value"></param>
// public VoltageMagnitudeAttribute(double value) { Value = value; }
//}
///// <summary>
///// Object for manipulating voltage option enumeration-attached
///// <see cref="double"/> magnitude values.
///// </summary>
//public class VoltageMagnitudeAttributeCoder
// : AttributeCoder<ExcitationVoltageOptions.ExcitationVoltageOption, VoltageMagnitudeAttribute, double>
//{
// /// <summary>
// /// Initializes a <see cref="Test.Module.Channel.Sensor.VoltageMagnitudeAttributeCoder"/> object.
// /// </summary>
// public VoltageMagnitudeAttributeCoder()
// : base(attribute => attribute.Value, null)
// {
// }
//}
}
}
}
}
}

View File

@@ -0,0 +1,31 @@
/*
Test.Module.Channel.cs
Copyright © 2008
Diversified Technical Systems, Inc.
All Rights Reserved
*/
namespace DTS.DAS.Concepts
{
// *** see Test.cs ***
public partial class Test
{
/// <summary>
/// A container for DTS generic module concepts.
/// </summary>
public sealed partial class Module
{
/// <summary>
/// A container for DTS generic channel concepts.
/// </summary>
public sealed partial class Channel
{
/// <summary>
/// Class is not intended for instantiation.
/// </summary>
private Channel( ) { }
}
}
}
}

View File

@@ -0,0 +1,24 @@
/*
* DAS.Channel.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
using DTS.Utilities;
namespace DTS.DAS.Concepts.DAS
{
/// <summary>
/// Slice control app's internal abstract representation of a DAS channel.
/// </summary>
///
/// <typeparam name="DataType">
/// The "type" of the data contained by channels of this DAS.
/// </typeparam>
///
public abstract class Channel<DataType> : Exceptional
{
}
}

View File

@@ -0,0 +1,115 @@
/*
* IDownloadEnabled.cs
*
* Copyright © 2010
* Diversified Technical Systems, Inc.
* All Rights Reserved.
*/
using System;
using DTS.Utilities;
/// <DevelopmentNote Developer="Paul Hrissikopoulos">
/// It may make sense to refactor this namespace to be DTS.DAS.Concepts.Tsr and rename the TSR-specific
/// event to "Event" so that the fully qualified name of the class is "DTS.DAS.Concepts.Tsr.Event", but
/// then maybe keep the IDownloadEnabled and other generic interfaces outside of the "Tsr"-specific
/// namespace...? No, should probably stay with Event, since it has an "Event" type referenced in the
/// interface.
/// </DevelopmentNote>
namespace DTS.DAS.Concepts
{ ///
/// <summary>
/// Representation of data and metadata associated with a TSR event.
/// </summary>
///
public abstract class TsrEvent : Exceptional, ICloneable
{
/// <summary>
/// The 1-based <see cref="UInt64"/> identifier for this event.
/// </summary>
public virtual UInt64 EventId { get; protected set; }
/// <summary>
/// The <see cref="System.DateTime"/> containing the date and time of this event.
/// </summary>
public virtual DateTime TimeStamp { get; protected set; }
/// <summary>
/// The <see cref="string"/> serial number of the hardware that captured this event.
/// </summary>
public virtual string SerialNumber { get; protected set; }
/// <summary>
/// The <see cref="string"/> alternate serial number of the hardware that captured the event.
/// </summary>
public virtual string AlternateSerialNumber { get; protected set; }
/// <summary>
/// The <see cref="double"/> duration in seconds of this event.
/// </summary>
public virtual double DurationSeconds { get; protected set; }
/// <summary>
/// The <see cref="double"/> maximum sample rate for this event.
/// </summary>
public virtual double MaxSampleRate { get; protected set; } // note this is the "highest" sample rate
/// <summary>
/// The <see cref="float"/> temperature (in C).
/// </summary>
public virtual float TemperatureC { get; protected set; }
/// <summary>
/// The <see cref="double"/> number of pre-trigger seconds.
/// </summary>
public virtual double PreTriggerSeconds { get; protected set; }
///
/// <summary>
/// Generate a shallow copy of this object.
/// </summary>
/// <returns>A shallow copy of this <see cref="object"/>.</returns>
///
public abstract object Clone();
}
///
/// <summary>
/// Representation of the ability to download from this object.
/// </summary>
///
public interface IDownloadEnabled
{ //
// TODO: Determine whether or not these things should be in here. Maybe the implementing
// object should just ask for them in the constructor and keep them private? I don't think
// these are universally applicable to something "download enabled"... are they?
//
//public uint MaximumStoredEventSizeSeconds { get; }
//public ushort DownloadIncrementSamples { get; }
//public string[] ChannelDescription { get; }
//public int TimeOffsetMilliseconds { get; }
/// <summary>
/// A list of download <see cref="DTS.DAS.Concepts.TsrEvent"/>s available for download.
/// </summary>
TsrEvent[] EventList {get;}
///
/// <summary>
/// Get the event data for the specified sample.
/// </summary>
/// <param name="Event">The <see cref="DTS.DAS.Concepts.TsrEvent"/> to have it's data extracted.</param>
/// <param name="FirstSample">The <see cref="UInt64"/> index of the first sample to be downloaded.</param>
/// <param name="LastSample">The <see cref="UInt64"/> index of the last sample to be downloaded.</param>
/// <returns>An array of <see cref="double"/> data arrays for each channel.</returns>
///
double [][] GetEventData( TsrEvent Event, UInt64 FirstSample, UInt64 LastSample ); // Any reason to do data as an out parameter rather than a return value?
// Have a subclassed channel class that has a data array, just so that 2-d array isn't so ambiguous?
/// <summary>
/// Determine whether or not the data on this download-enabled entity has been downloaded.
/// </summary>
bool DataHasBeenDownloaded { get; }
}
}

View File

@@ -0,0 +1,52 @@
/*
* DAS.Channel.Data.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
using System.Collections.Generic;
using DTS.Utilities;
namespace DTS.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Representation of a list of channel data.
/// </summary>
public abstract class Data<DatumType> : ExceptionalList<DatumType>
{
/// <summary>
/// Initialize an instance of the DTS.DAS.Concepts.DAS.Channel.Data class.
/// </summary>
protected Data( )
{
}
/// <summary>
/// Initialize an instance of the DTS.DAS.Concepts.DAS.Channel.Data class.
/// </summary>
///
/// <param name="capacity">
/// The number of elements that the list can initially store.
/// </param>
///
protected Data( int capacity )
: base( capacity )
{
}
/// <summary>
/// Initialize an instance of the DTS.DAS.Concepts.DAS.Channel.Data class.
/// </summary>
///
/// <param name="collection">
/// The collection whose elements are copied to the new list.
/// </param>
///
protected Data( IEnumerable<DatumType> collection )
: base( collection )
{
}
}
}

View File

@@ -0,0 +1,52 @@
/*
* DTS.Common.DAS.Concepts.DAS.Channel.Data.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
using System.Collections.Generic;
using DTS.Common.Utilities;
namespace DTS.Common.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Representation of a list of channel data.
/// </summary>
public abstract class Data<TDatumType> : ExceptionalList<TDatumType>
{
/// <summary>
/// Initialize an instance of the DTS.Common.DAS.Concepts.DAS.Channel.Data class.
/// </summary>
protected Data()
{
}
/// <summary>
/// Initialize an instance of the DTS.Common.DAS.Concepts.DAS.Channel.Data class.
/// </summary>
///
/// <param name="capacity">
/// The number of elements that the list can initially store.
/// </param>
///
protected Data(int capacity)
: base(capacity)
{
}
/// <summary>
/// Initialize an instance of the DTS.Common.DAS.Concepts.DAS.Channel.Data class.
/// </summary>
///
/// <param name="collection">
/// The collection whose elements are copied to the new list.
/// </param>
///
protected Data(IEnumerable<TDatumType> collection)
: base(collection)
{
}
}
}

View File

@@ -0,0 +1,113 @@
/*
Test.Module.RecordingMode.cs
Copyright © 2008
Diversified Technical Systems, Inc.
All Rights Reserved
*/
using System;
using System.ComponentModel;
namespace DTS.DAS.Concepts
{
// *** see Test.cs ***
public partial class Test
{
/// <summary>
/// A container for DTS generic module concepts.
/// </summary>
public sealed partial class Module
{
/// <summary>
/// All available recording mode options.
/// </summary>
public enum RecordingMode
{
/// <summary>
/// invalid mode, this can't be used
/// </summary>
[Description("Invalid arm mode")]
InvalidArmMode = 0,
/// <summary>
/// circular buffer mode (constant recording, trigger)
/// </summary>
[Description("Circular buffer")]
CircularBuffer = 1,
/// <summary>
/// recorder mode (start, trigger)
/// </summary>
[Description("Recorder mode")]
RecorderMode = 2,
/// <summary>
/// contant recording, trigger, rearm after data collected
/// </summary>
[Description("Circular buffer Multiple-Events")]
AutoCircularBufferMode = 4,
/// <summary>
/// recorder mode (start, trigger) rearm after data collected
/// </summary>
[Description("Recorder mode Multiple-Events")]
AutoRecorderMode = 5,
/// <summary>
/// ???
/// </summary>
[Description("Immediate mode")]
ImmediateMode = 0x06,
/// <summary>
/// ???
/// </summary>
[Description("High Power mode")]
HighPowerRecorderMode = 0x07,
/// <summary>
/// ???
/// </summary>
[Description("Low Power mode")]
LowPowerRecorderMode = 0x08,
/// <summary>
/// ???
/// </summary>
[Description("Continuous mode")]
ContinuousRecorderMode = 0x09,
/// <summary>
/// ???
/// </summary>
[Description("Hybrid mode")]
HybridRecorderMode = 0x0A,
/// <summary>
/// ???
/// </summary>
[Description("Hybrid mode Multiple-Events")]
MultiHybridRecorderMode = 0x0B
}
/// <summary>
/// Convert a string representation of a recording mode enumeration into its corresponding
/// enumeration value.
/// </summary>
///
/// <param name="recordingMode">
/// The <see cref="string"/> representation to be converted.
/// </param>
///
/// <returns>
/// The <see cref="DTS.DAS.Concepts.Test.Module.RecordingMode"/> value corresponding to the
/// specified string, if any. If not, an exception will be thrown.
/// </returns>
///
public static RecordingMode GetRecordingModeFromString( string recordingMode )
{
try
{
return ( RecordingMode )Enum.Parse( typeof( RecordingMode ), recordingMode );
}
catch ( Exception ex )
{
throw new Exception( "encountered problem getting recording mode from string representation " + ( null != recordingMode ? "\"" + recordingMode + "\"" : "<<NULL>>" ), ex );
}
}
}
}
}

View File

@@ -0,0 +1,25 @@
/*
* DTS.Common.DAS.Concepts.DAS.Channel.IEngineeringUnitAware.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.Common.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of the concept of engineering unit awareness.
/// </summary>
public interface IEngineeringUnitAware
{
/// <summary>
/// Get/set this object's engineering unit description <see cref="string"/>.
/// </summary>
string EngineeringUnits
{
get;
set;
}
}
}

View File

@@ -0,0 +1,27 @@
/*
* ICalibratable.cs
*
* Copyright © 2010
* Diversified Technical Systems, Inc.
* All Rights Reserved.
*/
namespace DTS.DAS.Concepts
{ ///
/// <summary>
/// Representation of the ability to calibrate.
/// </summary>
///
public interface ICalibratable
{ //
// Properties required for rudimentary calibration.
//
string SerialNumber { get; set; }
double Sensitivity { get; set; }
double BatteryVolts { get; set; }
double VddVolts { get; set; }
double SignalConditioningVolts { get; set; }
// access for generic attributes.
}
}

View File

@@ -0,0 +1,57 @@
/*
* DAS.Channel.IShuntAware.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of the concept of shunt-check awareness.
/// </summary>
public interface IShuntAware
{
/// <summary>
/// Get/set this object's <see cref="double"/> measured shunt deflection value.
/// </summary>
double MeasuredShuntDeflectionMv
{
get;
set;
}
/// <summary>
/// Get/set this object's <see cref="double"/> target shunt deflection value.
/// </summary>
double TargetShuntDeflectionMv
{
get;
set;
}
}
/// <summary>
/// Definition of the concept of calsignal-check awareness.
/// </summary>
public interface ICalSignalAware
{
/// <summary>
/// Get/set this object's <see cref="double"/> measured shunt deflection value.
/// </summary>
double MeasuredCalSignalMv
{
get;
set;
}
/// <summary>
/// Get/set this object's <see cref="double"/> target shunt deflection value.
/// </summary>
double TargetCalSignalMv
{
get;
set;
}
}
}

View File

@@ -0,0 +1,41 @@
/*
* DAS.Channel.ILevelTriggerable.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
using System;
namespace DTS.DAS.Concepts.DAS.Channel
{
///
/// <summary>
/// Definition of the concept of level triggerability.
/// </summary>
///
public interface ILevelTriggerable
{
/// <summary>
/// Get/set the "trigger below" threshold. Set to "null" to deactivate.
/// </summary>
double? TriggerBelowThresholdEu { get; set; }
/// <summary>
/// Get/set the "trigger above" threshold. Set to "null" to deactivate.
/// </summary>
double? TriggerAboveThresholdEu { get; set; }
LevelTriggerTypes LevelTriggerType { get; set; }
}
[Flags]
public enum LevelTriggerTypes
{
NONE = 0x00,
OutsideWindow = 0x01,
InsideWindow = 0x02,
LessThan = 0x04,
GreaterThan = 0x08
}
}

View File

@@ -0,0 +1,47 @@
/*
Test.Module.Channel.Sensor.cs
Copyright © 2008
Diversified Technical Systems, Inc.
All Rights Reserved
*/
using System.ComponentModel;
namespace DTS.DAS.Concepts
{
// *** see Test.cs ***
public partial class Test
{
/// <summary>
/// A container for DTS generic module concepts.
/// </summary>
public sealed partial class Module
{
// *** see Test.Module.Channel.cs ***
public partial class Channel
{
/// <summary>
/// Container for DTS generic sensor concepts.
/// </summary>
sealed partial class Sensor
{
/// <summary>
/// Not intended for instantiation.
/// </summary>
private Sensor( ) { }
/// <summary>
/// IEPE Coupling modes
/// </summary>
public enum CouplingModes
{
[Description("AC")]
AC,
[Description("AC/DC")]
DC
}
}
}
}
}
}

View File

@@ -0,0 +1,25 @@
/*
* DAS.Channel.IIsoCodeAware.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of the concept of ISO code awareness.
/// </summary>
public interface IIsoCodeAware
{
/// <summary>
/// Get/set this object's IsoCode <see cref="string"/>.
/// </summary>
string IsoCode
{
get;
set;
}
}
}

View File

@@ -0,0 +1,65 @@
/*
* DTS.Channel.IDecimatable
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.Common.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of what it means for a DAS channel to be "decimatable".
/// </summary>
///
/// <typeparam name="T">
/// The type of data handled by this DAS channel.
/// </typeparam>
///
public interface IDecimatable<out T>
{
/// <summary>
/// The number of points to be squeezed into a single index point.
/// </summary>
uint PointsPerPoint
{
get;
set;
}
/// <summary>
/// Get/set the decimation method to be applied.
/// </summary>
DecimationMethod DecimationType
{
get;
set;
}
/// <summary>
/// Generate a decimated array using the current <see cref="DTS.Common.DAS.Concepts.DAS.Channel.DecimationMethod"/>.
/// </summary>
///
/// <returns>
/// A decimated array of type "T".
/// </returns>
///
T[] ToDecimatedArray();
/// <summary>
/// Get the value at the specified post-decimation index.
/// </summary>
/// <param name="i"></param>
/// <returns></returns>
///
/// <remarks>
/// Note that implementing this interface implies that the indexing operator should return values from
/// the set decimated according to the PointsPerPoint and Method properties.
/// </remarks>
///
T this[long i]
{
get;
}
}
}

View File

@@ -0,0 +1,594 @@
using DTS.Common.Utilities;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using static DTS.Common.Enums.DASFactory.DFConstantsAndEnums;
namespace DTS.Common.DAS.Concepts
{
public partial class Test
{
/// <summary>
/// A container for DTS generic module concepts.
/// </summary>
public sealed partial class Module
{
public class TiltAxis
{
public int AxisNumber { get; set; }
public double CurrentTilt { get; set; }
public string Label { get; set; }
public int Inversion { get; set; } = 1;
public bool IsIgnored { get; set; } = false;
public double MountedOffset { get; set; } = 0.0;
public double TargetOffset { get; set; } = 0.0;
}
public class TiltAxesHelper
{
bool UseForTiltCalculation { get; set; } = true;
public Dictionary<int, TiltAxis> AxisConfigurations { get; set; }
= new Dictionary<int, TiltAxis>();
public TiltAxis AxisOne { get; set; }
public TiltAxis AxisTwo { get; set; }
public double LevelTolerance { get; set; } = 0.5;
public TiltAxesHelper()
{
AxisConfigurations = new Dictionary<int, TiltAxis>
{
{ 1, new TiltAxis() },
{ 2, new TiltAxis() },
{ 3, new TiltAxis() }
};
}
/// <summary>
/// Constructor to build Helper from FW Attributes.
/// </summary>
public TiltAxesHelper(
string TiltAxes,
double MountOffsetAxisOne,
double MountOffsetAxisTwo,
double TargetAxisOne,
double TargetAxisTwo,
double LevelTolerance,
int AxisIgnored,
bool UseForTiltCalculation)
: this()
{
this.LevelTolerance = LevelTolerance;
// Parse the TiltAxes string from e.g. "IXIYIZ"
for (int i = 0; i < 3; i++)
{
// X, Y, or Z
AxisConfigurations[i].Label = TiltAxes[i * 2].ToString();
// N = negative = -1 otherwise positive
AxisConfigurations[i].Inversion =
TiltAxes[i * 2 + 1] == 'N' ? -1 : 1;
}
if (AxisIgnored < 3)
AxisConfigurations[AxisIgnored].IsIgnored = true;
// References to used axes depending on ignored axis
if (AxisIgnored == 1)
{
AxisOne = AxisConfigurations[2];
AxisTwo = AxisConfigurations[3];
}
else if (AxisIgnored == 2)
{
AxisOne = AxisConfigurations[1];
AxisTwo = AxisConfigurations[3];
}
else
{
AxisOne = AxisConfigurations[1];
AxisOne = AxisConfigurations[2];
}
AxisOne.MountedOffset = MountOffsetAxisOne;
AxisTwo.MountedOffset = MountOffsetAxisTwo;
AxisOne.TargetOffset = TargetAxisOne;
AxisOne.TargetOffset = TargetAxisTwo;
}
public string AxesToString()
{
string s = "";
foreach (var a in AxisConfigurations)
s = s + (a.Value.Label) + (a.Value.Inversion == -1 ? "N" : "P");
return s;
}
}
public enum TiltAxesSimple
{
XYZ = 0,
XZY = 1,
YXZ = 2,
YZX = 3,
ZXY = 4,
ZYX = 5,
}
public static TiltAxesSimple SimplifyTiltAxes(TiltAxes axes)
{
return (TiltAxesSimple)Enum.Parse(typeof(TiltAxesSimple), axes.ToString().Replace("I", ""));
}
public enum TiltAxesPolarity
{
PPP = 0,
PPN = 1,
PNP = 2,
PNN = 3,
NPP = 4,
NPN = 5,
NNP = 6,
NNN = 7
}
/// <summary>
/// Convert a string representation of a recording mode enumeration into its corresponding
/// enumeration value.
/// </summary>
///
/// <param name="tiltAxes">
/// The <see cref="string"/> representation to be converted.
/// </param>
///
/// <returns>
/// The <see cref="Test.Module.TiltAxes"/> value corresponding to the
/// specified string, if any. If not, an exception will be thrown.
/// </returns>
///
public static TiltAxes GetTiltAxesFromString(string tiltAxes)
{
try
{
return (TiltAxes)Enum.Parse(typeof(TiltAxes), tiltAxes);
}
catch (Exception ex)
{
throw new Exception("encountered problem getting tilt axis from string representation " + (null != tiltAxes ? "\"" + tiltAxes + "\"" : "<<NULL>>"), ex);
}
}
public static int[] GetPolaritiesFromTiltAxes(TiltAxes ta)
{
var rv = new List<int>();
var rvBool = GetBoolPolaritiesFromTiltAxes(ta);
foreach (var b in rvBool)
{
rv.Add(b ? -1 : 1);
}
return rv.ToArray();
}
public static bool[] GetBoolPolaritiesFromTiltAxes(TiltAxes tiltAxes)
{
var rv = new bool[3];
var ax = 0;
var tiltAxesString = tiltAxes.ToString();
// Parse enum for I's, invert corresponding array member;
for (var i = 0; i < tiltAxesString.Length; i++)
{
if (tiltAxesString[i] == 'I')
{
rv[ax] = true;
}
else
{
ax++;
}
}
return rv;
}
public enum TiltSensorCalAttributes
{
TILTSENSOR_CAL_1_GainAxis1 = 0,
TILTSENSOR_CAL_2_ZeroAxis1 = 1,
TILTSENSOR_CAL_3_ZeroDomAxis2PosAxis1 = 2,
TILTSENSOR_CAL_4_ZeroDomAxis2NegAxis1 = 3,
TILTSENSOR_CAL_5_ZeroDomAxis3PosAxis1 = 4,
TILTSENSOR_CAL_6_ZeroDomAxis3NegAxis1 = 5,
TILTSENSOR_CAL_7_GainAxis2 = 6,
TILTSENSOR_CAL_8_ZeroAxis2 = 7,
TILTSENSOR_CAL_9_ZeroDomAxis1PosAxis2 = 8,
TILTSENSOR_CAL_10_ZeroDomAxis1NegAxis2 = 9,
TILTSENSOR_CAL_11_ZeroDomAxis3PosAxis2 = 10,
TILTSENSOR_CAL_12_ZeroDomAxis3NegAxis2 = 11,
TILTSENSOR_CAL_13_GainAxis3 = 12,
TILTSENSOR_CAL_14_ZeroAxis3 = 13,
TILTSENSOR_CAL_15_ZeroDomAxis1PosAxis3 = 14,
TILTSENSOR_CAL_16_ZeroDomAxis1NegAxis3 = 15,
TILTSENSOR_CAL_17_ZeroDomAxis2PosAxis3 = 16,
TILTSENSOR_CAL_18_ZeroDomAxis2NegAxis3 = 17,
}
/// <summary>
/// 3 digits of precision by default
/// http://manuscript.dts.local/f/cases/34373/Tilt-Sensor-4-0-reported-value-significant-figure-in-DataPRO
/// </summary>
private const int SIGNIFICANT_DIGITS = 1000;
public static double[] GetTiltDegreesEU(short[] tiltSensorADC, double[] tiltSensorCals)
{
return GetTiltDegreesEU(tiltSensorADC, tiltSensorCals, TiltAxes.IXYZ, 3, new float[2] { 0F, 0F });
}
public static double[] GetTiltDegreesEU(short[] tiltSensorADC, double[] tiltSensorCals, TiltAxes axes, int ignoredAxis, float[] mountOffsetAxis)
{
var mountOffsetAxisOne = mountOffsetAxis[0];
var mountOffsetAxisTwo = mountOffsetAxis[1];
double tiltSensorAxisXDegreesPre = 0D;
double tiltSensorAxisYDegreesPre = 0D;
double tiltSensorAxisZDegreesPre = 0D;
if (ignoredAxis == 0) { ignoredAxis = 3; }
int dominantAxis = GetDominantTiltAxis(tiltSensorADC);
double[] gains = GetTiltGains(tiltSensorCals);
double[] zeroData = GetTiltZeroData(tiltSensorADC, tiltSensorCals, dominantAxis);
var xFactor = 1;
var yFactor = 1;
var zFactor = 1;
switch (axes)
{
case TiltAxes.IXIYIZ:
case TiltAxes.IXIYZ:
case TiltAxes.IXIZIY:
case TiltAxes.IXIZY:
case TiltAxes.IXYIZ:
case TiltAxes.IXYZ:
case TiltAxes.IXZIY:
case TiltAxes.IXZY:
case TiltAxes.IYIXIZ:
case TiltAxes.IYIXZ:
case TiltAxes.IYIZIX:
case TiltAxes.IYZIX:
case TiltAxes.IZIXIY:
case TiltAxes.IZIXY:
case TiltAxes.IZIYIX:
case TiltAxes.IZYIX:
case TiltAxes.YIXIZ:
case TiltAxes.YIXZ:
case TiltAxes.YIZIX:
case TiltAxes.YZIX:
case TiltAxes.ZIXIY:
case TiltAxes.ZIXY:
case TiltAxes.ZIYIX:
case TiltAxes.ZYIX:
xFactor = -1;
break;
}
switch (axes)
{
case TiltAxes.IXIYIZ:
case TiltAxes.IXIYZ:
case TiltAxes.IXIZIY:
case TiltAxes.IXZIY:
case TiltAxes.IYIXIZ:
case TiltAxes.IYIXZ:
case TiltAxes.IYIZIX:
case TiltAxes.IYIZX:
case TiltAxes.IYXIZ:
case TiltAxes.IYXZ:
case TiltAxes.IYZIX:
case TiltAxes.IYZX:
case TiltAxes.IZIXIY:
case TiltAxes.IZIYIX:
case TiltAxes.IZIYX:
case TiltAxes.IZXIY:
case TiltAxes.XIYIZ:
case TiltAxes.XIYZ:
case TiltAxes.XIZIY:
case TiltAxes.XZIY:
case TiltAxes.ZIXIY:
case TiltAxes.ZIYIX:
case TiltAxes.ZIYX:
case TiltAxes.ZXIY:
yFactor = -1;
break;
}
switch (axes)
{
case TiltAxes.IXIYIZ:
case TiltAxes.IXIZIY:
case TiltAxes.IXIZY:
case TiltAxes.IXYIZ:
case TiltAxes.IYIXIZ:
case TiltAxes.IYIZIX:
case TiltAxes.IYIZX:
case TiltAxes.IYXIZ:
case TiltAxes.IZIXIY:
case TiltAxes.IZIXY:
case TiltAxes.IZIYIX:
case TiltAxes.IZIYX:
case TiltAxes.IZXIY:
case TiltAxes.IZXY:
case TiltAxes.IZYIX:
case TiltAxes.IZYX:
case TiltAxes.XIYIZ:
case TiltAxes.XIZIY:
case TiltAxes.XIZY:
case TiltAxes.XYIZ:
case TiltAxes.YIXIZ:
case TiltAxes.YIZIX:
case TiltAxes.YIZX:
case TiltAxes.YXIZ:
zFactor = -1;
break;
}
var simplifiedAxes = SimplifyTiltAxes(axes);
switch (simplifiedAxes)
{
case TiltAxesSimple.XYZ:
double Sx = xFactor * ((tiltSensorADC[0] - zeroData[0]) / gains[0]);
double Sy = yFactor * ((tiltSensorADC[1] - zeroData[1]) / gains[1]);
double Sz = zFactor * ((tiltSensorADC[2] - zeroData[2]) / gains[2]);
double SG = Math.Sqrt(Math.Pow(Sx, 2) + Math.Pow(Sy, 2) + Math.Pow(Sz, 2));
switch (ignoredAxis)
{
case 1:
tiltSensorAxisXDegreesPre = double.NaN;
tiltSensorAxisYDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sy, SG) + mountOffsetAxisTwo) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
tiltSensorAxisZDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sz, SG) + mountOffsetAxisOne) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
break;
case 2:
tiltSensorAxisXDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sx, SG) + mountOffsetAxisOne) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
tiltSensorAxisYDegreesPre = double.NaN;
tiltSensorAxisZDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sz, SG) + mountOffsetAxisOne) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
break;
case 3:
tiltSensorAxisXDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sx, SG) + mountOffsetAxisOne) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
tiltSensorAxisYDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sy, SG) + mountOffsetAxisTwo) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
tiltSensorAxisZDegreesPre = double.NaN;
break;
}
break;
case TiltAxesSimple.XZY:
Sx = xFactor * ((tiltSensorADC[0] - zeroData[0]) / gains[0]);
Sz = zFactor * ((tiltSensorADC[1] - zeroData[1]) / gains[1]);
Sy = yFactor * ((tiltSensorADC[2] - zeroData[2]) / gains[2]);
SG = Math.Sqrt(Math.Pow(Sx, 2) + Math.Pow(Sy, 2) + Math.Pow(Sz, 2));
switch (ignoredAxis)
{
case 1:
tiltSensorAxisXDegreesPre = double.NaN;
tiltSensorAxisZDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sz, SG) + mountOffsetAxisOne) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
tiltSensorAxisYDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sy, SG) + mountOffsetAxisTwo) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
break;
case 2:
tiltSensorAxisXDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sx, SG) + mountOffsetAxisOne) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
tiltSensorAxisZDegreesPre = double.NaN;
tiltSensorAxisYDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sy, SG) + mountOffsetAxisTwo) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
break;
case 3:
tiltSensorAxisXDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sx, SG) + mountOffsetAxisOne) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
tiltSensorAxisZDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sz, SG) + mountOffsetAxisTwo) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
tiltSensorAxisYDegreesPre = double.NaN;
break;
}
break;
case TiltAxesSimple.YXZ:
Sy = yFactor * ((tiltSensorADC[0] - zeroData[0]) / gains[0]);
Sx = xFactor * ((tiltSensorADC[1] - zeroData[1]) / gains[1]);
Sz = zFactor * ((tiltSensorADC[2] - zeroData[2]) / gains[2]);
SG = Math.Sqrt(Math.Pow(Sx, 2) + Math.Pow(Sy, 2) + Math.Pow(Sz, 2));
switch (ignoredAxis)
{
case 1:
tiltSensorAxisYDegreesPre = double.NaN;
tiltSensorAxisXDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sx, SG) + mountOffsetAxisOne) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
tiltSensorAxisZDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sz, SG) + mountOffsetAxisTwo) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
break;
case 2:
tiltSensorAxisYDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sy, SG) + mountOffsetAxisOne) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
tiltSensorAxisXDegreesPre = double.NaN;
tiltSensorAxisZDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sz, SG) + mountOffsetAxisTwo) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
break;
case 3:
tiltSensorAxisYDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sy, SG) + mountOffsetAxisOne) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
tiltSensorAxisXDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sx, SG) + mountOffsetAxisTwo) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
tiltSensorAxisZDegreesPre = double.NaN;
break;
}
break;
case TiltAxesSimple.YZX:
Sy = yFactor * ((tiltSensorADC[0] - zeroData[0]) / gains[0]);
Sz = zFactor * ((tiltSensorADC[1] - zeroData[1]) / gains[1]);
Sx = xFactor * ((tiltSensorADC[2] - zeroData[2]) / gains[2]);
SG = Math.Sqrt(Math.Pow(Sx, 2) + Math.Pow(Sy, 2) + Math.Pow(Sz, 2));
switch (ignoredAxis)
{
case 1:
tiltSensorAxisYDegreesPre = double.NaN;
tiltSensorAxisZDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sz, SG) + mountOffsetAxisOne) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
tiltSensorAxisXDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sx, SG) + mountOffsetAxisTwo) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
break;
case 2:
tiltSensorAxisYDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sy, SG) + mountOffsetAxisOne) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
tiltSensorAxisZDegreesPre = double.NaN;
tiltSensorAxisXDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sx, SG) + mountOffsetAxisTwo) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
break;
case 3:
tiltSensorAxisYDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sy, SG) + mountOffsetAxisOne) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
tiltSensorAxisZDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sz, SG) + mountOffsetAxisTwo) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
tiltSensorAxisXDegreesPre = double.NaN;
break;
}
break;
case TiltAxesSimple.ZXY:
Sz = zFactor * ((tiltSensorADC[0] - zeroData[0]) / gains[0]);
Sx = xFactor * ((tiltSensorADC[1] - zeroData[1]) / gains[1]);
Sy = yFactor * ((tiltSensorADC[2] - zeroData[2]) / gains[2]);
SG = Math.Sqrt(Math.Pow(Sx, 2) + Math.Pow(Sy, 2) + Math.Pow(Sz, 2));
switch (ignoredAxis)
{
case 1:
tiltSensorAxisZDegreesPre = double.NaN;
tiltSensorAxisXDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sx, SG) + mountOffsetAxisOne) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
tiltSensorAxisYDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sy, SG) + mountOffsetAxisTwo) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
break;
case 2:
tiltSensorAxisZDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sz, SG) + mountOffsetAxisOne) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
tiltSensorAxisXDegreesPre = double.NaN;
tiltSensorAxisYDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sy, SG) + mountOffsetAxisTwo) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
break;
case 3:
tiltSensorAxisZDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sz, SG) + mountOffsetAxisOne) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
tiltSensorAxisXDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sx, SG) + mountOffsetAxisTwo) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
tiltSensorAxisYDegreesPre = double.NaN;
break;
}
break;
case TiltAxesSimple.ZYX:
Sz = zFactor * ((tiltSensorADC[0] - zeroData[0]) / gains[0]);
Sy = yFactor * ((tiltSensorADC[1] - zeroData[1]) / gains[1]);
Sx = xFactor * ((tiltSensorADC[2] - zeroData[2]) / gains[2]);
SG = Math.Sqrt(Math.Pow(Sx, 2) + Math.Pow(Sy, 2) + Math.Pow(Sz, 2));
switch (ignoredAxis)
{
case 1:
tiltSensorAxisZDegreesPre = double.NaN;
tiltSensorAxisYDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sy, SG) + mountOffsetAxisOne) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
tiltSensorAxisXDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sx, SG) + mountOffsetAxisTwo) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
break;
case 2:
tiltSensorAxisZDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sz, SG) + mountOffsetAxisOne) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
tiltSensorAxisYDegreesPre = double.NaN;
tiltSensorAxisXDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sx, SG) + mountOffsetAxisTwo) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
break;
case 3:
tiltSensorAxisZDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sz, SG) + mountOffsetAxisOne) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
tiltSensorAxisYDegreesPre = Math.Round((DegreesFromADC.GetDegrees(Sy, SG) + mountOffsetAxisTwo) * SIGNIFICANT_DIGITS) / SIGNIFICANT_DIGITS; //1 decimal place
tiltSensorAxisXDegreesPre = double.NaN;
break;
}
break;
}
return new double[] { tiltSensorAxisXDegreesPre, tiltSensorAxisYDegreesPre, tiltSensorAxisZDegreesPre };
}
public static double[] GetTiltZeroData(short[] tiltSensorADC, double[] tiltSensorCals, int dominantAxis)
{
double[] zeroData = new double[]
{
tiltSensorCals[(int)TiltSensorCalAttributes.TILTSENSOR_CAL_2_ZeroAxis1],
tiltSensorCals[(int)TiltSensorCalAttributes.TILTSENSOR_CAL_8_ZeroAxis2],
tiltSensorCals[(int)TiltSensorCalAttributes.TILTSENSOR_CAL_14_ZeroAxis3]
};
bool positivePolarity = (tiltSensorADC[dominantAxis] > 0);
switch (dominantAxis)
{
case 0:
zeroData[1] = (positivePolarity) ? tiltSensorCals[(int)TiltSensorCalAttributes.TILTSENSOR_CAL_9_ZeroDomAxis1PosAxis2] : tiltSensorCals[(int)TiltSensorCalAttributes.TILTSENSOR_CAL_10_ZeroDomAxis1NegAxis2];
zeroData[2] = (positivePolarity) ? tiltSensorCals[(int)TiltSensorCalAttributes.TILTSENSOR_CAL_15_ZeroDomAxis1PosAxis3] : tiltSensorCals[(int)TiltSensorCalAttributes.TILTSENSOR_CAL_16_ZeroDomAxis1NegAxis3];
break;
case 1:
zeroData[0] = (positivePolarity) ? tiltSensorCals[(int)TiltSensorCalAttributes.TILTSENSOR_CAL_3_ZeroDomAxis2PosAxis1] : tiltSensorCals[(int)TiltSensorCalAttributes.TILTSENSOR_CAL_4_ZeroDomAxis2NegAxis1];
zeroData[2] = (positivePolarity) ? tiltSensorCals[(int)TiltSensorCalAttributes.TILTSENSOR_CAL_17_ZeroDomAxis2PosAxis3] : tiltSensorCals[(int)TiltSensorCalAttributes.TILTSENSOR_CAL_18_ZeroDomAxis2NegAxis3];
break;
case 2:
zeroData[0] = (positivePolarity) ? tiltSensorCals[(int)TiltSensorCalAttributes.TILTSENSOR_CAL_5_ZeroDomAxis3PosAxis1] : tiltSensorCals[(int)TiltSensorCalAttributes.TILTSENSOR_CAL_6_ZeroDomAxis3NegAxis1];
zeroData[1] = (positivePolarity) ? tiltSensorCals[(int)TiltSensorCalAttributes.TILTSENSOR_CAL_11_ZeroDomAxis3PosAxis2] : tiltSensorCals[(int)TiltSensorCalAttributes.TILTSENSOR_CAL_12_ZeroDomAxis3NegAxis2];
break;
}
return zeroData;
}
public static int GetDominantTiltAxis(short[] tiltSensorADC)
{
return (tiltSensorADC.Max() < Math.Abs(tiltSensorADC.Min())) ? Array.IndexOf(tiltSensorADC, tiltSensorADC.Min()) : Array.IndexOf(tiltSensorADC, tiltSensorADC.Max());
}
public static double[] GetTiltGains(double[] tiltSensorCals)
{
double[] gains = new double[3];
gains[0] = tiltSensorCals[(int)TiltSensorCalAttributes.TILTSENSOR_CAL_1_GainAxis1] == 0D ? 1D : tiltSensorCals[(int)TiltSensorCalAttributes.TILTSENSOR_CAL_1_GainAxis1];
gains[1] = tiltSensorCals[(int)TiltSensorCalAttributes.TILTSENSOR_CAL_7_GainAxis2] == 0D ? 1D : tiltSensorCals[(int)TiltSensorCalAttributes.TILTSENSOR_CAL_7_GainAxis2];
gains[2] = tiltSensorCals[(int)TiltSensorCalAttributes.TILTSENSOR_CAL_13_GainAxis3] == 0D ? 1D : tiltSensorCals[(int)TiltSensorCalAttributes.TILTSENSOR_CAL_13_GainAxis3];
return gains;
}
public enum AxisLabel
{
X = 0,
Y = 1,
Z = 2,
}
public static AxisLabel[] GetAxisLabelFromTiltAxes(TiltAxes tiltAxes)
{
var simplifiedTiltAxes = SimplifyTiltAxes(tiltAxes);
var axesLabelChars = simplifiedTiltAxes.ToString().ToCharArray();
var rv = new AxisLabel[axesLabelChars.Length];
for (int i = 0; i < rv.Length; i++)
{
rv[i] = (AxisLabel)Enum.Parse(typeof(AxisLabel), axesLabelChars[i].ToString());
}
return rv;
}
public static AxisLabel[] GetAxisLabelFromTiltAxes(string tiltAxes)
{
return GetAxisLabelFromTiltAxes(GetTiltAxesFromString(tiltAxes));
}
public static string ConvertBoolToInvertString(bool isInverted)
{
return isInverted ? "I" : "";
}
public static string GetOrientationLabelFromAxisInfo(string[] axisLabels, bool[] invertAxis)
{
var sb = new StringBuilder();
for (int i = 0; i < 3; i++)
{
sb.Append($"{ConvertBoolToInvertString(invertAxis[i])}{axisLabels[i]}");
}
return sb.ToString();
}
public static TiltAxes GetTiltAxesFromAxisInfo(string[] axisLabels, bool[] invertAxis)
{
return GetTiltAxesFromString(GetOrientationLabelFromAxisInfo(axisLabels, invertAxis));
}
public static float[] GetMountOffsetsOrTargetsFromAxisInfo(float[] perAxisValue, int axisToIgnore)
{
var rv = new float[2];
switch (axisToIgnore)
{
case 1:
rv[0] = perAxisValue[1];
rv[1] = perAxisValue[2];
break;
case 2:
rv[0] = perAxisValue[0];
rv[1] = perAxisValue[2];
break;
case 3:
rv[0] = perAxisValue[0];
rv[1] = perAxisValue[1];
break;
}
return rv;
}
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* IRealtimeable.cs
*
* Copyright © 2010
* Diversified Technical Systems, Inc.
* All Rights Reserved.
*/
using System;
namespace DTS.Common.DAS.Concepts
{ ///
/// <summary>
/// Representation of a real-time data sample.
/// </summary>
///
public class RealtimeSample
{
public double[] DataEU; // Note this indexes by channel.
public ulong SampleNumber;
}
///
/// <summary>
/// Representation of the ability to perform "real-time" data capture.
/// </summary>
///
public interface IRealtimeable
{
void StartRealtime(double sampleRate);
void StopRealtime();
RealtimeSample[] GetRealtimeSamples();
}
}

View File

@@ -0,0 +1,62 @@
/*
Test.Module.Channel.Sensor.ExcitationVoltage.cs
Copyright © 2008
Diversified Technical Systems, Inc.
All Rights Reserved
*/
using System.ComponentModel;
namespace DTS.Common.DAS.Concepts
{
// *** see Test.cs ***
public partial class Test
{
/// <summary>
/// A container for DTS generic module concepts.
/// </summary>
public sealed partial class Module
{
// *** see Test.Module.Channel.cs ***
public partial class Channel
{
//*** see DTS.Common.DAS.Concepts.Test.Module.Channel.Sensor.cs ***
public partial class Sensor
{
/// <summary>
/// All available Sensitivity Unit types.
/// </summary>
public enum SensUnits
{
/// <summary>
/// No Sensitivity Units (Polynomial Sensor)
/// </summary>
[Description("NONE")]
NONE = 0,
/// <summary>
/// Sensitivity expressed in mV with output at Capacity EU
/// </summary>
[Description("mV")]
mV = 1,
/// <summary>
/// Excitation proportional sensitivity expressed in mV/V with output at Capacity EU
/// </summary>
[Description("mV/V")]
mVperV = 2,
/// <summary>
/// Excitation proportional sensitivity expressed in mV/V/EU
/// </summary>
[Description("mV/V/EU")]
mVperVperEU = 3,
/// <summary>
/// Sensitivity expressed in mV/EU
/// </summary>
[Description("mV/EU")]
mVperEU = 4
}
}
}
}
}
}

View File

@@ -0,0 +1,146 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.21022</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{AE3987F7-C4C6-40FB-A353-1A2DADEF7A9A}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DTS.DAS.Concepts</RootNamespace>
<AssemblyName>DTS.DAS.Concepts</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<OldToolsVersion>3.5</OldToolsVersion>
<TargetFrameworkProfile />
<SccProjectName>
</SccProjectName>
<SccLocalPath>
</SccLocalPath>
<SccAuxPath>
</SccAuxPath>
<SccProvider>
</SccProvider>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>
</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="ArmStatus.cs" />
<Compile Include="AvailableArmModes.cs" />
<Compile Include="DAS\Channel\TimestampPartTypes.cs" />
<Compile Include="Interfaces\DAS\Channel\ICalSignalAware.cs" />
<Compile Include="DAS\Channel\LevelTriggerTypes.cs" />
<Compile Include="DAS\DecimationMethod.cs" />
<Compile Include="DAS\Channel\Channel.cs" />
<Compile Include="DAS\Channel\Data.cs" />
<Compile Include="Interfaces\DAS\Channel\ITimestampAware.cs" />
<Compile Include="Interfaces\DAS\Channel\IDecimatable.cs" />
<Compile Include="Interfaces\DAS\Channel\IEngineeringUnitAware.cs" />
<Compile Include="Interfaces\DAS\Channel\IInversionAware.cs" />
<Compile Include="Interfaces\DAS\Channel\IIsoCodeAware.cs" />
<Compile Include="Interfaces\DAS\Channel\ILevelTriggerable.cs" />
<Compile Include="Interfaces\DAS\Channel\ISerialNumberAware.cs" />
<Compile Include="Interfaces\DAS\Channel\IShuntAware.cs" />
<Compile Include="DAS\DAS.Id.cs" />
<Compile Include="Interfaces\DAS\Channel\IVoltageInsertAware.cs" />
<Compile Include="Interfaces\DAS\Channel\ILinearized.cs" />
<Compile Include="DataScaler.cs" />
<Compile Include="DataScaler.InvalidExcitationVoltageException.cs" />
<Compile Include="Interfaces\IArmable.cs" />
<Compile Include="Interfaces\ICalibratable.cs" />
<Compile Include="Interfaces\IDataCollectionEnabled.cs" />
<Compile Include="Interfaces\IDownloadEnabled.cs" />
<Compile Include="Interfaces\IGpioEnabled.cs" />
<Compile Include="Interfaces\ILargeDataAware.cs" />
<Compile Include="Interfaces\IRealtimeable.cs" />
<Compile Include="Interfaces\ITriggerable.cs" />
<Compile Include="Properties\AssemblyInfo.cs">
<CustomToolNamespace>DTS.Common.DAS.Concepts</CustomToolNamespace>
</Compile>
<Compile Include="ShuntModeType.cs" />
<Compile Include="Test\Module\Channel\Sensor\ExcitationVoltage.cs" />
<Compile Include="Test\Module\Channel\Sensor\SensorUnits.cs" />
<Compile Include="Test\Module\RecordingMode.cs" />
<Compile Include="Test\Module\TiltAxes.cs" />
<Compile Include="TsrEvent.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="LinearizationFormula.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DTS.Common.SettingsDB\DTS.Common.Settings.csproj">
<Project>{61017104-d8ee-41d1-b9ca-dad863ff78b2}</Project>
<Name>DTS.Common.Settings</Name>
</ProjectReference>
<ProjectReference Include="..\DTS.Common.Utilities\DTS.Common.Utilities.csproj">
<Project>{d6da1b74-c711-43c2-91b1-1908a8d04dbf}</Project>
<Name>DTS.Common.Utilities</Name>
</ProjectReference>
<ProjectReference Include="..\DTS.Common\DTS.Common.csproj">
<Project>{f7a0804f-61a4-40ae-83d0-f1137622b592}</Project>
<Name>DTS.Common</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="Design\DTS.Common.DAS.ConceptsClassDiagram.cd" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,14 @@
namespace DTS.Common.DAS.Concepts
{
/// <summary>
/// different possible armstatus
/// </summary>
public enum ArmStatus
{
Disarming,
Disarmed,
Arming,
Armed,
Recording, // Extra statuses (chuck's mail)
}
}

View File

@@ -0,0 +1,121 @@
/*
* IArmable.cs
*
* Copyright © 2010
* Diversified Technical Systems, Inc.
* All Rights Reserved.
*/
namespace DTS.Common.DAS.Concepts
{
///
/// <summary>
/// Formal description of the ability to "arm".
/// </summary>
///
public interface IArmable
{
void Arm();
void Disarm();
ArmStatus ArmStatus { get; }
AvailableArmModes ArmMode { get; }
}
}
//Like Rollin said, NGI will (for now) be orphaned. NASCAR is in for sure. TSR6DX is really TSRPRO, I think. RateTestTSR==BlastTestTSR and needs to be flattened. TSR==TSRBasic. The missing one in that list is HEADSII.
//NASCAR is 3 16-bit channels using a 216 daughterboard.
//TSRPRO is 6 channels, 3 16-bit on a 216 daughterboard, 3 12-bit on the 215 motherboard
//BlastTestTSR is 7 channels, 4 12-bit on the 215 motherboard, 3 16-bit on a hacked daughterboard
//TSRBasic is 3 12-bit channels on the 215 motherboard
//HEADSII is 7 12-bit channels on the 221 board
//The other missing component to some of what you sent earlier is that some of these systems have multiple sample rates. BlastTestTSR will have the 4 12-bit channels @ 40ksps and the 3 16-bit channels @ 1ksps. NGI had 2 24-bit channels @ 1ksps and 2 16-bit (?? can't remember for sure) channels @ 1sps. As it stands now we have the lower level download code just interpolate slow data to fast data and then everything has the "same" sample rate at the upper level, but it might be nice to deal with it more formally since that creates some funny edge cases we have to deal with by limiting the download to occur in sample number chunks that are a multiple of the fast rate divided by the slow rate.
//On 8/12/2010 11:12 AM, Paul Hrissikopoulos wrote:
//> By the way, the types that the switches currently in the TSR2 code seem to think important are:
//>
//> TSRModel.NASCARIDR:
//> TSRModel.TSR6DX:
//> TSRModel.RateTestTSR:
//> TSRModel.BlastTSR:
//> TSRModel.TSR:
//> TSRModel.NGIPrototype:
//>
//> Are we going to want all of those? Some of those? Those and then some?
//>
//> On 8/12/2010 11:07 AM, Paul Hrissikopoulos wrote:
//>> I guess in theory the software should be able to deal with the multiplicity of device types as it sees fit -- some code, definitely including parts of the UI, will need to be able to actively discriminate between types before doing something type-specific, but I think the hope is that the bulk should be able to use it in a more generic sense (arm the same, download the same, realtime the same, etc.). But still maybe that's a valid point -- do we foresee a ton of cases where we'll be doing interface is/as and/or typefield checks before doing something?
//>>
//>> On 8/12/2010 10:50 AM, Tadd Seiff wrote:
//>>> I like this.
//>>>
//>>> My approach at the moment is immediately how to use this as a HEADS device. My understanding is that the device will surface through the factory which will populate things such as TSR.Channel[] Channels which can then be accessed safely only with RunTime checks like if (HEADS == unit.TSRModel) {...}. Does this put us in the same position being at the mercy of switch statements at a higher level? This is just my knee-jerk reaction.
//>>>
//>>> On 8/12/2010 10:08 AM, Paul Hrissikopoulos wrote:
//>>>> My reordering is attached. Search it for "?" for some open questions. Please let me know if you think I'm missing anything major (or minor) or am entirely on the wrong track.
//>>>>
//>>>> On 8/9/2010 10:26 PM, Rollin White wrote:
//>>>>> Here's an update with a channel class.
//>>>>>
//>>>>> Please voice concerns, opinions, etc. This is just my simple view of the task.
//>>>>>
//>>>>> On 8/9/2010 3:02 PM, Rollin White wrote:
//>>>>>> Here's my first cut at the interface description for the next generation TSR class. The interface is meant to describe the features common to all models.
//>>>>>>
//>>>>>> In addition to what's here, there needs to be significant definition of the channel class. Finally, there are probably a few interfaces that need to be defined that class implementers would optionally implement. For example, ISupportsDynamicEventLength.
//>>>>>>
//>>>>>> This is simply a starting point. Comments welcome.
//>>>>
//>>>
//>>
//>
//>
//--
//Chuck Gillen-O'Neel
//Diversified Technical Systems, Inc.
//909 Electric Avenue, Suite 206
//Seal Beach, CA 90740
//Telephone: (562) 493-0158
//Email: chuck.go@dtsweb.com
// My comments:
// * For sensitivity we should either have mv/count and eu/mv for each channel OR have eu/count for each channel. Obviously the former is more flexible, but also a little more complicated and maybe unneeded for 95-99% of TSR/HEADS applications.
// * OffsetCounts in IChannel should be signed. We nearly always need to make offsets signed. I'm speaking from my own mistakes here ... !!! :)
// * We need to think about the arm states a bit more. There have been a couple of cases where having a Disarming state, in addition to Disarmed, has been nice.
// * For GPIOs we might as well surface (and extend the firmware a bit to support this) the fact that IOs can be inputs as well as high/low outputs. So, rather than just returning a bool we might want to return a state enum. It's already there in the interface for SetGPIO since the GPIOPin.Direction enum has input and output and if it's set to input the State parameter is effectively a no-op.
// * The question of a good interface for Calibration is still unanswered. The interface as shown is obviously fine for doing those three readings, but I'm not sure how truly useful that is in a generic sense. I have a feeling that this is a place where we'll be hooking in model checks, etc. etc. Maybe that's okay and can be limited to the cal software.
//On 8/12/2010 10:50 AM, Tadd Seiff wrote:
//> I like this.
//>
//> My approach at the moment is immediately how to use this as a HEADS device. My understanding is that the device will surface through the factory which will populate things such as TSR.Channel[] Channels which can then be accessed safely only with RunTime checks like if (HEADS == unit.TSRModel) {...}. Does this put us in the same position being at the mercy of switch statements at a higher level? This is just my knee-jerk reaction.
//>
//> On 8/12/2010 10:08 AM, Paul Hrissikopoulos wrote:
//>> My reordering is attached. Search it for "?" for some open questions. Please let me know if you think I'm missing anything major (or minor) or am entirely on the wrong track.
//>>
//>> On 8/9/2010 10:26 PM, Rollin White wrote:
//>>> Here's an update with a channel class.
//>>>
//>>> Please voice concerns, opinions, etc. This is just my simple view of the task.
//>>>
//>>> On 8/9/2010 3:02 PM, Rollin White wrote:
//>>>> Here's my first cut at the interface description for the next generation TSR class. The interface is meant to describe the features common to all models.
//>>>>
//>>>> In addition to what's here, there needs to be significant definition of the channel class. Finally, there are probably a few interfaces that need to be defined that class implementers would optionally implement. For example, ISupportsDynamicEventLength.
//>>>>
//>>>> This is simply a starting point. Comments welcome.
//>>
//>
//--
//Chuck Gillen-O'Neel
//Diversified Technical Systems, Inc.
//909 Electric Avenue, Suite 206
//Seal Beach, CA 90740
//Telephone: (562) 493-0158
//Email: chuck.go@dtsweb.com

View File

@@ -0,0 +1,27 @@
/*
* DTS.Channel.ILargeDataAware
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of what it means for a DAS channel to be "large data aware".
/// </summary>
///
public interface ILargeDataAware
{
/// <summary>
/// Determine whether or not this data set is small enough to be safely fit into any array
/// within the context of a slice application (will be filtered, sent to viewer, etc).
/// </summary>
bool IsDataArraySized
{
get;
}
}
}

View File

@@ -0,0 +1,25 @@
/*
* IDataCollectionEnabled.cs
*
* Copyright © 2010
* Diversified Technical Systems, Inc.
* All Rights Reserved.
*/
namespace DTS.DAS.Concepts
{ ///
/// <summary>
/// Representation of the ability to perform a basic data collection.
/// </summary>
///
public interface IDataCollectionEnabled
: IArmable,
ITriggerable,
IDownloadEnabled
{ //
// Additional properties required for rudimentary data collection.
//
double[] AvailableSampleRates { get; }
double SampleRate { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
/*
* ITriggerable.cs
*
* Copyright © 2010
* Diversified Technical Systems, Inc.
* All Rights Reserved.
*/
namespace DTS.DAS.Concepts
{ ///
/// <summary>
/// Functional description of a "triggerable" object.
/// </summary>
///
public interface ITriggerable
{
void Trigger();
}
}

View File

@@ -0,0 +1,60 @@
/*
* IDownloadEnabled.cs
*
* Copyright © 2010
* Diversified Technical Systems, Inc.
* All Rights Reserved.
*/
using System;
/// <DevelopmentNote Developer="Paul Hrissikopoulos">
/// It may make sense to refactor this namespace to be DTS.Common.DAS.ConceptsTsr and rename the TSR-specific
/// event to "Event" so that the fully qualified name of the class is "DTS.Common.DAS.ConceptsTsr.Event", but
/// then maybe keep the IDownloadEnabled and other generic interfaces outside of the "Tsr"-specific
/// namespace...? No, should probably stay with Event, since it has an "Event" type referenced in the
/// interface.
/// </DevelopmentNote>
namespace DTS.Common.DAS.Concepts
{
///
/// <summary>
/// Representation of the ability to download from this object.
/// </summary>
///
public interface IDownloadEnabled
{ //
// TODO: Determine whether or not these things should be in here. Maybe the implementing
// object should just ask for them in the constructor and keep them private? I don't think
// these are universally applicable to something "download enabled"... are they?
//
//public uint MaximumStoredEventSizeSeconds { get; }
//public ushort DownloadIncrementSamples { get; }
//public string[] ChannelDescription { get; }
//public int TimeOffsetMilliseconds { get; }
/// <summary>
/// A list of download <see cref="DTS.Common.DAS.ConceptsTsrEvent"/>s available for download.
/// </summary>
TsrEvent[] EventList { get; }
///
/// <summary>
/// Get the event data for the specified sample.
/// </summary>
/// <param name="Event">The <see cref="DTS.Common.DAS.ConceptsTsrEvent"/> to have it's data extracted.</param>
/// <param name="FirstSample">The <see cref="UInt64"/> index of the first sample to be downloaded.</param>
/// <param name="LastSample">The <see cref="UInt64"/> index of the last sample to be downloaded.</param>
/// <returns>An array of <see cref="double"/> data arrays for each channel.</returns>
///
double[][] GetEventData(TsrEvent Event, ulong FirstSample, ulong LastSample); // Any reason to do data as an out parameter rather than a return value?
// Have a subclassed channel class that has a data array, just so that 2-d array isn't so ambiguous?
/// <summary>
/// Determine whether or not the data on this download-enabled entity has been downloaded.
/// </summary>
bool DataHasBeenDownloaded { get; }
}
}

View File

@@ -0,0 +1,25 @@
/*
* DAS.Channel.IEngineeringUnitAware.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of the concept of engineering unit awareness.
/// </summary>
public interface IEngineeringUnitAware
{
/// <summary>
/// Get/set this object's engineering unit description <see cref="string"/>.
/// </summary>
string EngineeringUnits
{
get;
set;
}
}
}

View File

@@ -0,0 +1,61 @@
using System;
using DTS.Common.Utilities;
namespace DTS.Common.DAS.Concepts
{
///
/// <summary>
/// Representation of data and metadata associated with a TSR event.
/// </summary>
///
public abstract class TsrEvent : Exceptional, ICloneable
{
/// <summary>
/// The 1-based <see cref="UInt64"/> identifier for this event.
/// </summary>
public virtual UInt64 EventId { get; protected set; }
/// <summary>
/// The <see cref="System.DateTime"/> containing the date and time of this event.
/// </summary>
public virtual DateTime TimeStamp { get; protected set; }
/// <summary>
/// The <see cref="string"/> serial number of the hardware that captured this event.
/// </summary>
public virtual string SerialNumber { get; protected set; }
/// <summary>
/// The <see cref="string"/> alternate serial number of the hardware that captured the event.
/// </summary>
public virtual string AlternateSerialNumber { get; protected set; }
/// <summary>
/// The <see cref="double"/> duration in seconds of this event.
/// </summary>
public virtual double DurationSeconds { get; protected set; }
/// <summary>
/// The <see cref="double"/> maximum sample rate for this event.
/// </summary>
public virtual double MaxSampleRate { get; protected set; } // note this is the "highest" sample rate
/// <summary>
/// The <see cref="float"/> temperature (in C).
/// </summary>
public virtual float TemperatureC { get; protected set; }
/// <summary>
/// The <see cref="double"/> number of pre-trigger seconds.
/// </summary>
public virtual double PreTriggerSeconds { get; protected set; }
///
/// <summary>
/// Generate a shallow copy of this object.
/// </summary>
/// <returns>A shallow copy of this <see cref="object"/>.</returns>
///
public abstract object Clone();
}
}

View File

@@ -0,0 +1,31 @@
/*
* IGpioEnabled.cs
*
* Copyright © 2010
* Diversified Technical Systems, Inc.
* All Rights Reserved.
*/
namespace DTS.DAS.Concepts.GPIOPin
{
public enum Directions
{
Output = 0x00, Peripheral = 0x01, Input = 0x02,
InputPulledUp = 0x03, InputPulledDown = 0x04
};
}
namespace DTS.DAS.Concepts
{ ///
/// <summary>
/// Representation of GPIO functionality.
/// </summary>
///
public interface IGpioEnabled
{
// TODO: Well have to bring these in as soon as we figure out where to get that enum from.
void SetGpio(uint Port, uint Pin, GPIOPin.Directions Direction, bool State);
bool GetGpio(uint Port, uint Pin);
}
}

View File

@@ -0,0 +1,26 @@
/*
* DTS.Common.DAS.Concepts.DAS.Channel.IInversionAware.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.Common.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of the concept of inversion awareness.
/// </summary>
public interface IInversionAware
{ ///
/// <summary>
/// Get/set this object's inversion state <see cref="bool"/>.
/// </summary>
///
bool IsInverted
{
get;
set;
}
}
}

View File

@@ -0,0 +1,27 @@
/*
* DTS.Channel.ILargeDataAware
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.Common.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of what it means for a DAS channel to be "large data aware".
/// </summary>
///
public interface ILargeDataAware
{
/// <summary>
/// Determine whether or not this data set is small enough to be safely fit into any array
/// within the context of a slice application (will be filtered, sent to viewer, etc).
/// </summary>
bool IsDataArraySized
{
get;
}
}
}

View File

@@ -0,0 +1,25 @@
/*
* DAS.Channel.ISerialNumberAware.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of the concept of serial number awareness.
/// </summary>
public interface ISerialNumberAware
{
/// <summary>
/// Get/set this object's serial number <see cref="string"/>.
/// </summary>
string SerialNumber
{
get;
set;
}
}
}

View File

@@ -0,0 +1,11 @@
namespace DTS.Common.DAS.Concepts.DAS.Channel
{
public interface ILinearized
{
DTS.Common.Classes.Sensors.LinearizationFormula LinearizationFormula
{
get;
set;
}
}
}

View File

@@ -0,0 +1,27 @@
/*
* ICalibratable.cs
*
* Copyright © 2010
* Diversified Technical Systems, Inc.
* All Rights Reserved.
*/
namespace DTS.Common.DAS.Concepts
{ ///
/// <summary>
/// Representation of the ability to calibrate.
/// </summary>
///
public interface ICalibratable
{ //
// Properties required for rudimentary calibration.
//
string SerialNumber { get; set; }
double Sensitivity { get; set; }
double BatteryVolts { get; set; }
double VddVolts { get; set; }
double SignalConditioningVolts { get; set; }
// access for generic attributes.
}
}

View File

@@ -0,0 +1,14 @@
using System;
namespace DTS.Common.DAS.Concepts.DAS.Channel
{
[Flags]
public enum LevelTriggerTypes
{
NONE = 0x00,
OutsideWindow = 0x01,
InsideWindow = 0x02,
LessThan = 0x04,
GreaterThan = 0x08
}
}

View File

@@ -0,0 +1,26 @@
namespace DTS.Common.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of the concept of calsignal-check awareness.
/// </summary>
public interface ICalSignalAware
{
/// <summary>
/// Get/set this object's <see cref="double"/> measured shunt deflection value.
/// </summary>
double MeasuredCalSignalMv
{
get;
set;
}
/// <summary>
/// Get/set this object's <see cref="double"/> target shunt deflection value.
/// </summary>
double TargetCalSignalMv
{
get;
set;
}
}
}

View File

@@ -0,0 +1,25 @@
/*
* IDataCollectionEnabled.cs
*
* Copyright © 2010
* Diversified Technical Systems, Inc.
* All Rights Reserved.
*/
namespace DTS.Common.DAS.Concepts
{ ///
/// <summary>
/// Representation of the ability to perform a basic data collection.
/// </summary>
///
public interface IDataCollectionEnabled
: IArmable,
ITriggerable,
IDownloadEnabled
{ //
// Additional properties required for rudimentary data collection.
//
double[] AvailableSampleRates { get; }
double SampleRate { get; set; }
}
}

View File

@@ -0,0 +1,63 @@
/*
Test.Module.Channel.Sensor.Bridge.cs
Copyright © 2008
Diversified Technical Systems, Inc.
All Rights Reserved
*/
using System.ComponentModel;
namespace DTS.DAS.Concepts
{
// *** see Test.cs ***
public partial class Test
{
/// <summary>
/// A container for DTS generic module concepts.
/// </summary>
public sealed partial class Module
{
// *** see Test.Module.Channel.cs ***
public partial class Channel
{
//*** see Test.Module.Channel.Sensor.cs ***
public partial class Sensor
{
/// <summary>
/// All available bridge types.
/// </summary>
public enum BridgeType
{
/// <summary>
/// sensor uses IEPE setup
/// </summary>
[Description("IEPE")]
IEPE = 1 << 0,
/// <summary>
/// sensor uses quarter bridge setup
/// </summary>
[Description("Quarter")]
QuarterBridge=1 << 1,
/// <summary>
/// sensor uses half bridge setup
/// </summary>
[Description("Bridge-Half")]
HalfBridge=1 << 2,
/// <summary>
/// sensor has a full bridge setup
/// </summary>
[Description("Bridge-Full")]
FullBridge = 1<< 3,
[Description("DigitalInput")]
DigitalInput = 1 << 4,
[Description("SQUIB")]
SQUIB = 1 << 5,
[Description("TOMDigital")]
TOMDigital = 1 << 6
}
}
}
}
}
}

View File

@@ -0,0 +1,25 @@
/*
* DTS.Common.DAS.Concepts.DAS.Channel.ISerialNumberAware.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.Common.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of the concept of serial number awareness.
/// </summary>
public interface ISerialNumberAware
{
/// <summary>
/// Get/set this object's serial number <see cref="string"/>.
/// </summary>
string SerialNumber
{
get;
set;
}
}
}

View File

@@ -0,0 +1,11 @@
namespace DTS.Common.DAS.Concepts
{
/// <summary>
/// different possible arm modes
/// </summary>
public enum AvailableArmModes
{
LowPower,
CircularBuffer,
};
}

View File

@@ -0,0 +1,24 @@
using DTS.Common.Converters;
using System;
using System.ComponentModel;
namespace DTS.Common.DAS.Concepts.DAS.Channel
{
[TypeConverter(typeof(EnumDescriptionTypeConverter))]
[Flags]
public enum TimestampPartTypes
{
[Description("Marker")]
Marker = 1 <<0 ,
[Description("Seconds")]
Seconds_High = 1 << 1,
[Description("Seconds")]
Seconds_Low = 1 << 2,
[Description("Nanoseconds")]
Nanoseconds_High = 1 << 3,
[Description("Nanoseconds")]
Nanoseconds_Low = 1 << 4,
[Description("Reserved")]
Reserved = 1 << 5
}
}

View File

@@ -0,0 +1,34 @@
/*
* IRealtimeable.cs
*
* Copyright © 2010
* Diversified Technical Systems, Inc.
* All Rights Reserved.
*/
using System;
namespace DTS.DAS.Concepts
{ ///
/// <summary>
/// Representation of a real-time data sample.
/// </summary>
///
public class RealtimeSample
{
public double[] DataEU; // Note this indexes by channel.
public UInt64 SampleNumber;
}
///
/// <summary>
/// Representation of the ability to perform "real-time" data capture.
/// </summary>
///
public interface IRealtimeable
{
void StartRealtime( double sampleRate );
void StopRealtime();
RealtimeSample[] GetRealtimeSamples();
}
}

View File

@@ -0,0 +1,75 @@
/*
Test.Module.Channel.Sensor.ZeroMethod.cs
Copyright © 2008
Diversified Technical Systems, Inc.
All Rights Reserved
*/
using System.ComponentModel;
namespace DTS.DAS.Concepts
{
// *** see Test.cs ***
public partial class Test
{
/// <summary>
/// A container for DTS generic module concepts.
/// </summary>
public sealed partial class Module
{
// *** see Test.Module.Channel.cs ***
public partial class Channel
{
//*** see Test.Module.Channel.Sensor.cs ***
public partial class Sensor
{
/// <summary>
/// All available zero method types.
/// </summary>
public enum ZeroMethodType
{
// Lots of legacy compatibility (e.g. importing GM ISF) depends on the order/value of this enum.
/// <summary>
/// calculate electrical zero using an average over time
/// </summary>
[Description("Average Over Time")]
AverageOverTime = 0,
/// <summary>
/// calculate zero using time in pre-event
/// </summary>
[Description("Use Diagnostics Zero")]
UsePreEventDiagnosticsZero = 1,
/// <summary>
/// calculate zero using injected value
/// </summary>
[Description("Absolute Zero")]
None = 2
}
/// <summary>
/// Original version of all available zero method types.
/// </summary>
public enum OriginalZeroMethodType
{
/// <summary>
/// calculate electrical zero using an average over time
/// </summary>
[Description("Average Over Time")]
AverageOverTime,
/// <summary>
/// calculate zero using time in pre-event
/// </summary>
[Description("Use Diagnostics Zero")]
UsePreCalZero,
/// <summary>
/// calculate zero using injected value
/// </summary>
[Description("Absolute Zero")]
None
}
}
}
}
}
}

View File

@@ -0,0 +1,35 @@
/*
* DTS.Common.DAS.Concepts.DAS.Channel.IShuntAware.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.Common.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of the concept of shunt-check awareness.
/// </summary>
public interface IShuntAware
{
/// <summary>
/// Get/set this object's <see cref="double"/> measured shunt deflection value.
/// </summary>
double MeasuredShuntDeflectionMv
{
get;
set;
}
/// <summary>
/// Get/set this object's <see cref="double"/> target shunt deflection value.
/// </summary>
double TargetShuntDeflectionMv
{
get;
set;
}
}
}

View File

@@ -0,0 +1,919 @@
/*
* DataScaler.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
using System;
using DTS.Common.Classes.Sensors;
using DTS.Common.Constant;
using DTS.Common.Enums;
using DTS.Common.Enums.Sensors;
using DTS.Common.Utilities;
using DTS.Common.Utilities.DotNetProgrammingConstructs;
namespace DTS.Common.DAS.Concepts
{
/// <summary>
/// A class to contain properties and methods associated with data scaling.
/// </summary>
public partial class DataScaler : Exceptional
{
public double UserOffsetEU { get; set; }
public double Multiplier { get; set; } = 1D;
private DTS.Common.Classes.Sensors.LinearizationFormula _linearizationEquation;
public void SetLinearizationFormula(DTS.Common.Classes.Sensors.LinearizationFormula equation) { _linearizationEquation = equation; }
public DTS.Common.Classes.Sensors.LinearizationFormula GetLinearizationFormula()
{
return _linearizationEquation ?? (_linearizationEquation = new DTS.Common.Classes.Sensors.LinearizationFormula());
}
/// <summary>
/// Get the ADC->EU scaling factor (EU/mV)
/// </summary>
private double AdcToEuScalingFactor
{
get
{
try
{
if (null != _adcToEuScalingFactor) return (double)_adcToEuScalingFactor;
if (UseEUScaleFactors)
{
_adcToEuScalingFactor = (ScaleFactorEU * UnitConversion)
* (BasedOnOutputAtCapacity ? CapacityOutputIsBasedOn : 1.0)
* (IsInverted ? -1 : 1);
}
else
{
_adcToEuScalingFactor = (ScaleFactorMv * UnitConversion
/ (ProportionalToExcitation && SensitivityUnits != SensorConstants.SensUnits.mVperEU
? MvPerEu * GetExcitationVoltage() : MvPerEu))
* (BasedOnOutputAtCapacity ? CapacityOutputIsBasedOn : 1.0)
* (IsInverted ? -1.0 : 1.0);
}
return (double)_adcToEuScalingFactor;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem computing ADC->EU scaling factor", ex);
}
}
}
private double? _adcToEuScalingFactor = null;
/// <summary>
/// the ADCtoEUScalingFactor is a cached value
/// and isn't recalculated once it's calculated
/// this method clears the cached value so that the next time
/// it is used the value is recalculated
/// this should be done if the sensitivity or the scalefactors change
/// </summary>
public void ClearADCToEuScalingFactor()
{
_adcToEuScalingFactor = null;
}
/// <summary>
/// Get the mV/ADC scale factor
/// </summary>
private double AdcToMvScalingFactor
{
get
{
try
{
if (null == _adcToMvScalingFactor)
_adcToMvScalingFactor = ScaleFactorMv;
return (double)_adcToMvScalingFactor;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem computing ADC->MV scaling factor", ex);
}
}
}
private double? _adcToMvScalingFactor;
/// <summary>
/// set the mv/ADC scale factor for this channel.
/// </summary>
private double ScaleFactorMv
{
//we disable this, we don't want them doing calculations, we want them
//to use us for calculations ...
get => _scaleFactorMv.Value;
set
{
_scaleFactorMv.Value = value;
_adcToEuScalingFactor = null;
CalculateInitialOffset();
}
}
private double ScaleFactorEU
{
//we disable this, we don't want them doing calculations, we want them
//to use us for calculations ...
get => _scaleFactorEU.Value;
set { _scaleFactorEU.Value = value; _adcToEuScalingFactor = null; }
}
private bool UseEUScaleFactors
{
get => _useEUScaleFactors.Value;
set => _useEUScaleFactors.Value = value;
}
/// <summary>
/// Sets the scale factor. (mV/ADC)
/// </summary>
/// <param name="value"></param>
public void SetScaleFactorMv(double value) { ScaleFactorMv = value; }
public void SetScaleFactorEU(double value) { ScaleFactorEU = value; }
public void SetUseEUScaleFactors(bool value) { UseEUScaleFactors = value; }
private DigitalInputScaleMultiplier _digitalMultiplier = new DigitalInputScaleMultiplier();
public void SetDigitalMultiplier(DigitalInputScaleMultiplier multiplier) { _digitalMultiplier = multiplier; }
public DigitalInputScaleMultiplier GetDigitalMultiplier()
{
return _digitalMultiplier ?? (_digitalMultiplier = new DigitalInputScaleMultiplier());
}
public bool Digital { get; set; }
public bool DigitalOutput { get; set; }
/// <summary>
/// returns the conversion factor from ADC to mV
/// </summary>
/// <returns>mV/ADC</returns>
public double GetScaleFactorMv() { return ScaleFactorMv; }
private readonly Property<double> _scaleFactorMv
= new Property<double>(
typeof(DataScaler).Namespace + ".DataScaler.ScaleFactorMv",
0.0,
false
);
public double GetScaleFactorEU() { return ScaleFactorEU; }
private readonly Property<double> _scaleFactorEU
= new Property<double>(
typeof(DataScaler).Namespace + ".DataScaler.ScaleFactorEU",
0.0,
false
);
private readonly Property<bool> _useEUScaleFactors
= new Property<bool>(
typeof(DataScaler).Namespace + ".DataScaler.UseEUScaleFactors",
false,
true
);
public double UnitConversion { get; set; } = 1D;
/// <summary>
/// set the sensitivity mV/EU factor for this channel.
/// </summary>
private double MvPerEu
{
//we disable the get, we don't want outside code doing calculations,
//we want them to use this class to do calculations
get => _mvPerEu.Value;
set => _mvPerEu.Value = value;
}
private readonly Property<double> _mvPerEu
= new Property<double>(
typeof(DataScaler).Namespace + ".DataScaler.MvPerEu",
1.0, // Yes, it's initialized on purpose. In case this isn't an analog channel. Normally
true // we'd leave it uninitialized and trap the error if someone tries to use it, but our
); // binary serialization format always expects an EU value from all channels, so...
/// <summary>
/// sets mV per EU scale factor
/// </summary>
/// <param name="value"></param>
public void SetMvPerEu(double value) { MvPerEu = value; }
public double GetMvPerEu() { return MvPerEu; }
/// <summary>
/// Get/set the descriptor indiciating whether or not this channel is
/// based on output at capacity.
/// </summary>
public bool BasedOnOutputAtCapacity
{
get => _basedOnOutputAtCapacity.Value;
set => _basedOnOutputAtCapacity.Value = value;
}
private readonly Property<bool> _basedOnOutputAtCapacity
= new Property<bool>(
typeof(DataScaler).Namespace + ".DataScaler.BasedOnOutputAtCapacity",
false,
true
);
/// <summary>
/// Get/set the capacity output is based on value.
/// </summary>
public double CapacityOutputIsBasedOn
{
get => _capacityOutputIsBasedOn.Value;
set
{
if (0 < value)
{
_capacityOutputIsBasedOn.Value = value;
}
else
{
_capacityOutputIsBasedOn.UnInitialize();
}
}
}
private readonly Property<double> _capacityOutputIsBasedOn
= new Property<double>(
typeof(DataScaler).Namespace + ".DataScaler.CapacityOutputIsBasedOn",
1.000,
true
);
public SensorConstants.SensUnits SensitivityUnits { get; set; } = SensorConstants.SensUnits.NONE;
/// <summary>
/// Get/set the descriptor indiciating whether or not this channel is
/// proportional to excitation.
/// </summary>
public bool ProportionalToExcitation
{
get => _proportionalToExcitation.Value;
set => _proportionalToExcitation.Value = value;
}
private readonly Property<bool> _proportionalToExcitation
= new Property<bool>(
typeof(DataScaler).Namespace + ".DataScaler.ProportionalToExcitation",
false,
true
);
/// <summary>
/// Get the <see cref="double"/> excitation voltage value.
/// </summary>
public double GetExcitationVoltage()
{
try
{
//FB 18727 use measured excitation if the setting is true & ExcitationVoltage is 2 volt
if (NominalExcitationVoltage == ExcitationVoltageOptions.ExcitationVoltageOption.Volt2 && Settings.SettingsDB.GetGlobalValueBool(Constants.UseMeasuredExcitation, false))
{
return _measuredExcitationVoltage.IsInitialized ? MeasuredExcitationVoltage : Test.Module.Channel.Sensor.GetExcitationVoltageMagnitudeFromEnum(NominalExcitationVoltage);
}
else
{
if (_factoryExcitationVoltage.IsInitialized) return FactoryExcitationVoltage;
return _measuredExcitationVoltage.IsInitialized ? MeasuredExcitationVoltage : Test.Module.Channel.Sensor.GetExcitationVoltageMagnitudeFromEnum(NominalExcitationVoltage);
}
}
catch (System.Exception ex)
{
throw new Exception("encountered problem determining excitation voltage", ex);
}
}
/// <summary>
/// Get/set the excitation voltage for this channel.
/// </summary>
public ExcitationVoltageOptions.ExcitationVoltageOption NominalExcitationVoltage
{
get => _excitationVoltage.Value == ExcitationVoltageOptions.ExcitationVoltageOption.Undefined
? throw new InvalidExcitationVoltageException(
"cannot use undefined excitation voltage to calculate scaling factor")
: _excitationVoltage.Value;
set => _excitationVoltage.Value = value;
}
private readonly Property<ExcitationVoltageOptions.ExcitationVoltageOption> _excitationVoltage
= new Property<ExcitationVoltageOptions.ExcitationVoltageOption>(
typeof(DataScaler).Namespace + ".DataScaler.ExcitationVoltage",
ExcitationVoltageOptions.ExcitationVoltageOption.Volt5,
false
);
public bool FactoryExcitationVoltageValid => _factoryExcitationVoltage.IsInitialized;
/// <summary>
/// Get/set the factory excitation voltage value.
/// </summary>
public double FactoryExcitationVoltage
{
get => _factoryExcitationVoltage.Value;
set
{
if (0 < value)
{
_factoryExcitationVoltage.Value = value;
}
else
{
_factoryExcitationVoltage.UnInitialize();
}
}
}
private readonly Property<double> _factoryExcitationVoltage
= new Property<double>(
typeof(DataScaler).Namespace + ".DataScaler.FactoryExcitationVoltage",
0.0,
false
);
public bool MeasuredExcitationVoltageValid => _measuredExcitationVoltage.IsInitialized;
/// <summary>
/// Get/set the measured excitation voltage value.
/// </summary>
public double MeasuredExcitationVoltage
{
get => _measuredExcitationVoltage.Value;
set => _measuredExcitationVoltage.Value = value;
}
private readonly Property<double> _measuredExcitationVoltage
= new Property<double>(
typeof(DataScaler).Namespace + ".DataScaler.MeasuredExcitationVoltage",
0.0,
false
);
/// <summary>
/// Get/set channel inversion status.
/// </summary>
public bool IsInverted
{
get => _isInverted.Value;
set => _isInverted.Value = value;
}
private readonly Property<bool> _isInverted
= new Property<bool>(
typeof(DataScaler).Namespace + ".DataScaler.IsInverted",
false,
false
);
private double _initialOffsetmVinADC = 0D;
private double _initialOffsetEU = 0D;
private InitialOffset _initialOffset = new InitialOffset();
public void SetInitialOffset(InitialOffset offset)
{
_initialOffset = offset;
CalculateInitialOffset();
}
public void SetInitialOffset(string offset)
{
_initialOffset.FromDbSerializeString(offset);
CalculateInitialOffset();
}
private void CalculateInitialOffset()
{
switch (_initialOffset.Form)
{
case InitialOffsetTypes.FRONTAL:
case InitialOffsetTypes.LHS:
case InitialOffsetTypes.RHS:
case InitialOffsetTypes.EU: InitialEU = _initialOffset.EU; break;
case InitialOffsetTypes.EUAtMV: //calculated INSIDE the EU equation
{
InitialEU = 0;
//only true if we are using zeromethod = none
if (ZeroMethodType == ZeroMethodType.None && _scaleFactorMv.IsValueInitialized)
{
_initialOffsetEU = _initialOffset.EU;
_initialOffsetmVinADC = ScaleFactorMv != 0 ? _initialOffset.MV / ScaleFactorMv : 0D;
}
else
{
_initialOffsetmVinADC = 0D;
_initialOffsetEU = 0D;
}
}
break;
default:
_initialOffsetmVinADC = 0D;
_initialOffsetEU = 0D;
InitialEU = 0D;
break;
}
}
public double GetCorrectedADC(short adc, bool convertUnsigned = false)
{
if (!Digital // Never correct for non-Digital
|| (Digital && DigitalInputs.DisplaySPDADC // Don't correct SPD if we're showing RAW ADC
&& (adc != short.MaxValue && adc != short.MinValue)) // ...unless this is an older data set
|| (Digital && ScaleFactorMv >= 0)) // Don't correct for G5 DI or TDAS DIM
{
if (convertUnsigned)
{
var unsigned = (ushort)(adc - 0x8000);
return Convert.ToDouble(unsigned);
}
return Convert.ToDouble(adc);
}
var breakPoint = DigitalInputs.ConstantCurrentBreakPoint;
if (DigitalMode == DigitalInputModes.THL || DigitalMode == DigitalInputModes.TLH)
{
breakPoint = DigitalInputs.VoltageInputBreakPoint;
}
//handle digital sensors
var bAboveBreak = adc > breakPoint;
if ((short.MaxValue == adc || short.MinValue == adc)
&& (DigitalMode == DigitalInputModes.CCNC || DigitalMode == DigitalInputModes.CCNO)) // Handle pre-14435 change digital data)
{
//14435 Store SPD data as analog, but show in viewers as digital, expose Digital break point
//SLICE2 has inverted ADC, so we need to swap the direction of above/below
bAboveBreak = !bAboveBreak;
}
return bAboveBreak ? Convert.ToDouble(short.MaxValue) : Convert.ToDouble(short.MinValue);
}
public double GetEU(short adc)
{
try { return GetEU(Convert.ToDouble(adc)); }
catch (System.Exception ex)
{
Utilities.Logging.APILogger.Log(ex);
return double.NaN;
}
}
/// <summary>
/// represents the old concept of initial eu, just a value added to the end of the eu equation.
/// </summary>
private double InitialEU = 0D;
/// <summary>
/// returns the Initial EU property - this is the old concept of EU, it's just a value added
/// to the end of the eu equation ...
/// </summary>
public double GetInitialEU() => InitialEU;
private ZeroMethodType _zeroMethodType = ZeroMethodType.None;
public ZeroMethodType ZeroMethodType
{
get => _zeroMethodType;
set
{
_zeroMethodType = value;
CalculateInitialOffset();
}
}
/// <summary>
/// returns eu given a mV value
/// originally written for
/// 14700 Diagnostic offsets should show in EU also
/// ordinarily we go from ADC to mV or ADC to EU, but never mV to EU
/// however SLICE reads initial offsets in terms of mV
/// </summary>
/// <param name="mV"></param>
/// <returns></returns>
public double GetEUFromMv(double mV)
{
//first intercept the process if we have a non linear channel
if (null != _linearizationEquation && _linearizationEquation.IsValid())
{
double eu = 0;
if (UseEUScaleFactors)
{
for (var i = 0; i < _linearizationEquation.PolynomialCoefficients.Length && i < _linearizationEquation.PolynomialExponents.Length; i++)
{
eu += _linearizationEquation.GetCoefficient(i) * Math.Pow(mV, _linearizationEquation.PolynomialExponents[i]);
}
}
else
{
//FB 29728 pass parameter to determine is proportional
eu = _linearizationEquation.GetLinearizedValue(mV, GetExcitationVoltage(), ProportionalToExcitation) * (IsInverted ? -1D : 1D);
var zero = double.NaN;
//if datazeroleveladc is zero, then we shouldn't applying zeroing as it will give bad data
//however if it is non zero, go ahead and apply it
switch (_linearizationEquation.NonLinearStyle)
{
//the 0MMmV knows where zero mm is by default and doesn't need to calculate a zero value
//5512 mV for 0MM [IRTRACC] sometimes makes funny offset.
case NonLinearStyles.IRTraccZeroMMmV:
// IRTRACC with Cal Factor is always zero method of NONE
// http://manuscript.dts.local/f/cases/resolve/17783/IRTRACC-w-CalFactor-should-always-process-as-Zero-Method-NONE
case NonLinearStyles.IRTraccCalFactor:
zero = double.NaN;
break;
default:
//http://fogbugz/fogbugz/default.asp?11399 dont set zero if method is NONE
if (0 != DataZeroLevelADC && ZeroMethodType != ZeroMethodType.None) { zero = _linearizationEquation.GetLinearizedValue(GetMv(DataZeroLevelADC), GetExcitationVoltage()) * (IsInverted ? -1D : 1D); }
break;
}
if (double.IsNaN(zero) || double.IsNegativeInfinity(zero) || double.IsPositiveInfinity(zero)) { zero = 0D; }
eu = eu - zero;
switch (_linearizationEquation.NonLinearStyle)
{
case NonLinearStyles.IRTraccAverageOverTime:
case NonLinearStyles.IRTraccDiagnosticsZero:
case NonLinearStyles.IRTraccManual:
case NonLinearStyles.IRTraccZeroMMmV:
eu *= -1D;
break;
}
}
return eu + InitialEU + UserOffsetEU;
}
//handle analog sensors
//note that a negative scale factor results in a negative MvPerEU
//however, the EU output needs to consider polarity as well, IsInverted shows only the value of polarity, so
//we can use it here
if (!Digital)
{
//14918 Init offset displayed in EU during diag looks incorrect for EU@mV sensor
//Calculate Offset is what is setting the initial offset, but for EU@mV
//we need to make sure we compensate, ordinarily this is dont throug the initialoffsetmvinadc
//but this route wasn't taking it into consideration, it does now.
return (mV * (IsInverted ? -1 : 1)) / (MvPerEu * (ProportionalToExcitation ? GetExcitationVoltage() : 1)) *
Multiplier +
InitialEU + UserOffsetEU + _initialOffsetEU - _initialOffsetmVinADC * ScaleFactorMv;
}
return double.NaN;
}
//returns EU given an ADC value (taking into consideration software zeroing and initial EU)
public double GetEU(double adc)
{
// Correct ADC for DIM Data
var correctedadc = adc;
//GetCorrectedADC, will coalesce adc to a short, so avoid calling it if we don't need to
if (Digital) { correctedadc = GetCorrectedADC(Convert.ToInt16(adc)); }
//first intercept the process if we have a non linear channel
if (null != _linearizationEquation && _linearizationEquation.IsValid())
{
double eu = 0;
if (UseEUScaleFactors)
{
var mV = (correctedadc - DataZeroLevelADC) * ScaleFactorMv / MeasuredExcitationVoltage;
for (var i = 0; i < _linearizationEquation.PolynomialCoefficients.Length && i < _linearizationEquation.PolynomialExponents.Length; i++)
{
eu += _linearizationEquation.GetCoefficient(i) * Math.Pow(mV, _linearizationEquation.PolynomialExponents[i]);
}
}
else
{
eu = _linearizationEquation.GetLinearizedValue(GetMv(correctedadc), GetExcitationVoltage()) * (IsInverted ? -1D : 1D);
var zero = double.NaN;
//if datazeroleveladc is zero, then we shouldn't applying zeroing as it will give bad data
//however if it is non zero, go ahead and apply it
switch (_linearizationEquation.NonLinearStyle)
{
//the 0MMmV knows where zero mm is by default and doesn't need to calculate a zero value
//5512 mV for 0MM [IRTRACC] sometimes makes funny offset.
case NonLinearStyles.IRTraccZeroMMmV:
// IRTRACC with Cal Factor is always zero method of NONE
//http://manuscript.dts.local/f/cases/resolve/17783/IRTRACC-w-CalFactor-should-always-process-as-Zero-Method-NONE
case NonLinearStyles.IRTraccCalFactor:
zero = double.NaN;
break;
default:
//http://fogbugz/fogbugz/default.asp?11399 dont set zero if method is NONE
if (0 != DataZeroLevelADC && ZeroMethodType != ZeroMethodType.None) { zero = _linearizationEquation.GetLinearizedValue(GetMv(DataZeroLevelADC), GetExcitationVoltage()) * (IsInverted ? -1D : 1D); }
break;
}
if (double.IsNaN(zero) || double.IsNegativeInfinity(zero) || double.IsPositiveInfinity(zero)) { zero = 0D; }
eu = eu - zero;
switch (_linearizationEquation.NonLinearStyle)
{
case NonLinearStyles.IRTraccAverageOverTime:
case NonLinearStyles.IRTraccDiagnosticsZero:
case NonLinearStyles.IRTraccManual:
case NonLinearStyles.IRTraccZeroMMmV:
eu *= -1D;
break;
}
}
return eu * Multiplier + InitialEU + UserOffsetEU;
}
//handle analog sensors
if (!Digital)
{
var eu = (correctedadc - DataZeroLevelADC - _initialOffsetmVinADC) * Multiplier * AdcToEuScalingFactor +
InitialEU + UserOffsetEU + _initialOffsetEU;
return eu;
}
var breakPoint = DigitalInputs.ConstantCurrentBreakPoint;
if (DigitalMode == DigitalInputModes.THL || DigitalMode == DigitalInputModes.TLH)
{
breakPoint = DigitalInputs.VoltageInputBreakPoint;
}
//handle digital sensors
var bAboveBreak = correctedadc > breakPoint;
if (ScaleFactorMv < 0)
{
switch (DigitalMode)
{
case DigitalInputModes.CCNC:
case DigitalInputModes.CCNO:
//14435 Store SPD data as analog, but show in viewers as digital, expose Digital break point
//SLICE2 has inverted ADC, so we need to swap the direction of above/below
bAboveBreak = !bAboveBreak;
break;
default:
//Do Nothing
break;
}
}
if (bAboveBreak)
{
switch (DigitalMode)
{
case DigitalInputModes.CCNC:
return _digitalMultiplier.DefaultValue;
case DigitalInputModes.CCNO:
return _digitalMultiplier.ActiveValue;
case DigitalInputModes.THL:
return _digitalMultiplier.DefaultValue;
case DigitalInputModes.TLH:
return _digitalMultiplier.ActiveValue;
default: return _digitalMultiplier.ActiveValue;
}
}
switch (DigitalMode)
{
case DigitalInputModes.CCNC:
return _digitalMultiplier.ActiveValue;
case DigitalInputModes.CCNO:
return _digitalMultiplier.DefaultValue;
case DigitalInputModes.THL:
return _digitalMultiplier.ActiveValue;
case DigitalInputModes.TLH:
return _digitalMultiplier.DefaultValue;
default: return _digitalMultiplier.DefaultValue;
}
}
public DigitalInputModes DigitalMode { get; set; } = DigitalInputModes.CCNC;
/// <summary>
/// zeroMvInADC is the concept of ADC when 0mV is injected into the DAC
/// this is used with TDAS equipment to determine and remove offset on some
/// sensors
/// this value will be removed in SLICEWare to remove any measured offset present not from the sensor
/// DataZeroLevel also is an ADC value removed when converting to ADC (typically from software zeroing like window averaging)
/// however I keep it separate to allow the factor to be applied or not to ADC/EU/MV, while DataZeroLevel is only applied to EU
/// [however DataZeroLevel is ZeroMvInADC when zeroing method is "use 0mV", so we only need to apply ZeroMvInADC to mV scaling]
/// </summary>
private readonly Property<int> _zeroMvInADC = new Property<int>(
typeof(DataScaler).Namespace + ".DataScaler.ZeroMVInADC",
0,
true);
public int ZeroMvInADC
{
get => _zeroMvInADC.Value;
private set => _zeroMvInADC.Value = value;
}
public void SetZeroMvInADC(int adc) { ZeroMvInADC = adc; }
public void SetZeroMvInADC(double adc)
{
if (double.IsNaN(adc)) { ZeroMvInADC = 0; }
else
{
try { ZeroMvInADC = Convert.ToInt32(adc); }
catch (System.Exception) { ZeroMvInADC = 0; }
}
}
/// <summary>
/// WindowAverageADC is not needed for the DataScaler (as it automatically uses DataZeroLevelADC)
/// but I preserve it here so that it's set just like the other zero values (ZeroMvInADC) and maybe
/// will be available for use in the future
/// </summary>
private readonly Property<int> _windowAverageADC = new Property<int>(
typeof(DataScaler).Namespace + ".DataScaler.WindowAverageADC",
short.MinValue,
true);
/// <summary>
/// WindowAverageADC is the ADC average over the Zero Window for the channel
/// it is private here to force external access through methods
/// </summary>
private int WindowAverageADC
{
get => _windowAverageADC.Value;
set => _windowAverageADC.Value = value;
}
/// <summary>
/// Set the window average ADC for the scaler
/// This does not set the ZeroLevelADC which is used for software zeroing
/// </summary>
/// <param name="adc"></param>
public void SetWindowAverageADC(int adc) { WindowAverageADC = adc; }
public void SetWindowAverageADC(double adc)
{
if (double.IsNaN(adc)) { WindowAverageADC = 0; }
else
{
try { WindowAverageADC = Convert.ToInt32(adc); }
catch (System.Exception) { WindowAverageADC = 0; }
}
}
/// <summary>
/// SetRemovedADC stores the adc removed by H/W zeroing functions
/// the purpose of storing this is for use in mV functions that need to go from
/// ADC to mV but also need to adjust back in the removed ADC
/// </summary>
/// <param name="adc"></param>
public void SetRemovedADC(int adc) { RemovedADC = adc; }
private int RemovedADC
{
get => _removedADC.Value;
set => _removedADC.Value = value;
}
private readonly Property<int> _removedADC
= new Property<int>(
typeof(DataScaler).Namespace + ".DataScaler.RemovedADC",
0,
true
);
/// <summary>
/// SetRemovedInternalADC stores the internal adc removed by H/W zeroing functions
/// the purpose of storing this is for use in mV functions that need to go from
/// ADC to mV but also need to adjust back in the removed ADC
/// </summary>
/// <param name="adc"></param>
public void SetRemovedInternalADC(int adc) { RemovedInternalADC = adc; }
private int RemovedInternalADC
{
get => _removedInternalADC.Value;
set => _removedInternalADC.Value = value;
}
private readonly Property<int> _removedInternalADC
= new Property<int>(
typeof(DataScaler).Namespace + ".DataScaler.RemovedInternalADC",
0,
true
);
public double GetAdcToEuScalingFactor() { return AdcToEuScalingFactor; }
public double GetAdcToMvScalingFactor() { return AdcToMvScalingFactor; }
private readonly Property<short> _dataZeroLevelADC
= new Property<short>(
typeof(DataScaler).Namespace + ".DataScaler.DataZeroLevelADC",
0,
true
);
/// <summary>
/// DataZeroLevelADC is the amount of ADC to be removed by software to zero out the data. This value is typically determined
/// using Software Zeroing like averaging window.
/// </summary>
private short DataZeroLevelADC
{
get => _dataZeroLevelADC.IsValueInitialized ? _dataZeroLevelADC.Value : Convert.ToInt16(0);
set => _dataZeroLevelADC.Value = value;
}
public void SetDataZeroLevelADC(short value) { DataZeroLevelADC = value; }
public short GetDataZeroLevelADC() { return DataZeroLevelADC; }
/// <summary>
/// returns the mV corresponding to the given ADC value
/// </summary>
/// <param name="adc"></param>
/// <returns></returns>
public double GetMv(short adc)
{
return GetMv(Convert.ToDouble(adc));
}
/// <summary>
/// returns mV unless IEPE is true, then returns V
/// </summary>
/// <param name="adc"></param>
/// <returns></returns>
public double GetMvOrV(short adc, bool volts)
{
return GetMv(adc) / (volts ? 1000D : 1D);
}
/// <summary>
/// returns mV unless IEPE is true, then returns V
/// </summary>
/// <param name="adc"></param>
/// <returns></returns>
public double GetMvOrV(double adc, bool volts)
{
return GetMv(adc) / (volts ? 1000D : 1D);
}
public bool IEPE { get; set; }
private readonly int IEPESCALE = 1;
public DataScaler()
{
IEPE = false;
DigitalOutput = false;
Digital = false;
UserOffsetEU = 0D;
}
public DataScaler(DataScaler copy)
{
IsInverted = copy.IsInverted;
SetLinearizationFormula(copy._linearizationEquation);
Digital = copy.Digital;
SetDigitalMultiplier(copy._digitalMultiplier);
DigitalMode = copy.DigitalMode;
SetScaleFactorMv(copy.GetScaleFactorMv());
SetScaleFactorEU(copy.GetScaleFactorEU());
SetUseEUScaleFactors(copy.UseEUScaleFactors);
UnitConversion = copy.UnitConversion;
BasedOnOutputAtCapacity = copy.BasedOnOutputAtCapacity;
CapacityOutputIsBasedOn = copy.CapacityOutputIsBasedOn;
SensitivityUnits = copy.SensitivityUnits;
Multiplier = copy.Multiplier;
UserOffsetEU = copy.UserOffsetEU;
IEPE = copy.IEPE;
SetMvPerEu(copy.GetMvPerEu());
SetDataZeroLevelADC(copy.GetDataZeroLevelADC());
SetRemovedADC(copy.RemovedADC);
SetRemovedInternalADC(copy.RemovedInternalADC);
SetZeroMvInADC(copy.ZeroMvInADC);
SetWindowAverageADC(copy.WindowAverageADC);
SetInitialOffset(copy._initialOffset);
ZeroMethodType = copy.ZeroMethodType;
NominalExcitationVoltage = copy.NominalExcitationVoltage;
MeasuredExcitationVoltage = copy.MeasuredExcitationVoltage;
FactoryExcitationVoltage = copy.FactoryExcitationVoltage;
ProportionalToExcitation = copy.ProportionalToExcitation;
}
/// <summary>
/// 10485 Disable mV graphs for digital inputs
/// 10436 When moving from ADC to mV unit scale is incorrect on both TDAS PRO DIM and G5 for digital input channels.
/// this constant is just a value that we display when displaying mV for a digital input
/// </summary>
public const double DIGITAL_ON_VALUE = 2500D;
public double GetMv(double adc)
{
//we don't consider software zero'ing for mV, so leave out DataZeroLevel, but take into consideration the
//removed offset.
//note we do consider ZeroMvInADC in mV values as TDC does
//digitals per 10436 we display -2500/2500
if (Digital)
{
switch (DigitalMode)
{
case DigitalInputModes.TLH:
case DigitalInputModes.THL:
return adc > DigitalInputs.VoltageInputBreakPoint ? DIGITAL_ON_VALUE : -1D * DIGITAL_ON_VALUE;
default:
return adc > DigitalInputs.ConstantCurrentBreakPoint ? DIGITAL_ON_VALUE : -1D * DIGITAL_ON_VALUE;
}
}
if (null != _linearizationEquation && _linearizationEquation.IsValid())
{
var mV = (adc - ZeroMvInADC) * ScaleFactorMv;
if (IEPE) { return Converters.InitialOffsetToIEPESensorOffsetConverter.ConvertDouble(mV) * 1000.0; }
return mV;
}
else
{
var mV = (adc + RemovedADC - ZeroMvInADC) * ScaleFactorMv;
if (IEPE) { return Converters.InitialOffsetToIEPESensorOffsetConverter.ConvertDouble(mV) * 1000.0; }
return mV;
}
}
public void SetIRTraccZeros(double averageOverTime, double diagnosticADC)
{
}
}
}

View File

@@ -0,0 +1,29 @@
/*
* DataScaler.InvalidExcitationVoltageException.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.Common.DAS.Concepts
{
// *** see DTS.Slice.Control.DataScaler.cs ***
public partial class DataScaler
{ ///
/// <summary>
/// A representation of the DataScaler.InvalidExcitationVoltageException class.
/// </summary>
///
public class InvalidExcitationVoltageException : Exception
{
public InvalidExcitationVoltageException() { }
public InvalidExcitationVoltageException(string msg) : base(msg) { }
public InvalidExcitationVoltageException(string msg, System.Exception innerEx) : base(msg, innerEx) { }
protected InvalidExcitationVoltageException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
: base(info, context) { }
}
}
}

View File

@@ -0,0 +1,34 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle( "DTS.DAS.Concepts" )]
[assembly: AssemblyDescription( "" )]
[assembly: AssemblyConfiguration( "" )]
[assembly: AssemblyCompany( "DTS" )]
[assembly: AssemblyProduct( "DTS.DAS.Concepts" )]
[assembly: AssemblyCopyright( "Copyright © DTS 2008" )]
[assembly: AssemblyTrademark( "" )]
[assembly: AssemblyCulture( "" )]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible( false )]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid( "9b6f7402-27d3-4cc9-9ff3-3cfe16e0b429" )]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.06.0081")]
[assembly: AssemblyFileVersion("1.06.0081")]

View File

@@ -0,0 +1,39 @@
/*
* DTS.Common.DAS.Concepts.DAS.Channel.ILevelTriggerable.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
using System;
namespace DTS.Common.DAS.Concepts.DAS.Channel
{
///
/// <summary>
/// Definition of the concept of level triggerability.
/// </summary>
///
public interface ILevelTriggerable
{
/// <summary>
/// created for 14042 Flash Clear turns of excitation for s6
/// this allows for a cached ADC value to be used rather than having to retrieve a sample average
/// when calculating already level triggered
/// </summary>
double? SampleAverageADC { get; set; }
/// <summary>
/// Get/set the "trigger below" threshold. Set to "null" to deactivate.
/// </summary>
double? TriggerBelowThresholdEu { get; set; }
/// <summary>
/// Get/set the "trigger above" threshold. Set to "null" to deactivate.
/// </summary>
double? TriggerAboveThresholdEu { get; set; }
LevelTriggerTypes LevelTriggerType { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
/*
* ITriggerable.cs
*
* Copyright © 2010
* Diversified Technical Systems, Inc.
* All Rights Reserved.
*/
namespace DTS.Common.DAS.Concepts
{ ///
/// <summary>
/// Functional description of a "triggerable" object.
/// </summary>
///
public interface ITriggerable
{
void Trigger();
}
}

View File

@@ -0,0 +1,86 @@
/*
* DTS.Channel.IDecimatable
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of what it means for a DAS channel to be "decimatable".
/// </summary>
///
/// <typeparam name="T">
/// The type of data handled by this DAS channel.
/// </typeparam>
///
public interface IDecimatable<out T>
{
/// <summary>
/// The number of points to be squeezed into a single index point.
/// </summary>
uint PointsPerPoint
{
get;
set;
}
/// <summary>
/// Get/set the decimation method to be applied.
/// </summary>
DecimationMethod DecimationType
{
get;
set;
}
/// <summary>
/// Generate a decimated array using the current <see cref="DTS.DAS.Concepts.DAS.Channel.DecimationMethod"/>.
/// </summary>
///
/// <returns>
/// A decimated array of type "T".
/// </returns>
///
T[ ] ToDecimatedArray( );
/// <summary>
/// Get the value at the specified post-decimation index.
/// </summary>
/// <param name="i"></param>
/// <returns></returns>
///
/// <remarks>
/// Note that implementing this interface implies that the indexing operator should return values from
/// the set decimated according to the PointsPerPoint and Method properties.
/// </remarks>
///
T this[ long i ]
{
get;
}
}
/// <summary>
/// Methods for determining the value of the representative point for decimated sets.
/// </summary>
public enum DecimationMethod
{
/// <summary>
/// Use that value of the PointsPerPoint-th point as the representative value.
/// </summary>
Point,
/// <summary>
/// Use the average of the PointsPerPoint values as the representative value.
/// </summary>
Average,
/// <summary>
/// Use the peak magnitude value of the PointsPerPoint values as the representative value.
/// </summary>
PeakMagnitude,
}
}

View File

@@ -0,0 +1,35 @@
/*
* DAS.Channel.IVoltageInsertionAware.cs
*
* Copyright © 2012
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of the concept of shunt-check awareness.
/// </summary>
public interface IVoltageInsertionAware
{
/// <summary>
/// Get/set this object's <see cref="double"/> measured shunt deflection value.
/// </summary>
double ExpectedGain
{
get;
set;
}
/// <summary>
/// Get/set this object's <see cref="double"/> target shunt deflection value.
/// </summary>
double MeasuredGain
{
get;
set;
}
}
}

View File

@@ -0,0 +1,7 @@
namespace DTS.Common.DAS.Concepts.DAS.Channel
{
public interface ITimestampAware
{
TimestampPartTypes TimestampPartType { get; set; }
}
}

Binary file not shown.

View File

@@ -0,0 +1,14 @@
namespace DTS.Common.DAS.Concepts
{
/// <summary>
/// different possible armstatus
/// </summary>
public enum ArmStatus
{
Disarming,
Disarmed,
Arming,
Armed,
Recording, // Extra statuses (chuck's mail)
}
}

View File

@@ -0,0 +1,11 @@
namespace DTS.Common.DAS.Concepts
{
/// <summary>
/// different possible arm modes
/// </summary>
public enum AvailableArmModes
{
LowPower,
CircularBuffer,
};
}

View File

@@ -0,0 +1,24 @@
/*
* DTS.Common.DAS.Concepts.DAS.Channel.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
using DTS.Common.Utilities;
namespace DTS.Common.DAS.Concepts.DAS
{
/// <summary>
/// Slice control app's internal abstract representation of a DAS channel.
/// </summary>
///
/// <typeparam name="TDataType">
/// The "type" of the data contained by channels of this DAS.
/// </typeparam>
///
public abstract class Channel<TDataType> : Exceptional
{
}
}

View File

@@ -0,0 +1,52 @@
/*
* DTS.Common.DAS.Concepts.DAS.Channel.Data.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
using System.Collections.Generic;
using DTS.Common.Utilities;
namespace DTS.Common.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Representation of a list of channel data.
/// </summary>
public abstract class Data<TDatumType> : ExceptionalList<TDatumType>
{
/// <summary>
/// Initialize an instance of the DTS.Common.DAS.Concepts.DAS.Channel.Data class.
/// </summary>
protected Data()
{
}
/// <summary>
/// Initialize an instance of the DTS.Common.DAS.Concepts.DAS.Channel.Data class.
/// </summary>
///
/// <param name="capacity">
/// The number of elements that the list can initially store.
/// </param>
///
protected Data(int capacity)
: base(capacity)
{
}
/// <summary>
/// Initialize an instance of the DTS.Common.DAS.Concepts.DAS.Channel.Data class.
/// </summary>
///
/// <param name="collection">
/// The collection whose elements are copied to the new list.
/// </param>
///
protected Data(IEnumerable<TDatumType> collection)
: base(collection)
{
}
}
}

View File

@@ -0,0 +1,14 @@
using System;
namespace DTS.Common.DAS.Concepts.DAS.Channel
{
[Flags]
public enum LevelTriggerTypes
{
NONE = 0x00,
OutsideWindow = 0x01,
InsideWindow = 0x02,
LessThan = 0x04,
GreaterThan = 0x08
}
}

View File

@@ -0,0 +1,24 @@
using DTS.Common.Converters;
using System;
using System.ComponentModel;
namespace DTS.Common.DAS.Concepts.DAS.Channel
{
[TypeConverter(typeof(EnumDescriptionTypeConverter))]
[Flags]
public enum TimestampPartTypes
{
[Description("Marker")]
Marker = 1 <<0 ,
[Description("Seconds")]
Seconds_High = 1 << 1,
[Description("Seconds")]
Seconds_Low = 1 << 2,
[Description("Nanoseconds")]
Nanoseconds_High = 1 << 3,
[Description("Nanoseconds")]
Nanoseconds_Low = 1 << 4,
[Description("Reserved")]
Reserved = 1 << 5
}
}

View File

@@ -0,0 +1,52 @@
/*
* DAS.Channel.Data.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
using System.Collections.Generic;
using DTS.Utilities;
namespace DTS.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Representation of a list of channel data.
/// </summary>
public abstract class Data<DatumType> : ExceptionalList<DatumType>
{
/// <summary>
/// Initialize an instance of the DTS.DAS.Concepts.DAS.Channel.Data class.
/// </summary>
protected Data( )
{
}
/// <summary>
/// Initialize an instance of the DTS.DAS.Concepts.DAS.Channel.Data class.
/// </summary>
///
/// <param name="capacity">
/// The number of elements that the list can initially store.
/// </param>
///
protected Data( int capacity )
: base( capacity )
{
}
/// <summary>
/// Initialize an instance of the DTS.DAS.Concepts.DAS.Channel.Data class.
/// </summary>
///
/// <param name="collection">
/// The collection whose elements are copied to the new list.
/// </param>
///
protected Data( IEnumerable<DatumType> collection )
: base( collection )
{
}
}
}

View File

@@ -0,0 +1,86 @@
/*
* DTS.Channel.IDecimatable
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of what it means for a DAS channel to be "decimatable".
/// </summary>
///
/// <typeparam name="T">
/// The type of data handled by this DAS channel.
/// </typeparam>
///
public interface IDecimatable<out T>
{
/// <summary>
/// The number of points to be squeezed into a single index point.
/// </summary>
uint PointsPerPoint
{
get;
set;
}
/// <summary>
/// Get/set the decimation method to be applied.
/// </summary>
DecimationMethod DecimationType
{
get;
set;
}
/// <summary>
/// Generate a decimated array using the current <see cref="DTS.DAS.Concepts.DAS.Channel.DecimationMethod"/>.
/// </summary>
///
/// <returns>
/// A decimated array of type "T".
/// </returns>
///
T[ ] ToDecimatedArray( );
/// <summary>
/// Get the value at the specified post-decimation index.
/// </summary>
/// <param name="i"></param>
/// <returns></returns>
///
/// <remarks>
/// Note that implementing this interface implies that the indexing operator should return values from
/// the set decimated according to the PointsPerPoint and Method properties.
/// </remarks>
///
T this[ long i ]
{
get;
}
}
/// <summary>
/// Methods for determining the value of the representative point for decimated sets.
/// </summary>
public enum DecimationMethod
{
/// <summary>
/// Use that value of the PointsPerPoint-th point as the representative value.
/// </summary>
Point,
/// <summary>
/// Use the average of the PointsPerPoint values as the representative value.
/// </summary>
Average,
/// <summary>
/// Use the peak magnitude value of the PointsPerPoint values as the representative value.
/// </summary>
PeakMagnitude,
}
}

View File

@@ -0,0 +1,25 @@
/*
* DAS.Channel.IEngineeringUnitAware.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of the concept of engineering unit awareness.
/// </summary>
public interface IEngineeringUnitAware
{
/// <summary>
/// Get/set this object's engineering unit description <see cref="string"/>.
/// </summary>
string EngineeringUnits
{
get;
set;
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* DAS.Channel.IInversionAware.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of the concept of inversion awareness.
/// </summary>
public interface IInversionAware
{ ///
/// <summary>
/// Get/set this object's inversion state <see cref="bool"/>.
/// </summary>
///
bool IsInverted
{
get;
set;
}
}
public interface ILinearized
{
LinearizationFormula LinearizationFormula
{
get;
set;
}
}
}

View File

@@ -0,0 +1,25 @@
/*
* DAS.Channel.IIsoCodeAware.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of the concept of ISO code awareness.
/// </summary>
public interface IIsoCodeAware
{
/// <summary>
/// Get/set this object's IsoCode <see cref="string"/>.
/// </summary>
string IsoCode
{
get;
set;
}
}
}

View File

@@ -0,0 +1,41 @@
/*
* DAS.Channel.ILevelTriggerable.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
using System;
namespace DTS.DAS.Concepts.DAS.Channel
{
///
/// <summary>
/// Definition of the concept of level triggerability.
/// </summary>
///
public interface ILevelTriggerable
{
/// <summary>
/// Get/set the "trigger below" threshold. Set to "null" to deactivate.
/// </summary>
double? TriggerBelowThresholdEu { get; set; }
/// <summary>
/// Get/set the "trigger above" threshold. Set to "null" to deactivate.
/// </summary>
double? TriggerAboveThresholdEu { get; set; }
LevelTriggerTypes LevelTriggerType { get; set; }
}
[Flags]
public enum LevelTriggerTypes
{
NONE = 0x00,
OutsideWindow = 0x01,
InsideWindow = 0x02,
LessThan = 0x04,
GreaterThan = 0x08
}
}

View File

@@ -0,0 +1,25 @@
/*
* DAS.Channel.ISerialNumberAware.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of the concept of serial number awareness.
/// </summary>
public interface ISerialNumberAware
{
/// <summary>
/// Get/set this object's serial number <see cref="string"/>.
/// </summary>
string SerialNumber
{
get;
set;
}
}
}

View File

@@ -0,0 +1,24 @@
/*
* DAS.Channel.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
using DTS.Utilities;
namespace DTS.DAS.Concepts.DAS
{
/// <summary>
/// Slice control app's internal abstract representation of a DAS channel.
/// </summary>
///
/// <typeparam name="DataType">
/// The "type" of the data contained by channels of this DAS.
/// </typeparam>
///
public abstract class Channel<DataType> : Exceptional
{
}
}

View File

@@ -0,0 +1,57 @@
/*
* DAS.Channel.IShuntAware.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of the concept of shunt-check awareness.
/// </summary>
public interface IShuntAware
{
/// <summary>
/// Get/set this object's <see cref="double"/> measured shunt deflection value.
/// </summary>
double MeasuredShuntDeflectionMv
{
get;
set;
}
/// <summary>
/// Get/set this object's <see cref="double"/> target shunt deflection value.
/// </summary>
double TargetShuntDeflectionMv
{
get;
set;
}
}
/// <summary>
/// Definition of the concept of calsignal-check awareness.
/// </summary>
public interface ICalSignalAware
{
/// <summary>
/// Get/set this object's <see cref="double"/> measured shunt deflection value.
/// </summary>
double MeasuredCalSignalMv
{
get;
set;
}
/// <summary>
/// Get/set this object's <see cref="double"/> target shunt deflection value.
/// </summary>
double TargetCalSignalMv
{
get;
set;
}
}
}

View File

@@ -0,0 +1,171 @@
/*
* DAS.Id.cs
* DTM - why does this class exist? it's only encapsulating a string
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
using System;
using DTS.Common.Utilities;
namespace DTS.Common.DAS.Concepts.DAS
{
/// <summary>
/// Representation of the DTS.Common.DAS.Concepts.DAS.Id type.
/// why does this class even exist?
/// </summary>
public sealed class Id : Exceptional, IComparable<Id>, IEquatable<Id>
{
/// <summary>
/// The Thing In Itself.
/// </summary>
private readonly string value;
/// <summary>
/// Initialize an instance of the DTS.Common.DAS.Concepts.DAS.Id class.
/// </summary>
public Id(string value)
{
this.value = value;
}
/// <summary>
/// Allow DTS.Common.DAS.Concepts.DAS.Ids to be implicitly converted to strings.
/// </summary>
///
/// <param name="id">
/// The <see cref="Id"/> id to be stringified.
/// </param>
///
/// <returns>
/// The <see cref="string"/> value of this DTS.Common.DAS.Concepts.DAS.Id.
/// </returns>
///
public static implicit operator string(Id id)
{
return id.ToString();
}
/// <summary>
/// Allow strings to be implicitly converted to DTS.Slice.Control.DAS.Ids.
/// </summary>
///
/// <param name="id">
/// The <see cref="string"/> value to be DTS.Slice.Control.DAS.Id-ified.
/// </param>
///
/// <returns>
/// The <see cref="Id"/> equivalent to the specified string.
/// </returns>
///
public static implicit operator Id(string id)
{
return new Id(id);
}
public override bool Equals(object obj)
{
if (obj is Id that) { return Equals(that); }
return string.Compare(ToString(), obj.ToString(), StringComparison.OrdinalIgnoreCase) == 0;
}
/// <summary>
/// Determine whether this object instance and the specified object instance are equal.
/// </summary>
///
/// <param name="that">
/// The <see cref="Id"/> to be compared to this object instance.
/// </param>
///
/// <returns>
/// <see cref="bool"/> true if this object is equal to the specified object; false otherwise.
/// </returns>
///
public bool Equals(Id that)
{
if (value == that.value) { return true; }
if (null == value) { return false; }
if (null == that.value) { return false; }
return value.Equals(that.value, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// Generate a comparison value between this object and another of it's type.
/// </summary>
///
/// <param name="that">
/// The <see cref="Id"/> to which this one is to be compared.
/// </param>
///
/// <returns>
/// An <see cref="int"/> value expressing the "similarity" between this object
/// and the one specified.
/// </returns>
///
public int CompareTo(Id that)
{
return Compare(this, that);
}
/// <summary>
/// Generate a string representation of this class.
/// </summary>
///
/// <returns>
/// The <see cref="string"/> representation of this object.
/// </returns>
///
public override string ToString()
{
return value;
}
/// <summary>
/// Generate a hash code for this instance.
/// </summary>
///
/// <returns>
/// The <see cref="int"/> hash code for this instance.
/// </returns>
///
public override int GetHashCode()
{
return value?.GetHashCode() ?? 0;
}
public static bool operator ==(Id left, Id right)
{
if (ReferenceEquals(left, null))
{
return ReferenceEquals(right, null);
}
return left.Equals(right);
}
public static int Compare(Id left, Id right)
{
if (left == right) { return 0; }
if (null == right) { return 1; }
if (null == left) { return -1; }
return string.Compare(left.ToString(), right.ToString(), StringComparison.OrdinalIgnoreCase);
}
public static bool operator >= (Id left, Id right)
{
return Compare(left, right) >= 0;
}
public static bool operator >(Id left, Id right)
{
return Compare(left, right) > 0;
}
public static bool operator <= (Id left, Id right)
{
return Compare(left, right) <= 0;
}
public static bool operator <(Id left, Id right)
{
return Compare(left, right) < 0;
}
public static bool operator !=(Id left, Id right)
{
return !(left == right);
}
}
}

View File

@@ -0,0 +1,35 @@
/*
* DAS.Channel.IVoltageInsertionAware.cs
*
* Copyright © 2012
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of the concept of shunt-check awareness.
/// </summary>
public interface IVoltageInsertionAware
{
/// <summary>
/// Get/set this object's <see cref="double"/> measured shunt deflection value.
/// </summary>
double ExpectedGain
{
get;
set;
}
/// <summary>
/// Get/set this object's <see cref="double"/> target shunt deflection value.
/// </summary>
double MeasuredGain
{
get;
set;
}
}
}

View File

@@ -0,0 +1,23 @@
namespace DTS.Common.DAS.Concepts.DAS
{
/// <summary>
/// Methods for determining the value of the representative point for decimated sets.
/// </summary>
public enum DecimationMethod
{
/// <summary>
/// Use that value of the PointsPerPoint-th point as the representative value.
/// </summary>
Point,
/// <summary>
/// Use the average of the PointsPerPoint values as the representative value.
/// </summary>
Average,
/// <summary>
/// Use the peak magnitude value of the PointsPerPoint values as the representative value.
/// </summary>
PeakMagnitude,
}
}

View File

@@ -0,0 +1,146 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.21022</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{AE3987F7-C4C6-40FB-A353-1A2DADEF7A9A}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DTS.DAS.Concepts</RootNamespace>
<AssemblyName>DTS.DAS.Concepts</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<OldToolsVersion>3.5</OldToolsVersion>
<TargetFrameworkProfile />
<SccProjectName>
</SccProjectName>
<SccLocalPath>
</SccLocalPath>
<SccAuxPath>
</SccAuxPath>
<SccProvider>
</SccProvider>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>
</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="ArmStatus.cs" />
<Compile Include="AvailableArmModes.cs" />
<Compile Include="DAS\Channel\TimestampPartTypes.cs" />
<Compile Include="Interfaces\DAS\Channel\ICalSignalAware.cs" />
<Compile Include="DAS\Channel\LevelTriggerTypes.cs" />
<Compile Include="DAS\DecimationMethod.cs" />
<Compile Include="DAS\Channel\Channel.cs" />
<Compile Include="DAS\Channel\Data.cs" />
<Compile Include="Interfaces\DAS\Channel\ITimestampAware.cs" />
<Compile Include="Interfaces\DAS\Channel\IDecimatable.cs" />
<Compile Include="Interfaces\DAS\Channel\IEngineeringUnitAware.cs" />
<Compile Include="Interfaces\DAS\Channel\IInversionAware.cs" />
<Compile Include="Interfaces\DAS\Channel\IIsoCodeAware.cs" />
<Compile Include="Interfaces\DAS\Channel\ILevelTriggerable.cs" />
<Compile Include="Interfaces\DAS\Channel\ISerialNumberAware.cs" />
<Compile Include="Interfaces\DAS\Channel\IShuntAware.cs" />
<Compile Include="DAS\DAS.Id.cs" />
<Compile Include="Interfaces\DAS\Channel\IVoltageInsertAware.cs" />
<Compile Include="Interfaces\DAS\Channel\ILinearized.cs" />
<Compile Include="DataScaler.cs" />
<Compile Include="DataScaler.InvalidExcitationVoltageException.cs" />
<Compile Include="Interfaces\IArmable.cs" />
<Compile Include="Interfaces\ICalibratable.cs" />
<Compile Include="Interfaces\IDataCollectionEnabled.cs" />
<Compile Include="Interfaces\IDownloadEnabled.cs" />
<Compile Include="Interfaces\IGpioEnabled.cs" />
<Compile Include="Interfaces\ILargeDataAware.cs" />
<Compile Include="Interfaces\IRealtimeable.cs" />
<Compile Include="Interfaces\ITriggerable.cs" />
<Compile Include="Properties\AssemblyInfo.cs">
<CustomToolNamespace>DTS.Common.DAS.Concepts</CustomToolNamespace>
</Compile>
<Compile Include="ShuntModeType.cs" />
<Compile Include="Test\Module\Channel\Sensor\ExcitationVoltage.cs" />
<Compile Include="Test\Module\Channel\Sensor\SensorUnits.cs" />
<Compile Include="Test\Module\RecordingMode.cs" />
<Compile Include="Test\Module\TiltAxes.cs" />
<Compile Include="TsrEvent.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="LinearizationFormula.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DTS.Common.SettingsDB\DTS.Common.Settings.csproj">
<Project>{61017104-d8ee-41d1-b9ca-dad863ff78b2}</Project>
<Name>DTS.Common.Settings</Name>
</ProjectReference>
<ProjectReference Include="..\DTS.Common.Utilities\DTS.Common.Utilities.csproj">
<Project>{d6da1b74-c711-43c2-91b1-1908a8d04dbf}</Project>
<Name>DTS.Common.Utilities</Name>
</ProjectReference>
<ProjectReference Include="..\DTS.Common\DTS.Common.csproj">
<Project>{f7a0804f-61a4-40ae-83d0-f1137622b592}</Project>
<Name>DTS.Common</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="Design\DTS.Common.DAS.ConceptsClassDiagram.cd" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,29 @@
/*
* DataScaler.InvalidExcitationVoltageException.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.Common.DAS.Concepts
{
// *** see DTS.Slice.Control.DataScaler.cs ***
public partial class DataScaler
{ ///
/// <summary>
/// A representation of the DataScaler.InvalidExcitationVoltageException class.
/// </summary>
///
public class InvalidExcitationVoltageException : Exception
{
public InvalidExcitationVoltageException() { }
public InvalidExcitationVoltageException(string msg) : base(msg) { }
public InvalidExcitationVoltageException(string msg, System.Exception innerEx) : base(msg, innerEx) { }
protected InvalidExcitationVoltageException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
: base(info, context) { }
}
}
}

View File

@@ -0,0 +1,919 @@
/*
* DataScaler.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
using System;
using DTS.Common.Classes.Sensors;
using DTS.Common.Constant;
using DTS.Common.Enums;
using DTS.Common.Enums.Sensors;
using DTS.Common.Utilities;
using DTS.Common.Utilities.DotNetProgrammingConstructs;
namespace DTS.Common.DAS.Concepts
{
/// <summary>
/// A class to contain properties and methods associated with data scaling.
/// </summary>
public partial class DataScaler : Exceptional
{
public double UserOffsetEU { get; set; }
public double Multiplier { get; set; } = 1D;
private DTS.Common.Classes.Sensors.LinearizationFormula _linearizationEquation;
public void SetLinearizationFormula(DTS.Common.Classes.Sensors.LinearizationFormula equation) { _linearizationEquation = equation; }
public DTS.Common.Classes.Sensors.LinearizationFormula GetLinearizationFormula()
{
return _linearizationEquation ?? (_linearizationEquation = new DTS.Common.Classes.Sensors.LinearizationFormula());
}
/// <summary>
/// Get the ADC->EU scaling factor (EU/mV)
/// </summary>
private double AdcToEuScalingFactor
{
get
{
try
{
if (null != _adcToEuScalingFactor) return (double)_adcToEuScalingFactor;
if (UseEUScaleFactors)
{
_adcToEuScalingFactor = (ScaleFactorEU * UnitConversion)
* (BasedOnOutputAtCapacity ? CapacityOutputIsBasedOn : 1.0)
* (IsInverted ? -1 : 1);
}
else
{
_adcToEuScalingFactor = (ScaleFactorMv * UnitConversion
/ (ProportionalToExcitation && SensitivityUnits != SensorConstants.SensUnits.mVperEU
? MvPerEu * GetExcitationVoltage() : MvPerEu))
* (BasedOnOutputAtCapacity ? CapacityOutputIsBasedOn : 1.0)
* (IsInverted ? -1.0 : 1.0);
}
return (double)_adcToEuScalingFactor;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem computing ADC->EU scaling factor", ex);
}
}
}
private double? _adcToEuScalingFactor = null;
/// <summary>
/// the ADCtoEUScalingFactor is a cached value
/// and isn't recalculated once it's calculated
/// this method clears the cached value so that the next time
/// it is used the value is recalculated
/// this should be done if the sensitivity or the scalefactors change
/// </summary>
public void ClearADCToEuScalingFactor()
{
_adcToEuScalingFactor = null;
}
/// <summary>
/// Get the mV/ADC scale factor
/// </summary>
private double AdcToMvScalingFactor
{
get
{
try
{
if (null == _adcToMvScalingFactor)
_adcToMvScalingFactor = ScaleFactorMv;
return (double)_adcToMvScalingFactor;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem computing ADC->MV scaling factor", ex);
}
}
}
private double? _adcToMvScalingFactor;
/// <summary>
/// set the mv/ADC scale factor for this channel.
/// </summary>
private double ScaleFactorMv
{
//we disable this, we don't want them doing calculations, we want them
//to use us for calculations ...
get => _scaleFactorMv.Value;
set
{
_scaleFactorMv.Value = value;
_adcToEuScalingFactor = null;
CalculateInitialOffset();
}
}
private double ScaleFactorEU
{
//we disable this, we don't want them doing calculations, we want them
//to use us for calculations ...
get => _scaleFactorEU.Value;
set { _scaleFactorEU.Value = value; _adcToEuScalingFactor = null; }
}
private bool UseEUScaleFactors
{
get => _useEUScaleFactors.Value;
set => _useEUScaleFactors.Value = value;
}
/// <summary>
/// Sets the scale factor. (mV/ADC)
/// </summary>
/// <param name="value"></param>
public void SetScaleFactorMv(double value) { ScaleFactorMv = value; }
public void SetScaleFactorEU(double value) { ScaleFactorEU = value; }
public void SetUseEUScaleFactors(bool value) { UseEUScaleFactors = value; }
private DigitalInputScaleMultiplier _digitalMultiplier = new DigitalInputScaleMultiplier();
public void SetDigitalMultiplier(DigitalInputScaleMultiplier multiplier) { _digitalMultiplier = multiplier; }
public DigitalInputScaleMultiplier GetDigitalMultiplier()
{
return _digitalMultiplier ?? (_digitalMultiplier = new DigitalInputScaleMultiplier());
}
public bool Digital { get; set; }
public bool DigitalOutput { get; set; }
/// <summary>
/// returns the conversion factor from ADC to mV
/// </summary>
/// <returns>mV/ADC</returns>
public double GetScaleFactorMv() { return ScaleFactorMv; }
private readonly Property<double> _scaleFactorMv
= new Property<double>(
typeof(DataScaler).Namespace + ".DataScaler.ScaleFactorMv",
0.0,
false
);
public double GetScaleFactorEU() { return ScaleFactorEU; }
private readonly Property<double> _scaleFactorEU
= new Property<double>(
typeof(DataScaler).Namespace + ".DataScaler.ScaleFactorEU",
0.0,
false
);
private readonly Property<bool> _useEUScaleFactors
= new Property<bool>(
typeof(DataScaler).Namespace + ".DataScaler.UseEUScaleFactors",
false,
true
);
public double UnitConversion { get; set; } = 1D;
/// <summary>
/// set the sensitivity mV/EU factor for this channel.
/// </summary>
private double MvPerEu
{
//we disable the get, we don't want outside code doing calculations,
//we want them to use this class to do calculations
get => _mvPerEu.Value;
set => _mvPerEu.Value = value;
}
private readonly Property<double> _mvPerEu
= new Property<double>(
typeof(DataScaler).Namespace + ".DataScaler.MvPerEu",
1.0, // Yes, it's initialized on purpose. In case this isn't an analog channel. Normally
true // we'd leave it uninitialized and trap the error if someone tries to use it, but our
); // binary serialization format always expects an EU value from all channels, so...
/// <summary>
/// sets mV per EU scale factor
/// </summary>
/// <param name="value"></param>
public void SetMvPerEu(double value) { MvPerEu = value; }
public double GetMvPerEu() { return MvPerEu; }
/// <summary>
/// Get/set the descriptor indiciating whether or not this channel is
/// based on output at capacity.
/// </summary>
public bool BasedOnOutputAtCapacity
{
get => _basedOnOutputAtCapacity.Value;
set => _basedOnOutputAtCapacity.Value = value;
}
private readonly Property<bool> _basedOnOutputAtCapacity
= new Property<bool>(
typeof(DataScaler).Namespace + ".DataScaler.BasedOnOutputAtCapacity",
false,
true
);
/// <summary>
/// Get/set the capacity output is based on value.
/// </summary>
public double CapacityOutputIsBasedOn
{
get => _capacityOutputIsBasedOn.Value;
set
{
if (0 < value)
{
_capacityOutputIsBasedOn.Value = value;
}
else
{
_capacityOutputIsBasedOn.UnInitialize();
}
}
}
private readonly Property<double> _capacityOutputIsBasedOn
= new Property<double>(
typeof(DataScaler).Namespace + ".DataScaler.CapacityOutputIsBasedOn",
1.000,
true
);
public SensorConstants.SensUnits SensitivityUnits { get; set; } = SensorConstants.SensUnits.NONE;
/// <summary>
/// Get/set the descriptor indiciating whether or not this channel is
/// proportional to excitation.
/// </summary>
public bool ProportionalToExcitation
{
get => _proportionalToExcitation.Value;
set => _proportionalToExcitation.Value = value;
}
private readonly Property<bool> _proportionalToExcitation
= new Property<bool>(
typeof(DataScaler).Namespace + ".DataScaler.ProportionalToExcitation",
false,
true
);
/// <summary>
/// Get the <see cref="double"/> excitation voltage value.
/// </summary>
public double GetExcitationVoltage()
{
try
{
//FB 18727 use measured excitation if the setting is true & ExcitationVoltage is 2 volt
if (NominalExcitationVoltage == ExcitationVoltageOptions.ExcitationVoltageOption.Volt2 && Settings.SettingsDB.GetGlobalValueBool(Constants.UseMeasuredExcitation, false))
{
return _measuredExcitationVoltage.IsInitialized ? MeasuredExcitationVoltage : Test.Module.Channel.Sensor.GetExcitationVoltageMagnitudeFromEnum(NominalExcitationVoltage);
}
else
{
if (_factoryExcitationVoltage.IsInitialized) return FactoryExcitationVoltage;
return _measuredExcitationVoltage.IsInitialized ? MeasuredExcitationVoltage : Test.Module.Channel.Sensor.GetExcitationVoltageMagnitudeFromEnum(NominalExcitationVoltage);
}
}
catch (System.Exception ex)
{
throw new Exception("encountered problem determining excitation voltage", ex);
}
}
/// <summary>
/// Get/set the excitation voltage for this channel.
/// </summary>
public ExcitationVoltageOptions.ExcitationVoltageOption NominalExcitationVoltage
{
get => _excitationVoltage.Value == ExcitationVoltageOptions.ExcitationVoltageOption.Undefined
? throw new InvalidExcitationVoltageException(
"cannot use undefined excitation voltage to calculate scaling factor")
: _excitationVoltage.Value;
set => _excitationVoltage.Value = value;
}
private readonly Property<ExcitationVoltageOptions.ExcitationVoltageOption> _excitationVoltage
= new Property<ExcitationVoltageOptions.ExcitationVoltageOption>(
typeof(DataScaler).Namespace + ".DataScaler.ExcitationVoltage",
ExcitationVoltageOptions.ExcitationVoltageOption.Volt5,
false
);
public bool FactoryExcitationVoltageValid => _factoryExcitationVoltage.IsInitialized;
/// <summary>
/// Get/set the factory excitation voltage value.
/// </summary>
public double FactoryExcitationVoltage
{
get => _factoryExcitationVoltage.Value;
set
{
if (0 < value)
{
_factoryExcitationVoltage.Value = value;
}
else
{
_factoryExcitationVoltage.UnInitialize();
}
}
}
private readonly Property<double> _factoryExcitationVoltage
= new Property<double>(
typeof(DataScaler).Namespace + ".DataScaler.FactoryExcitationVoltage",
0.0,
false
);
public bool MeasuredExcitationVoltageValid => _measuredExcitationVoltage.IsInitialized;
/// <summary>
/// Get/set the measured excitation voltage value.
/// </summary>
public double MeasuredExcitationVoltage
{
get => _measuredExcitationVoltage.Value;
set => _measuredExcitationVoltage.Value = value;
}
private readonly Property<double> _measuredExcitationVoltage
= new Property<double>(
typeof(DataScaler).Namespace + ".DataScaler.MeasuredExcitationVoltage",
0.0,
false
);
/// <summary>
/// Get/set channel inversion status.
/// </summary>
public bool IsInverted
{
get => _isInverted.Value;
set => _isInverted.Value = value;
}
private readonly Property<bool> _isInverted
= new Property<bool>(
typeof(DataScaler).Namespace + ".DataScaler.IsInverted",
false,
false
);
private double _initialOffsetmVinADC = 0D;
private double _initialOffsetEU = 0D;
private InitialOffset _initialOffset = new InitialOffset();
public void SetInitialOffset(InitialOffset offset)
{
_initialOffset = offset;
CalculateInitialOffset();
}
public void SetInitialOffset(string offset)
{
_initialOffset.FromDbSerializeString(offset);
CalculateInitialOffset();
}
private void CalculateInitialOffset()
{
switch (_initialOffset.Form)
{
case InitialOffsetTypes.FRONTAL:
case InitialOffsetTypes.LHS:
case InitialOffsetTypes.RHS:
case InitialOffsetTypes.EU: InitialEU = _initialOffset.EU; break;
case InitialOffsetTypes.EUAtMV: //calculated INSIDE the EU equation
{
InitialEU = 0;
//only true if we are using zeromethod = none
if (ZeroMethodType == ZeroMethodType.None && _scaleFactorMv.IsValueInitialized)
{
_initialOffsetEU = _initialOffset.EU;
_initialOffsetmVinADC = ScaleFactorMv != 0 ? _initialOffset.MV / ScaleFactorMv : 0D;
}
else
{
_initialOffsetmVinADC = 0D;
_initialOffsetEU = 0D;
}
}
break;
default:
_initialOffsetmVinADC = 0D;
_initialOffsetEU = 0D;
InitialEU = 0D;
break;
}
}
public double GetCorrectedADC(short adc, bool convertUnsigned = false)
{
if (!Digital // Never correct for non-Digital
|| (Digital && DigitalInputs.DisplaySPDADC // Don't correct SPD if we're showing RAW ADC
&& (adc != short.MaxValue && adc != short.MinValue)) // ...unless this is an older data set
|| (Digital && ScaleFactorMv >= 0)) // Don't correct for G5 DI or TDAS DIM
{
if (convertUnsigned)
{
var unsigned = (ushort)(adc - 0x8000);
return Convert.ToDouble(unsigned);
}
return Convert.ToDouble(adc);
}
var breakPoint = DigitalInputs.ConstantCurrentBreakPoint;
if (DigitalMode == DigitalInputModes.THL || DigitalMode == DigitalInputModes.TLH)
{
breakPoint = DigitalInputs.VoltageInputBreakPoint;
}
//handle digital sensors
var bAboveBreak = adc > breakPoint;
if ((short.MaxValue == adc || short.MinValue == adc)
&& (DigitalMode == DigitalInputModes.CCNC || DigitalMode == DigitalInputModes.CCNO)) // Handle pre-14435 change digital data)
{
//14435 Store SPD data as analog, but show in viewers as digital, expose Digital break point
//SLICE2 has inverted ADC, so we need to swap the direction of above/below
bAboveBreak = !bAboveBreak;
}
return bAboveBreak ? Convert.ToDouble(short.MaxValue) : Convert.ToDouble(short.MinValue);
}
public double GetEU(short adc)
{
try { return GetEU(Convert.ToDouble(adc)); }
catch (System.Exception ex)
{
Utilities.Logging.APILogger.Log(ex);
return double.NaN;
}
}
/// <summary>
/// represents the old concept of initial eu, just a value added to the end of the eu equation.
/// </summary>
private double InitialEU = 0D;
/// <summary>
/// returns the Initial EU property - this is the old concept of EU, it's just a value added
/// to the end of the eu equation ...
/// </summary>
public double GetInitialEU() => InitialEU;
private ZeroMethodType _zeroMethodType = ZeroMethodType.None;
public ZeroMethodType ZeroMethodType
{
get => _zeroMethodType;
set
{
_zeroMethodType = value;
CalculateInitialOffset();
}
}
/// <summary>
/// returns eu given a mV value
/// originally written for
/// 14700 Diagnostic offsets should show in EU also
/// ordinarily we go from ADC to mV or ADC to EU, but never mV to EU
/// however SLICE reads initial offsets in terms of mV
/// </summary>
/// <param name="mV"></param>
/// <returns></returns>
public double GetEUFromMv(double mV)
{
//first intercept the process if we have a non linear channel
if (null != _linearizationEquation && _linearizationEquation.IsValid())
{
double eu = 0;
if (UseEUScaleFactors)
{
for (var i = 0; i < _linearizationEquation.PolynomialCoefficients.Length && i < _linearizationEquation.PolynomialExponents.Length; i++)
{
eu += _linearizationEquation.GetCoefficient(i) * Math.Pow(mV, _linearizationEquation.PolynomialExponents[i]);
}
}
else
{
//FB 29728 pass parameter to determine is proportional
eu = _linearizationEquation.GetLinearizedValue(mV, GetExcitationVoltage(), ProportionalToExcitation) * (IsInverted ? -1D : 1D);
var zero = double.NaN;
//if datazeroleveladc is zero, then we shouldn't applying zeroing as it will give bad data
//however if it is non zero, go ahead and apply it
switch (_linearizationEquation.NonLinearStyle)
{
//the 0MMmV knows where zero mm is by default and doesn't need to calculate a zero value
//5512 mV for 0MM [IRTRACC] sometimes makes funny offset.
case NonLinearStyles.IRTraccZeroMMmV:
// IRTRACC with Cal Factor is always zero method of NONE
// http://manuscript.dts.local/f/cases/resolve/17783/IRTRACC-w-CalFactor-should-always-process-as-Zero-Method-NONE
case NonLinearStyles.IRTraccCalFactor:
zero = double.NaN;
break;
default:
//http://fogbugz/fogbugz/default.asp?11399 dont set zero if method is NONE
if (0 != DataZeroLevelADC && ZeroMethodType != ZeroMethodType.None) { zero = _linearizationEquation.GetLinearizedValue(GetMv(DataZeroLevelADC), GetExcitationVoltage()) * (IsInverted ? -1D : 1D); }
break;
}
if (double.IsNaN(zero) || double.IsNegativeInfinity(zero) || double.IsPositiveInfinity(zero)) { zero = 0D; }
eu = eu - zero;
switch (_linearizationEquation.NonLinearStyle)
{
case NonLinearStyles.IRTraccAverageOverTime:
case NonLinearStyles.IRTraccDiagnosticsZero:
case NonLinearStyles.IRTraccManual:
case NonLinearStyles.IRTraccZeroMMmV:
eu *= -1D;
break;
}
}
return eu + InitialEU + UserOffsetEU;
}
//handle analog sensors
//note that a negative scale factor results in a negative MvPerEU
//however, the EU output needs to consider polarity as well, IsInverted shows only the value of polarity, so
//we can use it here
if (!Digital)
{
//14918 Init offset displayed in EU during diag looks incorrect for EU@mV sensor
//Calculate Offset is what is setting the initial offset, but for EU@mV
//we need to make sure we compensate, ordinarily this is dont throug the initialoffsetmvinadc
//but this route wasn't taking it into consideration, it does now.
return (mV * (IsInverted ? -1 : 1)) / (MvPerEu * (ProportionalToExcitation ? GetExcitationVoltage() : 1)) *
Multiplier +
InitialEU + UserOffsetEU + _initialOffsetEU - _initialOffsetmVinADC * ScaleFactorMv;
}
return double.NaN;
}
//returns EU given an ADC value (taking into consideration software zeroing and initial EU)
public double GetEU(double adc)
{
// Correct ADC for DIM Data
var correctedadc = adc;
//GetCorrectedADC, will coalesce adc to a short, so avoid calling it if we don't need to
if (Digital) { correctedadc = GetCorrectedADC(Convert.ToInt16(adc)); }
//first intercept the process if we have a non linear channel
if (null != _linearizationEquation && _linearizationEquation.IsValid())
{
double eu = 0;
if (UseEUScaleFactors)
{
var mV = (correctedadc - DataZeroLevelADC) * ScaleFactorMv / MeasuredExcitationVoltage;
for (var i = 0; i < _linearizationEquation.PolynomialCoefficients.Length && i < _linearizationEquation.PolynomialExponents.Length; i++)
{
eu += _linearizationEquation.GetCoefficient(i) * Math.Pow(mV, _linearizationEquation.PolynomialExponents[i]);
}
}
else
{
eu = _linearizationEquation.GetLinearizedValue(GetMv(correctedadc), GetExcitationVoltage()) * (IsInverted ? -1D : 1D);
var zero = double.NaN;
//if datazeroleveladc is zero, then we shouldn't applying zeroing as it will give bad data
//however if it is non zero, go ahead and apply it
switch (_linearizationEquation.NonLinearStyle)
{
//the 0MMmV knows where zero mm is by default and doesn't need to calculate a zero value
//5512 mV for 0MM [IRTRACC] sometimes makes funny offset.
case NonLinearStyles.IRTraccZeroMMmV:
// IRTRACC with Cal Factor is always zero method of NONE
//http://manuscript.dts.local/f/cases/resolve/17783/IRTRACC-w-CalFactor-should-always-process-as-Zero-Method-NONE
case NonLinearStyles.IRTraccCalFactor:
zero = double.NaN;
break;
default:
//http://fogbugz/fogbugz/default.asp?11399 dont set zero if method is NONE
if (0 != DataZeroLevelADC && ZeroMethodType != ZeroMethodType.None) { zero = _linearizationEquation.GetLinearizedValue(GetMv(DataZeroLevelADC), GetExcitationVoltage()) * (IsInverted ? -1D : 1D); }
break;
}
if (double.IsNaN(zero) || double.IsNegativeInfinity(zero) || double.IsPositiveInfinity(zero)) { zero = 0D; }
eu = eu - zero;
switch (_linearizationEquation.NonLinearStyle)
{
case NonLinearStyles.IRTraccAverageOverTime:
case NonLinearStyles.IRTraccDiagnosticsZero:
case NonLinearStyles.IRTraccManual:
case NonLinearStyles.IRTraccZeroMMmV:
eu *= -1D;
break;
}
}
return eu * Multiplier + InitialEU + UserOffsetEU;
}
//handle analog sensors
if (!Digital)
{
var eu = (correctedadc - DataZeroLevelADC - _initialOffsetmVinADC) * Multiplier * AdcToEuScalingFactor +
InitialEU + UserOffsetEU + _initialOffsetEU;
return eu;
}
var breakPoint = DigitalInputs.ConstantCurrentBreakPoint;
if (DigitalMode == DigitalInputModes.THL || DigitalMode == DigitalInputModes.TLH)
{
breakPoint = DigitalInputs.VoltageInputBreakPoint;
}
//handle digital sensors
var bAboveBreak = correctedadc > breakPoint;
if (ScaleFactorMv < 0)
{
switch (DigitalMode)
{
case DigitalInputModes.CCNC:
case DigitalInputModes.CCNO:
//14435 Store SPD data as analog, but show in viewers as digital, expose Digital break point
//SLICE2 has inverted ADC, so we need to swap the direction of above/below
bAboveBreak = !bAboveBreak;
break;
default:
//Do Nothing
break;
}
}
if (bAboveBreak)
{
switch (DigitalMode)
{
case DigitalInputModes.CCNC:
return _digitalMultiplier.DefaultValue;
case DigitalInputModes.CCNO:
return _digitalMultiplier.ActiveValue;
case DigitalInputModes.THL:
return _digitalMultiplier.DefaultValue;
case DigitalInputModes.TLH:
return _digitalMultiplier.ActiveValue;
default: return _digitalMultiplier.ActiveValue;
}
}
switch (DigitalMode)
{
case DigitalInputModes.CCNC:
return _digitalMultiplier.ActiveValue;
case DigitalInputModes.CCNO:
return _digitalMultiplier.DefaultValue;
case DigitalInputModes.THL:
return _digitalMultiplier.ActiveValue;
case DigitalInputModes.TLH:
return _digitalMultiplier.DefaultValue;
default: return _digitalMultiplier.DefaultValue;
}
}
public DigitalInputModes DigitalMode { get; set; } = DigitalInputModes.CCNC;
/// <summary>
/// zeroMvInADC is the concept of ADC when 0mV is injected into the DAC
/// this is used with TDAS equipment to determine and remove offset on some
/// sensors
/// this value will be removed in SLICEWare to remove any measured offset present not from the sensor
/// DataZeroLevel also is an ADC value removed when converting to ADC (typically from software zeroing like window averaging)
/// however I keep it separate to allow the factor to be applied or not to ADC/EU/MV, while DataZeroLevel is only applied to EU
/// [however DataZeroLevel is ZeroMvInADC when zeroing method is "use 0mV", so we only need to apply ZeroMvInADC to mV scaling]
/// </summary>
private readonly Property<int> _zeroMvInADC = new Property<int>(
typeof(DataScaler).Namespace + ".DataScaler.ZeroMVInADC",
0,
true);
public int ZeroMvInADC
{
get => _zeroMvInADC.Value;
private set => _zeroMvInADC.Value = value;
}
public void SetZeroMvInADC(int adc) { ZeroMvInADC = adc; }
public void SetZeroMvInADC(double adc)
{
if (double.IsNaN(adc)) { ZeroMvInADC = 0; }
else
{
try { ZeroMvInADC = Convert.ToInt32(adc); }
catch (System.Exception) { ZeroMvInADC = 0; }
}
}
/// <summary>
/// WindowAverageADC is not needed for the DataScaler (as it automatically uses DataZeroLevelADC)
/// but I preserve it here so that it's set just like the other zero values (ZeroMvInADC) and maybe
/// will be available for use in the future
/// </summary>
private readonly Property<int> _windowAverageADC = new Property<int>(
typeof(DataScaler).Namespace + ".DataScaler.WindowAverageADC",
short.MinValue,
true);
/// <summary>
/// WindowAverageADC is the ADC average over the Zero Window for the channel
/// it is private here to force external access through methods
/// </summary>
private int WindowAverageADC
{
get => _windowAverageADC.Value;
set => _windowAverageADC.Value = value;
}
/// <summary>
/// Set the window average ADC for the scaler
/// This does not set the ZeroLevelADC which is used for software zeroing
/// </summary>
/// <param name="adc"></param>
public void SetWindowAverageADC(int adc) { WindowAverageADC = adc; }
public void SetWindowAverageADC(double adc)
{
if (double.IsNaN(adc)) { WindowAverageADC = 0; }
else
{
try { WindowAverageADC = Convert.ToInt32(adc); }
catch (System.Exception) { WindowAverageADC = 0; }
}
}
/// <summary>
/// SetRemovedADC stores the adc removed by H/W zeroing functions
/// the purpose of storing this is for use in mV functions that need to go from
/// ADC to mV but also need to adjust back in the removed ADC
/// </summary>
/// <param name="adc"></param>
public void SetRemovedADC(int adc) { RemovedADC = adc; }
private int RemovedADC
{
get => _removedADC.Value;
set => _removedADC.Value = value;
}
private readonly Property<int> _removedADC
= new Property<int>(
typeof(DataScaler).Namespace + ".DataScaler.RemovedADC",
0,
true
);
/// <summary>
/// SetRemovedInternalADC stores the internal adc removed by H/W zeroing functions
/// the purpose of storing this is for use in mV functions that need to go from
/// ADC to mV but also need to adjust back in the removed ADC
/// </summary>
/// <param name="adc"></param>
public void SetRemovedInternalADC(int adc) { RemovedInternalADC = adc; }
private int RemovedInternalADC
{
get => _removedInternalADC.Value;
set => _removedInternalADC.Value = value;
}
private readonly Property<int> _removedInternalADC
= new Property<int>(
typeof(DataScaler).Namespace + ".DataScaler.RemovedInternalADC",
0,
true
);
public double GetAdcToEuScalingFactor() { return AdcToEuScalingFactor; }
public double GetAdcToMvScalingFactor() { return AdcToMvScalingFactor; }
private readonly Property<short> _dataZeroLevelADC
= new Property<short>(
typeof(DataScaler).Namespace + ".DataScaler.DataZeroLevelADC",
0,
true
);
/// <summary>
/// DataZeroLevelADC is the amount of ADC to be removed by software to zero out the data. This value is typically determined
/// using Software Zeroing like averaging window.
/// </summary>
private short DataZeroLevelADC
{
get => _dataZeroLevelADC.IsValueInitialized ? _dataZeroLevelADC.Value : Convert.ToInt16(0);
set => _dataZeroLevelADC.Value = value;
}
public void SetDataZeroLevelADC(short value) { DataZeroLevelADC = value; }
public short GetDataZeroLevelADC() { return DataZeroLevelADC; }
/// <summary>
/// returns the mV corresponding to the given ADC value
/// </summary>
/// <param name="adc"></param>
/// <returns></returns>
public double GetMv(short adc)
{
return GetMv(Convert.ToDouble(adc));
}
/// <summary>
/// returns mV unless IEPE is true, then returns V
/// </summary>
/// <param name="adc"></param>
/// <returns></returns>
public double GetMvOrV(short adc, bool volts)
{
return GetMv(adc) / (volts ? 1000D : 1D);
}
/// <summary>
/// returns mV unless IEPE is true, then returns V
/// </summary>
/// <param name="adc"></param>
/// <returns></returns>
public double GetMvOrV(double adc, bool volts)
{
return GetMv(adc) / (volts ? 1000D : 1D);
}
public bool IEPE { get; set; }
private readonly int IEPESCALE = 1;
public DataScaler()
{
IEPE = false;
DigitalOutput = false;
Digital = false;
UserOffsetEU = 0D;
}
public DataScaler(DataScaler copy)
{
IsInverted = copy.IsInverted;
SetLinearizationFormula(copy._linearizationEquation);
Digital = copy.Digital;
SetDigitalMultiplier(copy._digitalMultiplier);
DigitalMode = copy.DigitalMode;
SetScaleFactorMv(copy.GetScaleFactorMv());
SetScaleFactorEU(copy.GetScaleFactorEU());
SetUseEUScaleFactors(copy.UseEUScaleFactors);
UnitConversion = copy.UnitConversion;
BasedOnOutputAtCapacity = copy.BasedOnOutputAtCapacity;
CapacityOutputIsBasedOn = copy.CapacityOutputIsBasedOn;
SensitivityUnits = copy.SensitivityUnits;
Multiplier = copy.Multiplier;
UserOffsetEU = copy.UserOffsetEU;
IEPE = copy.IEPE;
SetMvPerEu(copy.GetMvPerEu());
SetDataZeroLevelADC(copy.GetDataZeroLevelADC());
SetRemovedADC(copy.RemovedADC);
SetRemovedInternalADC(copy.RemovedInternalADC);
SetZeroMvInADC(copy.ZeroMvInADC);
SetWindowAverageADC(copy.WindowAverageADC);
SetInitialOffset(copy._initialOffset);
ZeroMethodType = copy.ZeroMethodType;
NominalExcitationVoltage = copy.NominalExcitationVoltage;
MeasuredExcitationVoltage = copy.MeasuredExcitationVoltage;
FactoryExcitationVoltage = copy.FactoryExcitationVoltage;
ProportionalToExcitation = copy.ProportionalToExcitation;
}
/// <summary>
/// 10485 Disable mV graphs for digital inputs
/// 10436 When moving from ADC to mV unit scale is incorrect on both TDAS PRO DIM and G5 for digital input channels.
/// this constant is just a value that we display when displaying mV for a digital input
/// </summary>
public const double DIGITAL_ON_VALUE = 2500D;
public double GetMv(double adc)
{
//we don't consider software zero'ing for mV, so leave out DataZeroLevel, but take into consideration the
//removed offset.
//note we do consider ZeroMvInADC in mV values as TDC does
//digitals per 10436 we display -2500/2500
if (Digital)
{
switch (DigitalMode)
{
case DigitalInputModes.TLH:
case DigitalInputModes.THL:
return adc > DigitalInputs.VoltageInputBreakPoint ? DIGITAL_ON_VALUE : -1D * DIGITAL_ON_VALUE;
default:
return adc > DigitalInputs.ConstantCurrentBreakPoint ? DIGITAL_ON_VALUE : -1D * DIGITAL_ON_VALUE;
}
}
if (null != _linearizationEquation && _linearizationEquation.IsValid())
{
var mV = (adc - ZeroMvInADC) * ScaleFactorMv;
if (IEPE) { return Converters.InitialOffsetToIEPESensorOffsetConverter.ConvertDouble(mV) * 1000.0; }
return mV;
}
else
{
var mV = (adc + RemovedADC - ZeroMvInADC) * ScaleFactorMv;
if (IEPE) { return Converters.InitialOffsetToIEPESensorOffsetConverter.ConvertDouble(mV) * 1000.0; }
return mV;
}
}
public void SetIRTraccZeros(double averageOverTime, double diagnosticADC)
{
}
}
}

View File

@@ -0,0 +1,230 @@
<?xml version="1.0" encoding="utf-8"?>
<ClassDiagram MajorVersion="1" MinorVersion="1">
<Class Name="DTS.Common.DAS.Concepts.DataScaler" Collapsed="true">
<Position X="11.75" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>yIIHsKRGAwEJpVQIBARAJBBuA1EgIBouDUBAUIBBABY=</HashCode>
<FileName>DataScaler.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="DTS.Common.DAS.Concepts.DigitalInputScaleMultiplier" Collapsed="true">
<Position X="13.5" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAgAAIAAAgAAAAAAAAAhAAIAAAAQEAEEAAAA=</HashCode>
<FileName>DigitalInputScaleMultiplier.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="DTS.Common.DAS.Concepts.RealtimeSample" Collapsed="true">
<Position X="11.75" Y="1.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAgAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\IRealtimeable.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="DTS.Common.DAS.Concepts.LinearizationFormula" Collapsed="true">
<Position X="10" Y="1.5" Width="1.5" />
<TypeIdentifier>
<HashCode>EBABiQDJAEEswAAoCAgAAQJCAYBXAKGgAABAAgKEMUA=</HashCode>
<FileName>LinearizationFormula.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="DTS.Common.DAS.Concepts.Test" Collapsed="true">
<Position X="13.5" Y="1.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>ShuntModeType.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="DTS.Common.DAS.Concepts.TsrEvent" Collapsed="true" BaseTypeListCollapsed="true">
<Position X="8.25" Y="2.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAABCwAAAAAAAAAAAAAAAAAAEoAAAAAAAAAAAEABA=</HashCode>
<FileName>TsrEvent.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" Collapsed="true" />
</Class>
<Class Name="DTS.Common.DAS.Concepts.DAS.Channel&lt;TDataType&gt;" Collapsed="true">
<Position X="8.25" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>DAS\Channel\Channel.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="DTS.Common.DAS.Concepts.DAS.Id" Collapsed="true" BaseTypeListCollapsed="true">
<Position X="8.25" Y="1.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAQIAAAAAAAAAQEgAAAAAAAAAAAAKAAAAAAAAAAAAA=</HashCode>
<FileName>DAS\DAS.Id.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" Collapsed="true" />
</Class>
<Class Name="DTS.Common.DAS.Concepts.DAS.Channel.Data&lt;TDatumType&gt;" Collapsed="true">
<Position X="10" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>DAS\Channel\Data.cs</FileName>
</TypeIdentifier>
</Class>
<Interface Name="DTS.Common.DAS.Concepts.IArmable" Collapsed="true">
<Position X="0.5" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAEAAAAAAAAAAAgIAAAABAAAAAAAA=</HashCode>
<FileName>Interfaces\IArmable.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.ICalibratable" Collapsed="true">
<Position X="8.25" Y="3.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAQAAAAAAADAAAAAAAAAAIAAEAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\ICalibratable.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.IDataCollectionEnabled" Collapsed="true">
<Position X="0.5" Y="1.75" Width="1.5" />
<TypeIdentifier>
<HashCode>BAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\IDataCollectionEnabled.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.IDownloadEnabled" Collapsed="true">
<Position X="3.5" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAACAAAAABAQAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\IDownloadEnabled.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.IGpioEnabled" Collapsed="true">
<Position X="8.25" Y="4.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABABAAAA=</HashCode>
<FileName>Interfaces\IGpioEnabled.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.IRealtimeable" Collapsed="true">
<Position X="11.75" Y="5.25" Width="1.5" />
<TypeIdentifier>
<HashCode>AIAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\IRealtimeable.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.ITriggerable" Collapsed="true">
<Position X="5.75" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\ITriggerable.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.DAS.Channel.ICalSignalAware" Collapsed="true">
<Position X="10" Y="3.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAACAAAAAA=</HashCode>
<FileName>Interfaces\DAS\Channel\ICalSignalAware.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.DAS.Channel.IDecimatable&lt;T&gt;" Collapsed="true">
<Position X="11.75" Y="3.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAACAgAAAAAAAAAAAgAAAAAAAAAIAA=</HashCode>
<FileName>Interfaces\DAS\Channel\IDecimatable.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.DAS.Channel.IEngineeringUnitAware" Collapsed="true">
<Position X="13.5" Y="3.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\DAS\Channel\IEngineeringUnitAware.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.DAS.Channel.IInversionAware" Collapsed="true">
<Position X="10" Y="4.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\DAS\Channel\IInversionAware.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.DAS.Channel.IIsoCodeAware" Collapsed="true">
<Position X="11.75" Y="4.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\DAS\Channel\IIsoCodeAware.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.DAS.Channel.ILevelTriggerable" Collapsed="true">
<Position X="8.25" Y="5.25" Width="1.5" />
<TypeIdentifier>
<HashCode>AAIAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAg=</HashCode>
<FileName>Interfaces\DAS\Channel\ILevelTriggerable.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.DAS.Channel.ILinearized" Collapsed="true">
<Position X="10" Y="5.25" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\DAS\Channel\ILinearized.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.DAS.Channel.ISerialNumberAware" Collapsed="true">
<Position X="13.5" Y="5.25" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\DAS\Channel\ISerialNumberAware.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.DAS.Channel.IShuntAware" Collapsed="true">
<Position X="8.25" Y="6" Width="1.5" />
<TypeIdentifier>
<HashCode>ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAA=</HashCode>
<FileName>Interfaces\DAS\Channel\IShuntAware.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.DAS.Channel.IVoltageInsertionAware" Collapsed="true">
<Position X="10" Y="6" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAEAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\DAS\Channel\IVoltageInsertAware.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="DTS.Common.DAS.Concepts.DAS.Channel.ILargeDataAware" Collapsed="true">
<Position X="13.5" Y="4.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Interfaces\ILargeDataAware.cs</FileName>
</TypeIdentifier>
</Interface>
<Enum Name="DTS.Common.DAS.Concepts.ArmStatus" Collapsed="true">
<Position X="8.25" Y="7" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAIBAAAAAAAAAAAAAAAIBAAAAAAAAgAAAAA=</HashCode>
<FileName>ArmStatus.cs</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="DTS.Common.DAS.Concepts.AvailableArmModes" Collapsed="true">
<Position X="10" Y="7" Width="1.5" />
<TypeIdentifier>
<HashCode>AIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>AvailableArmModes.cs</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="DTS.Common.DAS.Concepts.DAS.DecimationMethod" Collapsed="true">
<Position X="11.75" Y="7" Width="1.5" />
<TypeIdentifier>
<HashCode>ACAAAAAAAAAAhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>DAS\DecimationMethod.cs</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="DTS.Common.DAS.Concepts.DAS.Channel.LevelTriggerTypes" Collapsed="true">
<Position X="8.25" Y="7.75" Width="1.5" />
<TypeIdentifier>
<HashCode>ACAAAAACACAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAACA=</HashCode>
<FileName>DAS\Channel\LevelTriggerTypes.cs</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="DTS.Common.Common.DAS.Concepts.GPIOPin.Directions" Collapsed="true">
<Position X="13.5" Y="7" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAYAAAAEAQAAAAAAAAAgAAAAAA=</HashCode>
<FileName>Interfaces\IGpioEnabled.cs</FileName>
</TypeIdentifier>
</Enum>
<Font Name="Segoe UI" Size="9" />
</ClassDiagram>

View File

@@ -0,0 +1,142 @@
/*
* IArmable.cs
*
* Copyright © 2010
* Diversified Technical Systems, Inc.
* All Rights Reserved.
*/
namespace DTS.DAS.Concepts
{
/// <summary>
/// different possible arm modes
/// </summary>
public enum AvailableArmModes
{
LowPower,
CircularBuffer,
};
/// <summary>
/// different possible armstatus
/// </summary>
public enum ArmStatus
{
Disarming,
Disarmed,
Arming,
Armed,
Recording, // Extra statuses (chuck's mail)
}
///
/// <summary>
/// Formal description of the ability to "arm".
/// </summary>
///
public interface IArmable
{
void Arm();
void Disarm();
ArmStatus ArmStatus { get; }
AvailableArmModes ArmMode { get; }
}
}
//Like Rollin said, NGI will (for now) be orphaned. NASCAR is in for sure. TSR6DX is really TSRPRO, I think. RateTestTSR==BlastTestTSR and needs to be flattened. TSR==TSRBasic. The missing one in that list is HEADSII.
//NASCAR is 3 16-bit channels using a 216 daughterboard.
//TSRPRO is 6 channels, 3 16-bit on a 216 daughterboard, 3 12-bit on the 215 motherboard
//BlastTestTSR is 7 channels, 4 12-bit on the 215 motherboard, 3 16-bit on a hacked daughterboard
//TSRBasic is 3 12-bit channels on the 215 motherboard
//HEADSII is 7 12-bit channels on the 221 board
//The other missing component to some of what you sent earlier is that some of these systems have multiple sample rates. BlastTestTSR will have the 4 12-bit channels @ 40ksps and the 3 16-bit channels @ 1ksps. NGI had 2 24-bit channels @ 1ksps and 2 16-bit (?? can't remember for sure) channels @ 1sps. As it stands now we have the lower level download code just interpolate slow data to fast data and then everything has the "same" sample rate at the upper level, but it might be nice to deal with it more formally since that creates some funny edge cases we have to deal with by limiting the download to occur in sample number chunks that are a multiple of the fast rate divided by the slow rate.
//On 8/12/2010 11:12 AM, Paul Hrissikopoulos wrote:
//> By the way, the types that the switches currently in the TSR2 code seem to think important are:
//>
//> TSRModel.NASCARIDR:
//> TSRModel.TSR6DX:
//> TSRModel.RateTestTSR:
//> TSRModel.BlastTSR:
//> TSRModel.TSR:
//> TSRModel.NGIPrototype:
//>
//> Are we going to want all of those? Some of those? Those and then some?
//>
//> On 8/12/2010 11:07 AM, Paul Hrissikopoulos wrote:
//>> I guess in theory the software should be able to deal with the multiplicity of device types as it sees fit -- some code, definitely including parts of the UI, will need to be able to actively discriminate between types before doing something type-specific, but I think the hope is that the bulk should be able to use it in a more generic sense (arm the same, download the same, realtime the same, etc.). But still maybe that's a valid point -- do we foresee a ton of cases where we'll be doing interface is/as and/or typefield checks before doing something?
//>>
//>> On 8/12/2010 10:50 AM, Tadd Seiff wrote:
//>>> I like this.
//>>>
//>>> My approach at the moment is immediately how to use this as a HEADS device. My understanding is that the device will surface through the factory which will populate things such as TSR.Channel[] Channels which can then be accessed safely only with RunTime checks like if (HEADS == unit.TSRModel) {...}. Does this put us in the same position being at the mercy of switch statements at a higher level? This is just my knee-jerk reaction.
//>>>
//>>> On 8/12/2010 10:08 AM, Paul Hrissikopoulos wrote:
//>>>> My reordering is attached. Search it for "?" for some open questions. Please let me know if you think I'm missing anything major (or minor) or am entirely on the wrong track.
//>>>>
//>>>> On 8/9/2010 10:26 PM, Rollin White wrote:
//>>>>> Here's an update with a channel class.
//>>>>>
//>>>>> Please voice concerns, opinions, etc. This is just my simple view of the task.
//>>>>>
//>>>>> On 8/9/2010 3:02 PM, Rollin White wrote:
//>>>>>> Here's my first cut at the interface description for the next generation TSR class. The interface is meant to describe the features common to all models.
//>>>>>>
//>>>>>> In addition to what's here, there needs to be significant definition of the channel class. Finally, there are probably a few interfaces that need to be defined that class implementers would optionally implement. For example, ISupportsDynamicEventLength.
//>>>>>>
//>>>>>> This is simply a starting point. Comments welcome.
//>>>>
//>>>
//>>
//>
//>
//--
//Chuck Gillen-O'Neel
//Diversified Technical Systems, Inc.
//909 Electric Avenue, Suite 206
//Seal Beach, CA 90740
//Telephone: (562) 493-0158
//Email: chuck.go@dtsweb.com
// My comments:
// * For sensitivity we should either have mv/count and eu/mv for each channel OR have eu/count for each channel. Obviously the former is more flexible, but also a little more complicated and maybe unneeded for 95-99% of TSR/HEADS applications.
// * OffsetCounts in IChannel should be signed. We nearly always need to make offsets signed. I'm speaking from my own mistakes here ... !!! :)
// * We need to think about the arm states a bit more. There have been a couple of cases where having a Disarming state, in addition to Disarmed, has been nice.
// * For GPIOs we might as well surface (and extend the firmware a bit to support this) the fact that IOs can be inputs as well as high/low outputs. So, rather than just returning a bool we might want to return a state enum. It's already there in the interface for SetGPIO since the GPIOPin.Direction enum has input and output and if it's set to input the State parameter is effectively a no-op.
// * The question of a good interface for Calibration is still unanswered. The interface as shown is obviously fine for doing those three readings, but I'm not sure how truly useful that is in a generic sense. I have a feeling that this is a place where we'll be hooking in model checks, etc. etc. Maybe that's okay and can be limited to the cal software.
//On 8/12/2010 10:50 AM, Tadd Seiff wrote:
//> I like this.
//>
//> My approach at the moment is immediately how to use this as a HEADS device. My understanding is that the device will surface through the factory which will populate things such as TSR.Channel[] Channels which can then be accessed safely only with RunTime checks like if (HEADS == unit.TSRModel) {...}. Does this put us in the same position being at the mercy of switch statements at a higher level? This is just my knee-jerk reaction.
//>
//> On 8/12/2010 10:08 AM, Paul Hrissikopoulos wrote:
//>> My reordering is attached. Search it for "?" for some open questions. Please let me know if you think I'm missing anything major (or minor) or am entirely on the wrong track.
//>>
//>> On 8/9/2010 10:26 PM, Rollin White wrote:
//>>> Here's an update with a channel class.
//>>>
//>>> Please voice concerns, opinions, etc. This is just my simple view of the task.
//>>>
//>>> On 8/9/2010 3:02 PM, Rollin White wrote:
//>>>> Here's my first cut at the interface description for the next generation TSR class. The interface is meant to describe the features common to all models.
//>>>>
//>>>> In addition to what's here, there needs to be significant definition of the channel class. Finally, there are probably a few interfaces that need to be defined that class implementers would optionally implement. For example, ISupportsDynamicEventLength.
//>>>>
//>>>> This is simply a starting point. Comments welcome.
//>>
//>
//--
//Chuck Gillen-O'Neel
//Diversified Technical Systems, Inc.
//909 Electric Avenue, Suite 206
//Seal Beach, CA 90740
//Telephone: (562) 493-0158
//Email: chuck.go@dtsweb.com

View File

@@ -0,0 +1,27 @@
/*
* ICalibratable.cs
*
* Copyright © 2010
* Diversified Technical Systems, Inc.
* All Rights Reserved.
*/
namespace DTS.DAS.Concepts
{ ///
/// <summary>
/// Representation of the ability to calibrate.
/// </summary>
///
public interface ICalibratable
{ //
// Properties required for rudimentary calibration.
//
string SerialNumber { get; set; }
double Sensitivity { get; set; }
double BatteryVolts { get; set; }
double VddVolts { get; set; }
double SignalConditioningVolts { get; set; }
// access for generic attributes.
}
}

View File

@@ -0,0 +1,25 @@
/*
* IDataCollectionEnabled.cs
*
* Copyright © 2010
* Diversified Technical Systems, Inc.
* All Rights Reserved.
*/
namespace DTS.DAS.Concepts
{ ///
/// <summary>
/// Representation of the ability to perform a basic data collection.
/// </summary>
///
public interface IDataCollectionEnabled
: IArmable,
ITriggerable,
IDownloadEnabled
{ //
// Additional properties required for rudimentary data collection.
//
double[] AvailableSampleRates { get; }
double SampleRate { get; set; }
}
}

View File

@@ -0,0 +1,115 @@
/*
* IDownloadEnabled.cs
*
* Copyright © 2010
* Diversified Technical Systems, Inc.
* All Rights Reserved.
*/
using System;
using DTS.Utilities;
/// <DevelopmentNote Developer="Paul Hrissikopoulos">
/// It may make sense to refactor this namespace to be DTS.DAS.Concepts.Tsr and rename the TSR-specific
/// event to "Event" so that the fully qualified name of the class is "DTS.DAS.Concepts.Tsr.Event", but
/// then maybe keep the IDownloadEnabled and other generic interfaces outside of the "Tsr"-specific
/// namespace...? No, should probably stay with Event, since it has an "Event" type referenced in the
/// interface.
/// </DevelopmentNote>
namespace DTS.DAS.Concepts
{ ///
/// <summary>
/// Representation of data and metadata associated with a TSR event.
/// </summary>
///
public abstract class TsrEvent : Exceptional, ICloneable
{
/// <summary>
/// The 1-based <see cref="UInt64"/> identifier for this event.
/// </summary>
public virtual UInt64 EventId { get; protected set; }
/// <summary>
/// The <see cref="System.DateTime"/> containing the date and time of this event.
/// </summary>
public virtual DateTime TimeStamp { get; protected set; }
/// <summary>
/// The <see cref="string"/> serial number of the hardware that captured this event.
/// </summary>
public virtual string SerialNumber { get; protected set; }
/// <summary>
/// The <see cref="string"/> alternate serial number of the hardware that captured the event.
/// </summary>
public virtual string AlternateSerialNumber { get; protected set; }
/// <summary>
/// The <see cref="double"/> duration in seconds of this event.
/// </summary>
public virtual double DurationSeconds { get; protected set; }
/// <summary>
/// The <see cref="double"/> maximum sample rate for this event.
/// </summary>
public virtual double MaxSampleRate { get; protected set; } // note this is the "highest" sample rate
/// <summary>
/// The <see cref="float"/> temperature (in C).
/// </summary>
public virtual float TemperatureC { get; protected set; }
/// <summary>
/// The <see cref="double"/> number of pre-trigger seconds.
/// </summary>
public virtual double PreTriggerSeconds { get; protected set; }
///
/// <summary>
/// Generate a shallow copy of this object.
/// </summary>
/// <returns>A shallow copy of this <see cref="object"/>.</returns>
///
public abstract object Clone();
}
///
/// <summary>
/// Representation of the ability to download from this object.
/// </summary>
///
public interface IDownloadEnabled
{ //
// TODO: Determine whether or not these things should be in here. Maybe the implementing
// object should just ask for them in the constructor and keep them private? I don't think
// these are universally applicable to something "download enabled"... are they?
//
//public uint MaximumStoredEventSizeSeconds { get; }
//public ushort DownloadIncrementSamples { get; }
//public string[] ChannelDescription { get; }
//public int TimeOffsetMilliseconds { get; }
/// <summary>
/// A list of download <see cref="DTS.DAS.Concepts.TsrEvent"/>s available for download.
/// </summary>
TsrEvent[] EventList {get;}
///
/// <summary>
/// Get the event data for the specified sample.
/// </summary>
/// <param name="Event">The <see cref="DTS.DAS.Concepts.TsrEvent"/> to have it's data extracted.</param>
/// <param name="FirstSample">The <see cref="UInt64"/> index of the first sample to be downloaded.</param>
/// <param name="LastSample">The <see cref="UInt64"/> index of the last sample to be downloaded.</param>
/// <returns>An array of <see cref="double"/> data arrays for each channel.</returns>
///
double [][] GetEventData( TsrEvent Event, UInt64 FirstSample, UInt64 LastSample ); // Any reason to do data as an out parameter rather than a return value?
// Have a subclassed channel class that has a data array, just so that 2-d array isn't so ambiguous?
/// <summary>
/// Determine whether or not the data on this download-enabled entity has been downloaded.
/// </summary>
bool DataHasBeenDownloaded { get; }
}
}

View File

@@ -0,0 +1,31 @@
/*
* IGpioEnabled.cs
*
* Copyright © 2010
* Diversified Technical Systems, Inc.
* All Rights Reserved.
*/
namespace DTS.DAS.Concepts.GPIOPin
{
public enum Directions
{
Output = 0x00, Peripheral = 0x01, Input = 0x02,
InputPulledUp = 0x03, InputPulledDown = 0x04
};
}
namespace DTS.DAS.Concepts
{ ///
/// <summary>
/// Representation of GPIO functionality.
/// </summary>
///
public interface IGpioEnabled
{
// TODO: Well have to bring these in as soon as we figure out where to get that enum from.
void SetGpio(uint Port, uint Pin, GPIOPin.Directions Direction, bool State);
bool GetGpio(uint Port, uint Pin);
}
}

View File

@@ -0,0 +1,27 @@
/*
* DTS.Channel.ILargeDataAware
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of what it means for a DAS channel to be "large data aware".
/// </summary>
///
public interface ILargeDataAware
{
/// <summary>
/// Determine whether or not this data set is small enough to be safely fit into any array
/// within the context of a slice application (will be filtered, sent to viewer, etc).
/// </summary>
bool IsDataArraySized
{
get;
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* IRealtimeable.cs
*
* Copyright © 2010
* Diversified Technical Systems, Inc.
* All Rights Reserved.
*/
using System;
namespace DTS.DAS.Concepts
{ ///
/// <summary>
/// Representation of a real-time data sample.
/// </summary>
///
public class RealtimeSample
{
public double[] DataEU; // Note this indexes by channel.
public UInt64 SampleNumber;
}
///
/// <summary>
/// Representation of the ability to perform "real-time" data capture.
/// </summary>
///
public interface IRealtimeable
{
void StartRealtime( double sampleRate );
void StopRealtime();
RealtimeSample[] GetRealtimeSamples();
}
}

View File

@@ -0,0 +1,19 @@
/*
* ITriggerable.cs
*
* Copyright © 2010
* Diversified Technical Systems, Inc.
* All Rights Reserved.
*/
namespace DTS.DAS.Concepts
{ ///
/// <summary>
/// Functional description of a "triggerable" object.
/// </summary>
///
public interface ITriggerable
{
void Trigger();
}
}

View File

@@ -0,0 +1,26 @@
namespace DTS.Common.DAS.Concepts.DAS.Channel
{
/// <summary>
/// Definition of the concept of calsignal-check awareness.
/// </summary>
public interface ICalSignalAware
{
/// <summary>
/// Get/set this object's <see cref="double"/> measured shunt deflection value.
/// </summary>
double MeasuredCalSignalMv
{
get;
set;
}
/// <summary>
/// Get/set this object's <see cref="double"/> target shunt deflection value.
/// </summary>
double TargetCalSignalMv
{
get;
set;
}
}
}

Some files were not shown because too many files have changed in this diff Show More