Files
DP44/Common/DTS.Common.SerializationPlus/.svn/pristine/18/188139b839c1986e9c672bef31ad6d453d320a4d.svn-base

2328 lines
105 KiB
Plaintext
Raw Normal View History

2026-04-17 14:55:32 -04:00
/*
* DTS.Slice.Control.Event.Module.Channel.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
using System;
using System.Collections.Generic;
using DTS.DASLib.Service;
using DTS.Common.DAS.Concepts.DAS.Channel;
using DTS.Common.DAS.Concepts;
using DTS.Common.DASResource;
using DTS.Common.Enums;
using DTS.Common.Enums.Sensors;
using DTS.Common.SerializationPlus;
using DTS.Common.Utilities;
using DTS.Common.Utilities.DotNetProgrammingConstructs;
using DTS.Common.Interface.DASFactory.Diagnostics;
namespace DTS.Slice.Control
{
// *** see DTS.Slice.Control.Event.cs ***
public partial class Event
{
// *** see DTS.Slice.Control.Event.Module.cs ***
public partial class Module
{
/// <summary>
/// Representation of the DTS.Slice.Control.Event.Module.Channel class.
/// </summary>
public abstract partial class Channel
: Exceptional,
IFilterable, IDisposable
{
public void Dispose() { }
/// <summary>
/// Initialize an instance of the Event.Module.Channel class. Specifically, perform initializations
/// that will be required no matter what constructor parameter signature is invoked.
/// </summary>
private Channel()
{
try
{
//this.InitializeReviewableAttributes(this.ReviewableAttributes);
}
catch (System.Exception ex)
{
throw new Exception("encountered problem constructing channel", ex);
}
}
/// <summary>
/// Initialize an instance of the DTS.Slice.Control.Event.Module.Channel class.
/// </summary>
///
/// <param name="parentModule">
/// The <see cref="DTS.Slice.Control.Event.Module"/> that contains this channel.
/// </param>
///
/// <param name="absoluteNumber">
/// The unique "absolute" <see cref="int"/> number of the channel with respect to all other channels
/// on all other DASes in the system.
/// </param>
///
protected Channel(Module parentModule, int absoluteNumber)
: this()
{
try
{
var enumerabilityGrabber = new EnumerabilityAttributeCoder();
ParentModule = parentModule;
AbsoluteNumber = absoluteNumber;
foreach (int enumValue in Enum.GetValues(typeof(ChannelFilter)))
if (enumerabilityGrabber.DecodeAttributeValue((ChannelFilter)enumValue))
AvailableFilters.Add(
new SaeJ211Filter((ChannelFilter)enumValue)
);
CurrentFilter = AvailableFilters[0];
}
catch (System.Exception ex)
{
throw new Exception("encountered problem constructing " + GetType().FullName, ex);
}
}
/// <summary>
/// Initialize an instance of the DTS.Slice.Control.Event.Module.Channel class.
/// </summary>
///
/// <param name="channel">
/// The <see cref="DTS.DASLib.Service.DASChannel"/> object with which to initialize
/// this object.
/// </param>
///
/// <param name="parentModule">
/// The <see cref="DTS.Slice.Control.Event.Module"/> that contains this channel.
/// </param>
///
/// <param name="absoluteNumber">
/// The unique "absolute" <see cref="int"/> number of the channel with respect to all other channels
/// on all other DASes in the system.
/// </param>
///
public Channel(DASChannel channel, Module parentModule, int absoluteNumber)
: this(parentModule, absoluteNumber)
{
try
{ //
// Initialize basic channel properties with any values we can find
// in the specified channel object.
//
Number = channel.ModuleChannelNumber;
Start = channel.EventStartTime;
AbsoluteDisplayOrder = channel.AbsoluteDisplayOrder;
UnitConversion = channel.UnitConverision;
AtCapacity = channel.AtCapacity;
CapacityOutputIsBasedOn = channel.CapacityOutputIsBasedOn;
SensitivityUnits = channel.SensitivityUnits;
IsoChannelName = channel.IsoChannelName;
UserCode = channel.UserCode;
UserChannelName = channel.UserChannelName;
LinearSensorCalibration = channel.LinearSensorCalibration;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem constructing " + GetType().FullName, ex);
}
}
/// <summary>
/// Initialize an instance of the DTS.Slice.Control.Event.Module.Channel class.
/// </summary>
///
/// <param name="channel">
/// The <see cref="DTS.Serialization.Test.Module.Channel"/> object with which to initialize
/// this object.
/// </param>
///
/// <param name="parentModule">
/// The <see cref="DTS.Slice.Control.Event.Module"/> that contains this channel.
/// </param>
///
/// <param name="absoluteNumber">
/// The unique "absolute" <see cref="int"/> number of the channel with respect to all other channels
/// on all other DASes in the system.
/// </param>
///
public Channel(Serialization.Test.Module.Channel channel, Module parentModule, int absoluteNumber)
: this(parentModule, absoluteNumber)
{
try
{ //
// Initialize basic channel properties with any values we can find
// in the specified channel object.
//
AbsoluteDisplayOrder = channel.AbsoluteDisplayOrder;
Multiplier = channel.Data.Multiplier;
UnitConversion = channel.Data.UnitConversion;
UserOffsetEU = channel.Data.UserOffsetEU;
Number = channel.Number;
Start = channel.Start;
try
{
if (channel.TimeOfFirstSampleValid) { TimeOfFirstSampleSec = channel.TimeOfFirstSampleSec; }
}
catch { }
if (channel.IsLastCalibrationDateValid) { LastCalibrationDate = channel.LastCalibrationDate; }
if (channel.IsCalDueDateValid) { CalDueDate = channel.CalDueDate; }
if (channel.IsSensorIDValid) { SensorID = channel.SensorID; }
if (channel.IsOffsetToleranceLowMvValid) { OffsetToleranceLowMv = channel.OffsetToleranceLowMv; }
if (channel.IsOffsetToleranceHighMvValid) { OffsetToleranceHighMv = channel.OffsetToleranceHighMv; }
if (channel.IsUserCodeValid) { UserCode = channel.UserCode; }
if (channel.IsUserChannelNameValid) { UserChannelName = channel.UserChannelName; }
if (channel.IsIsoChannelNameValid) { IsoChannelName = channel.IsoChannelName; }
IsSubsampled = channel.IsSubsampled;
UnsubsampledSampleRateHz = channel.UnsubsampledSampleRateHz;
IsSupersampled = channel.IsSupersampled;
UseEUScaler = channel.Data.UseEUScaleFactors;
UnsupersampledSampleRateHz = channel.UnsupersampledSampleRateHz;
try
{
if (channel.PersistentChannelInfo == null)
{
UnfilteredData = channel.TDASPersistentChannelInfo;
}
else
{
UnfilteredData = channel.PersistentChannelInfo; //channel.Data;
}
}
catch (System.Exception) { throw new System.IO.InvalidDataException("Invalid or corrupt data file, channel: " + channel.ChannelDescriptionString + " - " + channel.ChannelName2); }
// xxx proposal: this.UnfilteredData = ( null != channel.PersistentChannelInfo ? channel.PersistentChannelInfo : channel.Data );
// If everything uses persistent channel info, that's going to break the data viewer completely in the short term, unless we either
// change the data viewer to be clever about extracting something displayable or provide the "classic" data structure through the
// "UnfilteredData" property somehow.
}
catch (System.IO.InvalidDataException) { throw; }
catch (System.Exception ex)
{
throw new Exception("encountered problem constructing " + GetType().FullName, ex);
}
}
/*
/// <summary>
/// Get "reviewable" (attributes that can be automatically converted to strings and displayed
/// on the review tab) for this channel.
/// </summary>
public List<ReviewableAttribute> ReviewableAttributes
{
get { return _ReviewableAttributes.Value; }
private set { _ReviewableAttributes.Value = value; }
}
private Property<List<ReviewableAttribute>> _ReviewableAttributes
= new Property<List<ReviewableAttribute>>(
typeof(Event.Module.Channel).Namespace + ".Event.Module.Channel.ReviewableAttributes",
new List<ReviewableAttribute>(),
true
);
*/
/*
/// <summary>
/// Method to allow derived classes to initialize their own reviewable attributes.
/// </summary>
///
/// <param name="reviewableAttributes">
/// The <see cref="List"/> or <see cref="ReviewableAttribute"/>s to be initialized.
/// </param>
///
protected abstract void InitializeReviewableAttributes(List<ReviewableAttribute> reviewableAttributes);
*/
/// <summary>
/// Our data display unit options.
/// </summary>
public enum DataDisplayUnits
{
Adc,
Mv,
Eu
}
/// <summary>
/// The <see cref="Event.Module"/> that contains this channel.
/// </summary>
public Module ParentModule
{
get => _ParentModule.Value;
private set => _ParentModule.Value = value;
}
private readonly Property<Module> _ParentModule
= new Property<Module>(
typeof(Channel).Namespace + ".Event.Module.Channel.ParentModule",
null,
false
);
/// <summary>
/// Get the data scaler for this channel.
/// </summary>
public DataScaler Scaler => _Scaler.Value;
private readonly Property<DataScaler> _Scaler
= new Property<DataScaler>(
typeof(Channel).Namespace + ".Event.Module.Channel.Scaler",
new DataScaler(),
true
);
/// <summary>
/// Get/set the <see cref="bool"/> switch to enable/disable filter caching.
/// </summary>
public bool UseFilterCaching
{
//for now NEVER cache
/*get { return _UseFilterCaching.Value; }
set
{
if (false == (_UseFilterCaching.Value = value))
{ //
// If we disable filter caching on the fly, make sure the caches are cleared.
//
_Data = null;
_DataEu = null;
_DataMv = null;
lock (previouslyFilteredDataLock)
{
_previouslyFilteredData.Clear();
}
}
}*/
get => false;
set { }
}
/*private Property<bool> _UseFilterCaching
= new Property<bool>(
typeof(Event.Module.Channel).Namespace + ".Event.Module.Channel.UseFilterCaching",
true,
true
);
*/
/// <summary>
/// Get/set a user-readable description of this channel object; intended to be
/// the UI representation of this object. Literally, what the API channel's
/// ToString method said it was.
/// </summary>
public string ChannelDescriptionString
{
get => _ChannelDescriptionString.Value;
set => _ChannelDescriptionString.Value = value;
}
private readonly Property<string> _ChannelDescriptionString
= new Property<string>(
typeof(Channel).Namespace + ".Event.Module.Channel.ChannelDescriptionString",
null,
false
);
/// <summary>
/// Get/set the manufacturer of this channel object's sensor.
/// </summary>
public string Manufacturer
{
get => _Manufacturer.Value;
set => _Manufacturer.Value = value;
}
private readonly Property<string> _Manufacturer
= new Property<string>(
typeof(Channel).Namespace + ".Event.Module.Channel.Manufacturer",
null,
false
);
/// <summary>
/// Get/set the manufacturer of this channel object's sensor.
/// </summary>
public string Model
{
get => _Model.Value;
set => _Model.Value = value;
}
private readonly Property<string> _Model
= new Property<string>(
typeof(Channel).Namespace + ".Event.Module.Channel.Model",
null,
false
);
public string OriginalChannelName
{
get => _OriginalChannelName.Value;
set => _OriginalChannelName.Value = value;
}
private readonly Property<string> _OriginalChannelName
= new Property<string>(
typeof(Channel).Namespace + ".Event.Module.Channel.OriginalChannelName",
"",
true);
public string ChannelName2
{
get => _ChannelName2.Value;
set => _ChannelName2.Value = value;
}
private readonly Property<string> _ChannelName2
= new Property<string>(
typeof(Channel).Namespace + ".Event.Module.Channel.ChannelName2",
"",
true);
private readonly Property<string> _HardwareChannelName
= new Property<string>(
typeof(Channel).Name + ".Event.Module.Channel.HardwareChannelName",
"",
true);
public string HardwareChannelName
{
get => _HardwareChannelName.Value;
set => _HardwareChannelName.Value = value;
}
private readonly Property<string> _ChannelId
= new Property<string>(
typeof(Channel).Name + ".Event.Module.Channel.ChannelId",
"",
true);
/// <summary>
/// refers to a unique id for a logical channel in the test
/// for now this is using TestObjectChannel.GetId()
/// which is in the form of TestObjectSerial_ChannelType_ChannelId
/// </summary>
public string ChannelId
{
get => _ChannelId.Value;
set => _ChannelId.Value = value;
}
private readonly Property<string> _Sensor
= new Property<string>(
typeof(Channel).Name + ".Event.Module.Channel.Sensor",
"",
true);
/// <summary>
/// refers to a unique sensor serial number for a logical channel in the test
/// </summary>
public string Sensor
{
get => _Sensor.Value;
set => _Sensor.Value = value;
}
private readonly Property<string> _ChannelGroupName
= new Property<string>(
typeof(Channel).Name + ".Event.Module.Channel.ChannelGroupName",
"",
true);
/// <summary>
/// refers to the Group for a logical channel in the test
/// </summary>
public string ChannelGroupName
{
get => _ChannelGroupName.Value ?? "";
set => _ChannelGroupName.Value = value;
}
private readonly Property<string> _SetupEID
= new Property<string>(
typeof(Channel).Name + ".Event.Module.Channel.SetupEID",
string.Empty,
true);
/// <summary>
/// The electronic id for a channel at test setup time
/// </summary>
public string SetupEID
{
get => _SetupEID.Value ?? string.Empty;
set => _SetupEID.Value = value;
}
private readonly Property<string> _DataCollectionEID
= new Property<string>(
typeof(Channel).Name + ".Event.Module.Channel.DataCollectionEID",
string.Empty,
true);
/// <summary>
/// the electronic id on a channel at run time
/// </summary>
public string DataCollectionEID
{
get => _DataCollectionEID.Value ?? string.Empty;
set => _DataCollectionEID.Value = value;
}
public string UserValue1
{
get => _userValue1.Value;
set => _userValue1.Value = value;
}
private readonly Property<string> _userValue1 = new Property<string>(
typeof(Channel).Namespace + ".Event.Module.Channel.UserValue1",
"", true);
public string UserValue2
{
get => _userValue2.Value;
set => _userValue2.Value = value;
}
private readonly Property<string> _userValue2 = new Property<string>(
typeof(Channel).Namespace + ".Event.Module.Channel.UserValue2",
"", true);
public string UserValue3
{
get => _userValue3.Value;
set => _userValue3.Value = value;
}
private readonly Property<string> _userValue3 = new Property<string>(
typeof(Channel).Namespace + ".Event.Module.Channel.UserValue3",
"", true);
/// <summary>
/// Get/set the channel's ordinal number within the stack.
/// </summary>
public int Number
{
get => _Number.Value;
set => _Number.Value = value;
}
private readonly Property<int> _Number = new Property<int>("DTS.Control.Event.Module.Channel.Number", -1, false);
/// <summary>
/// Get the channel's ordinal number within the entire system.
/// </summary>
public int AbsoluteNumber
{
get => _AbsoluteNumber.Value;
private set => _AbsoluteNumber.Value = value;
}
private readonly Property<int> _AbsoluteNumber
= new Property<int>(
typeof(Channel).FullName + ".AbsoluteNumber",
-1,
false
);
public bool TimeOfFirstSampleSecValid => _TimeOfFirstSampleSec.IsInitialized;
/// <summary>
/// The <see cref="double"/> time of the first sample. Will be needed if the time
/// scale can't be determined by the trigger sample number (possible, as it's an unsigned
/// value and an all-positive ROI that doesn't contain T0 would need it to be negative).
/// </summary>
public double TimeOfFirstSampleSec
{
get => _TimeOfFirstSampleSec.Value;
set => _TimeOfFirstSampleSec.Value = value;
}
private readonly Property<double> _TimeOfFirstSampleSec
= new Property<double>(
typeof(Channel).FullName + ".TimeOfFirstSample",
0.0,
false
);
/// <summary>
/// Get/set the start time for this channel.
/// </summary>
public DateTime Start
{
get => _Start.Value;
set => _Start.Value = value;
}
private readonly Property<DateTime> _Start = new Property<DateTime>("DTS.Control.Event.Module.Channel.Start", DateTime.Now, false);
public LinkedList<short[]> PartialUnfilteredData = null;
// Method for creating channel files directly to disk.
// Change that linked list class to something that will handle this...
// I think what we need to do instead is to change the class/data structure that represents
// the channel data into an object that maybe double passes the reference, or derives from the
// memory-mapped file objecct, but it can also have extra methods and throw an exception if we
// try to access it before it's been properly initialized.
/// <summary>
/// Get/set the <see cref="short"/> data value list for this channel.
/// </summary>
public List<short> UnfilteredData
{
get => _UnfilteredData.Value;
set
{
try
{
// Reset unfiltered data caches.
_UnfilteredData.Value = value;
_UnfilteredDataEu = null;
_UnfilteredDataMv = null;
_DataRangeAdc.UnInitialize();
//_DataRangeEu .UnInitialize( ); // *** not currently cached.
//_DataRangeMv .UnInitialize( ); // *** not currently cached.
// Reset filtered data caches.
_Data = null;
_DataEu = null;
_DataMv = null;
lock (previouslyFilteredDataLock)
{
_previouslyFilteredData.Clear();
}
// Update the data count.
if (value is Serialization.SliceRaw.File.PersistentChannel persistentChannel)
DataCount = persistentChannel.Count;
else if (value is Serialization.TDAS.File.PersistentChannel tdasPersistentChannel)
DataCount = tdasPersistentChannel.Count;
else DataCount = value.Count;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem setting unfiltered data", ex);
}
}
}
private readonly Property<List<short>> _UnfilteredData = new Property<List<short>>("DTS.Control.Event.Module.Channel.Data", null, false);
public List<short> UnfilteredAlternateData
{
get => _UnfilteredAlternateData.Value;
set
{
try
{
// Reset unfiltered data caches.
_UnfilteredAlternateData.Value = value;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem setting unfiltered alternate data", ex);
}
}
}
private readonly Property<List<short>> _UnfilteredAlternateData = new Property<List<short>>("DTS.Control.Event.Module.Channel.AlternateData", null, false);
/// <summary>
/// Get the filtered double-converted data for this channel.
/// </summary>
public List<double> Data
{
get
{
try
{
if (UseFilterCaching)
{
if (null == _Data)
return _Data = new List<double>(GetDataFilteredBy(CurrentFilter, DataDisplayUnits.Adc));
return _Data;
}
return new List<double>(GetDataFilteredBy(CurrentFilter, DataDisplayUnits.Adc));
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting filtered data", ex);
}
}
}
private List<double> _Data = null;
/// <summary>
/// Get the data count for this channel.
/// </summary>
public int DataCount
{
get;
private set;
}
public abstract List<double> GetUnfilteredDataEu();
public abstract List<double> GetUnfilteredDataMV();
/// <summary>
/// Get an EU-scaled version of the data <see cref="double"/> <see cref="List"/>.
/// </summary>
public List<double> UnfilteredDataEu
{
get
{
try
{ //
// If scaled data has yet to be computed, then compute, cache and return it.
// Otherwise just return the cached version.
//
if (null == _UnfilteredDataEu)
{
if (UnfilteredData is ILargeDataAware largeDataAware)
{
if (!largeDataAware.IsDataArraySized)
{
throw new Serialization.SliceRaw.File.PersistentChannel.DataTooBigForArrayException("Data is too big to be viewed or filtered.");
}
}
_UnfilteredDataEu = GetUnfilteredDataEu();
}
return _UnfilteredDataEu;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting EU-scaled data", ex);
}
}
}
private List<double> _UnfilteredDataEu = null;
protected List<double> UnfilteredDataMV
{
get
{
try
{ //
// If scaled data has yet to be computed, then compute, cache and return it.
// Otherwise just return the cached version.
//
if (null == _UnfilteredDataMV)
{
if (UnfilteredData is ILargeDataAware largeDataAware)
{
if (!largeDataAware.IsDataArraySized)
{
throw new Serialization.SliceRaw.File.PersistentChannel.DataTooBigForArrayException("Data is too big to be viewed or filtered.");
}
}
_UnfilteredDataMV = GetUnfilteredDataMV();
}
return _UnfilteredDataMV;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting EU-scaled data", ex);
}
}
}
private List<double> _UnfilteredDataMV = null;
private List<double> _DataADC = null;
public List<double> DataADC
{
get
{
try
{ //
// If scaled data has yet to be computed, then compute, cache and return it.
// Otherwise just return the cached version.
//
if (null == _DataADC)
{
if (UnfilteredData is ILargeDataAware largeDataAware)
if (!largeDataAware.IsDataArraySized)
throw new Serialization.SliceRaw.File.PersistentChannel.DataTooBigForArrayException("Data is too big to be viewed or filtered.");
var persistentUnfilteredData
= UnfilteredData as Serialization.SliceRaw.File.PersistentChannel;
//double scalingFactor = AdcToMvScalingFactor;
_DataADC = new List<double>();
var dataCount = persistentUnfilteredData.Count;
for (var i = 0; i < dataCount; i++)
_DataADC.Add(persistentUnfilteredData[i]);
}
return _DataADC;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting ADC data", ex);
}
}
}
public virtual bool SupportsEU => true;
public virtual bool SupportsADC => true;
public virtual bool SupportsmV => true;
/// <summary>
/// Get/set the filtered EU data for this channel.
/// </summary>
public IList<double> DataEu
{
get
{
try
{
if (UseFilterCaching)
{
if (null == _DataEu)
return _DataEu = new List<double>(GetDataFilteredBy(CurrentFilter, DataDisplayUnits.Eu));
return _DataEu;
}
return new List<double>(GetDataFilteredBy(CurrentFilter, DataDisplayUnits.Eu));
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting filtered EU data", ex);
}
}
}
private List<double> _DataEu = null;
/// <summary>
/// Get an MV-scaled version of the data <see cref="double"/> list.
/// </summary>
public List<double> UnfilteredDataMv
{
get
{
try
{ //
// If scaled data has yet to be computed, then compute, cache and return it.
// Otherwise just return the cached version.
//
if (null == _UnfilteredDataMv)
{
if (UnfilteredData is ILargeDataAware largeDataAware)
if (!largeDataAware.IsDataArraySized)
throw new Serialization.SliceRaw.File.PersistentChannel.DataTooBigForArrayException("Data is too big to be viewed or filtered.");
if (UnfilteredData is Serialization.SliceRaw.File.PersistentChannel persistentUnfilteredData)
{
_UnfilteredDataMv = new List<double>();
var dataCount = persistentUnfilteredData.Count;
for (var i = 0; i < dataCount; i++)
{
_UnfilteredDataMv.Add(Scaler.GetMv(persistentUnfilteredData[i]));
}
}
else if (UnfilteredData is Serialization.TDAS.File.PersistentChannel tdasUnfilteredData)
{
_UnfilteredDataMv = new List<double>();
var dataCount = tdasUnfilteredData.Count;
for (var i = 0; i < dataCount; i++)
{
_UnfilteredDataMv.Add(Scaler.GetMv(tdasUnfilteredData[i]));
}
}
}
return _UnfilteredDataMv;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting MV-scaled data", ex);
}
}
}
private List<double> _UnfilteredDataMv = null;
/// <summary>
/// Get/set the filtered MV data for this channel.
/// </summary>
public List<double> DataMv
{
get
{
try
{
if (UseFilterCaching)
{
if (null == _DataMv)
return _DataMv = new List<double>(GetDataFilteredBy(CurrentFilter, DataDisplayUnits.Mv));
return _DataMv;
}
return new List<double>(GetDataFilteredBy(CurrentFilter, DataDisplayUnits.Mv));
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting filtered MV data", ex);
}
}
}
private List<double> _DataMv = null;
/// <summary>
/// Get/set the ADC->MV scale factor for this channel.
/// </summary>
public double ScaleFactorMv
{
get => Scaler.GetScaleFactorMv();
set
{
try
{
Scaler.SetScaleFactorMv(value);
_DataEu = null;
lock (previouslyFilteredDataLock)
{
_previouslyFilteredData.Clear();
}
_UnfilteredDataEu = null;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem setting " + typeof(Channel).Namespace + ".Event.Module.Channel.ScaleFactorMv property value", ex);
}
}
}
public double ScaleFactorEU
{
get => Scaler.GetScaleFactorEU();
set
{
try
{
Scaler.SetScaleFactorEU(value);
_DataEu = null;
lock (previouslyFilteredDataLock)
{
_previouslyFilteredData.Clear();
}
_UnfilteredDataEu = null;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem setting " + typeof(Channel).Namespace + ".Event.Module.Channel.ScaleFactorEU property value", ex);
}
}
}
public double UserOffsetEU
{
get => Scaler.UserOffsetEU;
set
{
Scaler.UserOffsetEU = value;
_DataEu = null;
lock (previouslyFilteredDataLock)
{
_previouslyFilteredData.Clear();
}
_UnfilteredDataEu = null;
}
}
public double Multiplier
{
get => Scaler.Multiplier;
set => Scaler.Multiplier = value;
}
public double UnitConversion
{
get => Scaler.UnitConversion;
set => Scaler.UnitConversion = value;
}
public bool AtCapacity
{
get => Scaler.BasedOnOutputAtCapacity;
set => Scaler.BasedOnOutputAtCapacity = value;
}
public double CapacityOutputIsBasedOn
{
get => Scaler.CapacityOutputIsBasedOn;
set => Scaler.CapacityOutputIsBasedOn = value;
}
public SensorConstants.SensUnits SensitivityUnits
{
get => Scaler.SensitivityUnits;
set => Scaler.SensitivityUnits = value;
}
/// <summary>
/// Get/set the sensitivity mV/EU factor for this channel.
/// </summary>
public double MvPerEu
{
set
{
try
{
Scaler.SetMvPerEu(value);
}
catch (System.Exception ex)
{
throw new Exception("encountered problem setting " + typeof(Channel).Namespace + ".Event.Module.Channel.MvPerEu property value", ex);
}
}
}
/// <summary>
/// putting this in a separate function to force that MvPerEu is not being used directly in calcuations
/// </summary>
/// <returns></returns>
public double GetMvPerEu()
{
return Scaler.GetMvPerEu();
}
public double GetScaleFactorMv()
{
return Scaler.GetScaleFactorMv();
}
/// <summary>
/// Get <see cref="bool"/> value indicating whether or not the specified channel is configured.
/// </summary>
public abstract bool IsConfigured
{
get;
set;
}
/// <summary>
/// Get the actual available maximum Adc range based on datum bit resolution.
/// </summary>
public double ActualMaxRangeAdc
{
get
{
try
{
return short.MaxValue;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem calculating actual max ADC range", ex);
}
}
}
/// <summary>
/// Get the actual available minimum ADC range based on datum bit resolution.
/// </summary>
public double ActualMinRangeAdc
{
get
{
try
{
return short.MinValue;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem calculating actual min ADC range", ex);
}
}
}
/// <summary>
/// Get the actual available maximum EU range based on scaling factor and bit resolution.
/// </summary>
public abstract double ActualMaxRangeEu { get; }
/// <summary>
/// Get the actual available minimum EU range based on scaling factor and bit resolution.
/// </summary>
public abstract double ActualMinRangeEu { get; }
public abstract double DesiredRangeEU { get; }
public abstract double SensorCapacityEU { get; }
/// <summary>
/// Get the actual available maximum MV range based on scaling factor and bit resolution.
/// </summary>
public virtual double ActualMaxRangeMv
{
get
{
try
{
return (Scaler.GetAdcToMvScalingFactor() >= 0) ? Scaler.GetMv(ActualMaxRangeAdc) : Scaler.GetMv(ActualMinRangeAdc);
}
catch (System.Exception ex)
{
throw new Exception("encountered problem calculating actual max MV range", ex);
}
}
}
/// <summary>
/// Get the actual available minimum MV range based on scaling factor and bit resolution.
/// </summary>
public virtual double ActualMinRangeMv
{
get
{
try
{
return (Scaler.GetAdcToMvScalingFactor() >= 0) ? Scaler.GetMv(ActualMinRangeAdc) : Scaler.GetMv(ActualMaxRangeAdc);
}
catch (System.Exception ex)
{
throw new Exception("encountered problem calculating actual min MV range", ex);
}
}
}
/// <summary>
/// Compute data min and max for this channel.
/// </summary>
///
/// <param name="dataMinAdc">
/// The <see cref="double"/> data min <see cref="Property"/> to be populated with
/// the min result of this method.
/// </param>
///
/// <param name="datMaxAdc">
/// The <see cref="double"/> data max <see cref="Property"/> to be populated with
/// the max result of this method.
/// </param>
///
private void ComputeDataMinMaxAdc(Property<double> dataMinAdc, Property<double> dataMaxAdc)
{
try
{
if (UnfilteredData is Serialization.TDAS.File.PersistentChannel) //temp
{
ComputeTDASDataMinMaxAdc(dataMinAdc, dataMaxAdc);
}
else
{
var dataCount = (UnfilteredData is Serialization.SliceRaw.File.PersistentChannel persistentChannel)
? persistentChannel.Count // use "persistent channel" count
: UnfilteredData.Count;
if (dataCount <= 0)
throw new Exception("channel has no data");
{
// Find the max and min in raw ADC.
double min, max;
if (!(UnfilteredData is Serialization.SliceRaw.File.PersistentChannel data))
throw new ApplicationException("attempting to use channel data object as memory-mapped file, but it apparently is not one");
min = max = data[0];
for (var i = 1; i < dataCount; i++)
{
min = Math.Min(min, data[i]);
max = Math.Max(max, data[i]);
}
dataMinAdc.Value = min;
dataMaxAdc.Value = max;
}
}
}
catch (System.Exception ex)
{
throw new Exception("encountered problem computing channel data min/max", ex);
}
}
private void ComputeTDASDataMinMaxAdc(Property<double> dataMinAdc, Property<double> dataMaxAdc)
{
try
{
var dataCount = (UnfilteredData is Serialization.TDAS.File.PersistentChannel persistentChannel)
? persistentChannel.Count // use "persistent channel" count
: UnfilteredData.Count;
if (dataCount <= 0)
throw new Exception("channel has no data");
{
// Find the max and min in raw ADC.
double min, max;
if (!(UnfilteredData is Serialization.TDAS.File.PersistentChannel data))
throw new ApplicationException("attempting to use channel data object as memory-mapped file, but it apparently is not one");
min = max = data[0];
for (var i = 1; i < dataCount; i++)
{
min = Math.Min(min, data[i]);
max = Math.Max(max, data[i]);
}
dataMinAdc.Value = min;
dataMaxAdc.Value = max;
}
}
catch (System.Exception ex)
{
throw new Exception("encountered problem computing channel data min/max", ex);
}
}
/// <summary>
/// Compute the min and max values in the given data vector.
/// </summary>
///
/// <param name="dataMin">
/// Returns the minimum <see cref="double"/> data value in the specified data vector.
/// </param>
///
/// <param name="dataMax">
/// Returns the maximum <see cref="double"/> data value in the specified data vector.
/// </param>
///
/// <param name="data">
/// The array of <see cref="double"/>s to be scoured for min and max values.
/// </param>
///
private void ComputeDataMinMax(out double dataMin, out double dataMax, double[] data)
{
try
{
if (null == data)
throw new ArgumentException("cannot process null data reference");
if (data.Length <= 0)
throw new ArgumentException("cannot process empty data vector");
dataMin = dataMax = data[0];
for (var i = 0; i < data.Length; i++)
{
dataMin = Math.Min(dataMin, data[i]);
dataMax = Math.Max(dataMax, data[i]);
}
}
catch (System.Exception ex)
{
throw new Exception("encountered problem computing data vector min/max", ex);
}
}
/// <summary>
/// Get the <see cref="double"/> data min in ADC.
/// </summary>
public double DataMinAdc
{
get
{
try
{
if (!_DataMinAdc.IsInitialized)
ComputeDataMinMaxAdc(_DataMinAdc, _DataMaxAdc);
return _DataMinAdc.Value;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting " + typeof(Channel).Namespace + ".Event.Module.Channel.DataMinAdc", ex);
}
}
}
private readonly Property<double> _DataMinAdc
= new Property<double>(
typeof(Channel).Namespace + ".Event.Module.Channel.DataMinAdc",
0.0,
false
);
/// <summary>
/// Get the <see cref="double"/> data min in EU.
/// </summary>
public abstract double DataMinEu { get; }
/// <summary>
/// Get the <see cref="double"/> data min in MV.
/// </summary>
public double DataMinMv => (Scaler.GetAdcToMvScalingFactor() >= 0) ?
Scaler.GetMv(DataMinAdc) :
Scaler.GetMv(DataMaxAdc);
/// <summary>
/// Get the <see cref="double"/> data max in ADC.
/// </summary>
public double DataMaxAdc
{
get
{
try
{
if (!_DataMaxAdc.IsInitialized)
ComputeDataMinMaxAdc(_DataMinAdc, _DataMaxAdc);
return _DataMaxAdc.Value;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting " + typeof(Channel).Namespace + ".Event.Module.Channel.DataMaxAdc", ex);
}
}
}
private readonly Property<double> _DataMaxAdc
= new Property<double>(
typeof(Channel).Namespace + ".Event.Module.Channel.DataMaxAdc",
0.0,
false
);
/// <summary>
/// Get the <see cref="double"/> data max in EU.
/// </summary>
public abstract double DataMaxEu { get; }
/// <summary>
/// Populate the specified filter-index'd dictionaries with the min/max values for the
/// specified filter setting.
/// </summary>
///
/// <param name="filteredMins">
/// The <see cref="ChannelFilter"/>-indexed Dictionary of
/// <see cref="double"/> data min values.
/// </param>
///
/// <param name="filteredMaxs">
/// The <see cref="ChannelFilter"/>-indexed Dictionary of
/// <see cref="double"/> data max values.
/// </param>
///
/// <param name="filter">
/// The <see cref="ChannelFilter"/> to be applied to the the channel's data prior to
/// the min/max calculation.
/// </param>
///
private void PopulateFilteredMinMaxValues(IDictionary<double, double> filteredMins,
IDictionary<double, double> filteredMaxs,
ChannelFilter filter)
{
try
{
ComputeDataMinMax(out double min, out double max, CurrentFilter.Apply(this, DataDisplayUnits.Eu, Serialization.File.UseLegacyTDCSoftwareFiltering));
filteredMins[CurrentFilter.CutoffFrequencyHz] = min;
filteredMaxs[CurrentFilter.CutoffFrequencyHz] = max;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem propulating filtered min/max values", ex);
}
}
/// <summary>
/// Get the minimum EU data value for the current filtering.
/// </summary>
public double DataMinFilteredEu
{
get
{
try
{
if (!_DataMinFilteredEu.Keys.Contains(CurrentFilter.CutoffFrequencyHz))
PopulateFilteredMinMaxValues(_DataMinFilteredEu, _DataMaxFilteredEu, CurrentFilter.Type);
return _DataMinFilteredEu[CurrentFilter.CutoffFrequencyHz];
}
catch (System.Exception ex)
{
throw new Exception(
"encountered problem getting min filtered EU on DAS: " + ((null != ParentModule && null != ParentModule.DasSerialNumber) ? ParentModule.DasSerialNumber : "<NULL>") + ", Channel: " + Number.ToString(),
ex
);
}
}
}
private readonly IDictionary<double, double> _DataMinFilteredEu
= new Dictionary<double, double>();
/// <summary>
/// Get the maximum EU data value for the current filtering.
/// </summary>
public double DataMaxFilteredEu
{
get
{
try
{
if (!_DataMaxFilteredEu.Keys.Contains(CurrentFilter.CutoffFrequencyHz))
PopulateFilteredMinMaxValues(_DataMinFilteredEu, _DataMaxFilteredEu, CurrentFilter.Type);
return _DataMaxFilteredEu[CurrentFilter.CutoffFrequencyHz];
}
catch (System.Exception ex)
{
throw new Exception(
"encountered problem getting max filtered EU on DAS: " + ((null != ParentModule && null != ParentModule.DasSerialNumber) ? ParentModule.DasSerialNumber : "<NULL>") + ", Channel: " + Number.ToString(),
ex
);
}
}
}
private readonly IDictionary<double, double> _DataMaxFilteredEu
= new Dictionary<double, double>();
/// <summary>
/// Get the <see cref="double"/> data max in MV.
/// </summary>
public double DataMaxMv => (Scaler.GetAdcToMvScalingFactor() >= 0) ?
Scaler.GetMv(DataMaxAdc) :
Scaler.GetMv(DataMinAdc);
/// <summary>
/// Get the <see cref="double"/> data range of this channel in ADC.
/// </summary>
public double DataRangeAdc
{
get
{
try
{
if (!_DataRangeAdc.IsInitialized)
return _DataRangeAdc.Value = DataMaxAdc - DataMinAdc;
return _DataRangeAdc.Value;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting " + typeof(Channel).Namespace + ".Event.Module.Channel.DataRangeAdc", ex);
}
}
}
private readonly Property<double> _DataRangeAdc
= new Property<double>(
typeof(Channel).Namespace + ".Event.Module.Channel.DataRangeAdc",
0.0,
false
);
/// <summary>
/// Get the <see cref="double"/> data range in EU.
/// </summary>
public abstract double DataRangeEu { get; }
/// <summary>
/// Get the <see cref="double"/> data range in MV.
/// </summary>
public double DataRangeMv => Math.Abs(Scaler.GetMv(DataRangeAdc));
/// <summary>
/// Get the <see cref="double"/> data range/2 of this channel in ADC.
/// </summary>
public double DataHalfRangeValueAdc
{
get
{
try
{
if (!_DataHalfRangeValueAdc.IsInitialized)
return _DataHalfRangeValueAdc.Value = (DataMaxAdc + DataMinAdc) / 2;
return _DataHalfRangeValueAdc.Value;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting " + typeof(Channel).Namespace + ".Event.Module.Channel.DataMeanAdc", ex);
}
}
}
private readonly Property<double> _DataHalfRangeValueAdc
= new Property<double>(
typeof(Channel).Namespace + ".Event.Module.Channel.DataHalfRangeValueAdc",
0.0,
false
);
/// <summary>
/// Get the <see cref="double"/> data range/2 in EU.
/// </summary>
public abstract double DataHalfRangeValueEu { get; }
/// <summary>
/// Get the <see cref="double"/> data range/2 in MV.
/// </summary>
public double DataHalfRangeValueMv => Scaler.GetMv(DataHalfRangeValueAdc);
/// <summary>
/// Get/set <see cref="double"/> noise as percentage of full scale value for this channel.
/// </summary>
public double NoiseAsPercentageOfFullScale
{
get => _NoiseAsPercentageOfFullScale.Value;
set => _NoiseAsPercentageOfFullScale.Value = value;
}
private readonly Property<double> _NoiseAsPercentageOfFullScale
= new Property<double>(
typeof(Channel).Namespace + ".Event.Module.Channel.NoiseAsPercentageOfFullScale",
0.0,
false
);
/// <summary>
/// Get the pre-test zero level (in ADC).
/// </summary>
public short PreTestZeroLevelAdc
{
get => _PreTestZeroLevelAdc.Value;
set => _PreTestZeroLevelAdc.Value = value;
}
private readonly Property<short> _PreTestZeroLevelAdc
= new Property<short>(
typeof(Channel).Namespace + ".Event.Module.Channel.PreTestZeroLevelAdc",
0,
false
);
//zeroMvInADC
public short ZeroMvInADC
{
get => _ZeroMvInADC.Value;
set => _ZeroMvInADC.Value = value;
}
private readonly Property<short> _ZeroMvInADC
= new Property<short>(
typeof(Channel).Name + ".Event.Module.Channel.ZeroMvInADC",
0,
false
);
/// <summary>
/// Window Average ADC is the average ADC over the zeroing window specified for the channel
/// short.MinValue indicates an invalid or uninitialized value
/// </summary>
public short WindowAverageADC
{
get => _WindowAverageADC.Value;
set => _WindowAverageADC.Value = value;
}
private readonly Property<short> _WindowAverageADC
= new Property<short>(
typeof(Channel).Name + ".Event.Module.Channel.WindowAverageADC",
short.MinValue,
false
);
/// <summary>
/// Get the pre-test zero level (in ADC).
/// </summary>
public double PreTestZeroLevelMv
{
get
{
if (_PreTestZeroLevelMv.IsValueInitialized)
{
return _PreTestZeroLevelMv.Value;
}
return 0D;
}
set => _PreTestZeroLevelMv.Value = value;
}
private readonly Property<double> _PreTestZeroLevelMv
= new Property<double>(
typeof(Channel).Namespace + ".Event.Module.Channel.PreTestZeroLevelMv",
0D,
true
);
public int RemovedADC
{
get
{
if (_removedADC.IsValueInitialized)
{
return _removedADC.Value;
}
return 0;
}
set
{
_removedADC.Value = value;
Scaler.SetRemovedADC(value);
}
}
private readonly Property<int> _removedADC
= new Property<int>(
typeof(Channel).Namespace + ".Event.Module.Channel.RemovedADC",
0,
true
);
public int RemovedInternalADC
{
get
{
if (_removedInternalADC.IsValueInitialized)
{
return _removedInternalADC.Value;
}
return 0;
}
set
{
_removedInternalADC.Value = value;
Scaler.SetRemovedInternalADC(value);
}
}
private readonly Property<int> _removedInternalADC
= new Property<int>(
typeof(Channel).Namespace + ".Event.Module.Channel.RemovedInternalADC",
0,
true
);
/// <summary>
/// the order of this channel among all channels when displaying channels
/// AbsoluteNumber on the other hand refers to physical order
/// -1 is an uninitialized value, which means channels will be sorted by AbsoluteNumber instead
/// </summary>
public int AbsoluteDisplayOrder
{
get
{
if (_absoluteDisplayOrder.IsValueInitialized) { return _absoluteDisplayOrder.Value; }
return -1;
}
set => _absoluteDisplayOrder.Value = value;
}
private readonly Property<int> _absoluteDisplayOrder = new Property<int>(
typeof(Channel).Namespace + ".Event.Module.Channel.AbsoluteDisplayOrder",
-1,
true);
/// <summary>
/// Get data zero level counts.
/// </summary>
public abstract short DataZeroLevelAdc
{
get;
}
/// <summary>
/// Get/Set channel Last Calibration Date
/// </summary>
public DateTime LastCalibrationDate
{
get => _LastCalibrationDate.Value;
set => _LastCalibrationDate.Value = value;
}
private readonly Property<DateTime> _LastCalibrationDate
= new Property<DateTime>(
typeof(Channel).Namespace + ".Event.Module.Channel.LastCalibrationDate",
(DateTime)System.Data.SqlTypes.SqlDateTime.MinValue,
true
);
public bool IsLastCalibrationDateValid => _LastCalibrationDate.IsInitialized;
/// <summary>
/// Get/Set channel Last Calibration Date
/// </summary>
public DateTime CalDueDate
{
get => _CalDueDate.Value;
set => _CalDueDate.Value = value;
}
private readonly Property<DateTime> _CalDueDate
= new Property<DateTime>(
typeof(Channel).Namespace + ".Event.Module.Channel.CalDueDate",
(DateTime)System.Data.SqlTypes.SqlDateTime.MinValue,
true
);
public bool IsCalDueDateValid => _CalDueDate.IsInitialized;
public string SensorID
{
get => _SensorID.Value;
set => _SensorID.Value = value;
}
private readonly Property<string> _SensorID
= new Property<string>(
typeof(Channel).Namespace + ".Event.Module.Channel.SensorID",
"",
true
);
public bool IsSensorIDValid => _SensorID.IsInitialized;
public double OffsetToleranceLowMv
{
get => _offsetToleranceLowMv.Value;
set => _offsetToleranceLowMv.Value = value;
}
private readonly Property<double> _offsetToleranceLowMv
= new Property<double>(
typeof(Channel).Namespace + ".Event.Module.Channel.OffsetToleranceLowMv",
0D,
true
);
public bool IsOffsetToleranceLowMvValid => _offsetToleranceLowMv.IsInitialized;
public double OffsetToleranceHighMv
{
get => _offsetToleranceHighMv.Value;
set => _offsetToleranceHighMv.Value = value;
}
private readonly Property<double> _offsetToleranceHighMv
= new Property<double>(
typeof(Channel).Namespace + ".Event.Module.Channel.OffsetToleranceHighMv",
0D,
true
);
public bool IsOffsetToleranceHighMvValid => _offsetToleranceHighMv.IsInitialized;
public string IsoChannelName
{
get => _isoChannelName.Value;
set => _isoChannelName.Value = value;
}
private readonly Property<string> _isoChannelName
= new Property<string>(
typeof(Channel).Namespace + ".Event.Module.Channel.IsoChannelName",
"",
true
);
public bool IsIsoChannelNameValid => _isoChannelName.IsInitialized;
public string UserCode
{
get => _userCode.Value;
set => _userCode.Value = value;
}
private readonly Property<string> _userCode
= new Property<string>(
typeof(Channel).Namespace + ".Event.Module.Channel.UserCode",
"",
true
);
public bool IsUserCodeValid => _userCode.IsInitialized;
public string UserChannelName
{
get => _userChannelName.Value;
set => _userChannelName.Value = value;
}
private readonly Property<string> _userChannelName
= new Property<string>(
typeof(Channel).Namespace + ".Event.Module.Channel.UserChannelName",
"",
true
);
public string LinearSensorCalibration
{
get => _linearSensorCalibration.Value;
set => _linearSensorCalibration.Value = value;
}
private readonly Property<string> _linearSensorCalibration
= new Property<string>(
typeof(Channel).Namespace + ".Event.Module.Channel.LinearSensorCalibration",
"",
true
);
public bool IsUserChannelNameValid => _userChannelName.IsInitialized;
/// <summary>
/// Get/set channel subsample indicator.
/// </summary>
public bool IsSubsampled
{
get => _IsSubsampled.Value;
set => _IsSubsampled.Value = value;
}
private readonly Property<bool> _IsSubsampled
= new Property<bool>(
typeof(Channel).Namespace + ".Event.Module.Channel.IsSubsampled",
false,
true
);
/// <summary>
/// Get/set channel unsubsampled sample rate.
/// </summary>
public float UnsubsampledSampleRateHz
{
get => _UnsubsampledSampleRateHz.Value;
set => _UnsubsampledSampleRateHz.Value = value;
}
private readonly Property<float> _UnsubsampledSampleRateHz
= new Property<float>(
typeof(Channel).Namespace + ".Event.Module.Channel.UnsubsampledSampleRateHz",
0,
true
);
/// <summary>
/// Get/set the sample rate for this test module.
/// </summary>
public bool IsSupersampled
{
get => _IsSupersampled.Value;
set => _IsSupersampled.Value = value;
}
private readonly Property<bool> _IsSupersampled
= new Property<bool>(
typeof(Module).Namespace + ".Event.Module.Channel.IsSupersampled",
false,
false
);
/// <summary>
/// Get/set whether viewing and exporting this channel should use the EU Scalar.
/// </summary>
public bool UseEUScaler
{
get => _UseEUScalar.Value;
set => _UseEUScalar.Value = value;
}
private readonly Property<bool> _UseEUScalar
= new Property<bool>(
typeof(Module).Namespace + ".Event.Module.Channel.UseEUScaler",
false,
false
);
/// <summary>
/// Get/set the sample rate for this test module.
/// </summary>
public float UnsupersampledSampleRateHz
{
get => _UnsupersampledSampleRateHz.Value;
set => _UnsupersampledSampleRateHz.Value = value;
}
private readonly Property<float> _UnsupersampledSampleRateHz
= new Property<float>(
typeof(Module).Namespace + ".Event.Module.Channel.UnsupersampledSampleRateHz",
0,
false
);
public void ClearDataCache()
{
var filtering = UseFilterCaching;
_Data = null;
_DataEu = null;
_DataMv = null;
_UnfilteredDataEu = null;
_DataADC = null;
lock (previouslyFilteredDataLock)
{
_previouslyFilteredData.Clear();
}
UseFilterCaching = filtering;
}
/// <summary>
/// Create the matching Event.Module.Channel-based representation of the specified
/// DTS.DASLib.Service.DASChannel-based object.
/// </summary>
///
/// <param name="channel">
/// The <see cref="DTS.DASLib.Service.DASChannel"/> object to be represented.
/// </param>
///
/// <param name="parentModule">
/// The <see cref="DTS.Slice.Control.Event.Module"/> that contains the created channel.
/// </param>
///
/// <returns>
/// The <see cref="DTS.Slice.Control.Event.Module.Channel"/>-based representation of the specified
/// channel object.
/// </returns>
///
/// <param name="absoluteNumber">
/// The unique "absolute" <see cref="int"/> number of the channel with respect to all other channels
/// on all other DASes in the system.
/// </param>
///
public static Channel CreateChannel(DASChannel channel, Module parentModule, int absoluteNumber)
{
try
{
switch (channel.GetType().FullName)
{
case "DTS.DASLib.Service.AnalogInputDASChannel":
return new AnalogInputChannel(channel, parentModule, absoluteNumber);
case "DTS.DASLib.Service.IEPEChannel":
return new IEPEInputChannel(channel, parentModule, absoluteNumber);
case "DTS.DASLib.Service.OutputSquibChannel":
{
var osc = channel as OutputSquibChannel;
var output = new SquibEventChannel(channel, parentModule, absoluteNumber);
output.MeasurementType = osc.MeasurementType;
output.ChannelName2 = osc.ChannelName2;
if (osc.MeasurementType == SquibMeasurementType.CURRENT)
{
if (osc.SquibDescription.EndsWith(".1"))
{
var newName = osc.SquibDescription.Substring(0,
osc.SquibDescription.Length - 2);
newName += ".2";
output.ChannelName2 = output.ChannelName2.Replace(osc.SquibDescription, newName);
}
}
output.ChannelId = osc.ChannelId;
output.Sensor = osc.Sensor;
output.SerialNumber = osc.SerialNumber;
output.ChannelGroupName = osc.ChannelGroupName;
return output;
}
case "DTS.DASLib.Service.OutputTOMDigitalChannel":
{
return new SquibDigitalChannel(channel, parentModule, absoluteNumber);
}
case "DTS.DASLib.Service.TimestampDASChannel":
{
return new TimestampChannel(channel, parentModule, absoluteNumber);
}
case "DTS.DASLib.Service.StreamInputDASChannel":
{
return new StreamInputChannel(channel, parentModule, absoluteNumber);
}
case "DTS.DASLib.Service.CANInputDASChannel":
{
return new CANInputChannel(channel, parentModule, absoluteNumber);
}
default:
throw new NotImplementedException("cannot create a " + typeof(Channel).FullName + "-based representation of a " + channel.GetType().FullName + " object");
}
}
catch (System.Exception ex)
{
throw new ApplicationException("encountered problem creating channel", ex);
}
}
/// <summary>
/// Create the matching Event.Module.Channel-based representation of the specified
/// DTS.DASLib.Service.DASChannel-based object.
/// </summary>
///
/// <param name="channel">
/// The <see cref="DTS.DASLib.Service.DASChannel"/> object to be represented.
/// </param>
///
/// <param name="parentModule">
/// The <see cref="DTS.Slice.Control.Event.Module"/> that contains the created channel.
/// </param>
///
/// <returns>
/// The <see cref="DTS.Slice.Control.Event.Module.Channel"/>-based representation of the specified
/// channel object.
/// </returns>
///
/// <param name="absoluteNumber">
/// The unique "absolute" <see cref="int"/> number of the channel with respect to all other channels
/// on all other DASes in the system.
/// </param>
///
public static Channel CreateChannel(Serialization.Test.Module.Channel channel, Module parentModule, int absoluteNumber)
{
try
{
switch (channel.GetType().FullName)
{
case "DTS.Serialization.Test+Module+AnalogInputChannel":
return new AnalogInputChannel(channel, parentModule, absoluteNumber);
case "DTS.Serialization.Test+Module+CalculatedChannel":
return new AnalogInputChannel(channel, parentModule, absoluteNumber);
default:
throw new NotImplementedException("cannot create a " + typeof(Channel).FullName + "-based representation of a " + channel.GetType().FullName + " object");
}
}
catch (System.IO.InvalidDataException ex2) { throw ex2; }
catch (System.Exception ex)
{
throw new ApplicationException("encountered problem creating channel", ex);
}
}
/// <summary>
/// Set the appropriate properties in this class from the equivalent properties
/// of the specified object.
/// </summary>
///
///<param name="dasChannel">
/// The <see cref="DTS.DASLib.Service.DASChannel"/> object containing the
/// property values to be copied.
/// </param>
///
public abstract void SetPropertyValuesFrom(DASChannel dasChannel);
/// <summary>
/// Set the appropriate properties in this class from the equivalent properties
/// of the specified object.
/// </summary>
///
///<param name="diagResults">
/// The <see cref="DTS.DASLib.Service.DiagnosticsResult"/> object containing the
/// property values to be copied.
/// </param>
///
public virtual void SetPropertyValuesFrom(IDiagnosticResult diagResults)
{
try
{
if (null == diagResults)
throw new ArgumentNullException("cannot set property values from null " + typeof(DiagnosticsResult).FullName);
ScaleFactorEU = diagResults.ScalefactorEngineeringUnitsPerADC;
ScaleFactorMv = diagResults.ScalefactorMilliVoltsPerADC;
if (this is AnalogInputChannel)
{
Scaler.IEPE = (this as AnalogInputChannel).Bridge == SensorConstants.BridgeType.IEPE;
}
try
{
if (this is AnalogInputChannel)
{
Scaler.Digital = (this as AnalogInputChannel).Bridge == SensorConstants.BridgeType.DigitalInput;
}
else { Scaler.Digital = false; }
}
catch (System.Exception) { }
if (this is IShuntAware)
{
if (null != diagResults.MeasuredShuntDeflectionMv)
(this as IShuntAware).MeasuredShuntDeflectionMv = (double)diagResults.MeasuredShuntDeflectionMv;
if (null != diagResults.TargetShuntDeflectionMv)
(this as IShuntAware).TargetShuntDeflectionMv = (double)diagResults.TargetShuntDeflectionMv;
}
if (this is ICalSignalAware)
{
if (null != diagResults.MeasuredCalSignalMv)
(this as ICalSignalAware).MeasuredCalSignalMv = (double)diagResults.MeasuredCalSignalMv;
if (null != diagResults.TargetCalSignalMv)
(this as ICalSignalAware).TargetCalSignalMv = (double)diagResults.TargetCalSignalMv;
}
try
{
NoiseAsPercentageOfFullScale = null != diagResults.NoisePercentFullScale ? (double)diagResults.NoisePercentFullScale : 0.0;
}
catch (InvalidOperationException)
{
throw new UserException("Diagnostics service did not return a value for requested \"noise as percentage of full scale\" statistic");
}
if (null != diagResults.FinalOffsetADC)
{
try
{
PreTestZeroLevelAdc = (short)diagResults.FinalOffsetADC;
}
catch (InvalidOperationException)
{
throw new UserException("Diagnostics service did not return a value for requested \"final offset\" statistic");
}
}
else
{
PreTestZeroLevelAdc = 0;
}
ZeroMvInADC = Convert.ToInt16(diagResults.ZeroMVInADC);
WindowAverageADC = Convert.ToInt16(diagResults.WindowAverageADC);
if (null != diagResults.MeasuredOffsetMilliVolts)
{
try
{
PreTestZeroLevelMv = (double)diagResults.MeasuredOffsetMilliVolts;
}
catch (InvalidOperationException)
{
/*throw new UserException( "diagnostics service did not return a value for requested \"measured offset\" statistic" ); */
PreTestZeroLevelMv = 0D;
}
}
else { PreTestZeroLevelMv = 0D; }
}
catch (System.Exception ex)
{
throw new Exception("encountered problem setting property value from " + (null != diagResults ? diagResults.GetType().FullName : "<<NULL>>") + " object", ex);
}
try
{
if (null != diagResults.RemovedOffsetADC)
{
RemovedADC = (short)diagResults.RemovedOffsetADC;
}
else { RemovedADC = 0; }
}
catch (System.Exception) { }
}
///// <summary>
///// Get the list of available filters.
///// </summary>
public List<IFilter> AvailableFilters => _AvailableFilters.Value;
private readonly Property<List<IFilter>> _AvailableFilters
= new Property<List<IFilter>>(
typeof(Channel).Namespace + ".Event.Module.Channel.AvailableFilters",
new List<IFilter>(),
true
);
/// <summary>
/// Get/set the default filter for this channel.
/// </summary>
public IFilter CurrentFilter
{
get => _CurrentFilter.Value;
set
{ //
// Might be lots of gratuitous "changing" of filter to the same value, since
// last I checked it happens every time you flip from one channel to another
// in the data viewer. Anyway, if nothing has changed, don't force a reload
// of the cached data.
//
if (_CurrentFilter.Value == null
|| !value.Name.Equals(_CurrentFilter.Value.Name, StringComparison.OrdinalIgnoreCase))
{ //
// Clear filtered data caches and set new filter value.
//
_Data = null;
_DataEu = null;
_DataMv = null;
_CurrentFilter.Value = value;
}
}
}
private readonly Property<IFilter> _CurrentFilter = new Property<IFilter>(typeof(Channel).Namespace + ".Event.Module.Channel.CurrentFilter",
null,
true
);
/// <summary>
/// Get/set the default filter for this channel.
/// </summary>
public IFilter DefaultFilter
{
get => _defaultFilter.Value;
set
{
if (_defaultFilter.Value == null || !value.Name.Equals(_defaultFilter.Value.Name, StringComparison.OrdinalIgnoreCase))
{
_Data = null;
_DataEu = null;
_DataMv = null;
_defaultFilter.Value = value;
}
}
}
private readonly Property<IFilter> _defaultFilter = new Property<IFilter>(typeof(Channel).Namespace + ".Event.Module.Channel.DefaultFilter", null, true);
public string FileName
{
get => _FileName.Value;
set => _FileName.Value = value;
}
private readonly Property<string> _FileName
= new Property<string>(
typeof(Channel).Namespace + ".Event.Module.Channel.FileName",
"",
true
);
protected static readonly object DisplayUnitLock = new object();
protected static readonly object previouslyFilteredDataLock = new object();
public void UnSet()
{
if (null != _previouslyFilteredData) { _previouslyFilteredData.Clear(); }
if (null != _DataEu) { _DataEu.Clear(); _DataEu = null; }
if (null != _UnfilteredDataEu) { _UnfilteredDataEu.Clear(); _UnfilteredDataEu = null; }
System.Runtime.GCSettings.LatencyMode = System.Runtime.GCLatencyMode.Batch;
System.Runtime.GCSettings.LargeObjectHeapCompactionMode = System.Runtime.GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();
}
/// <summary>
/// Get the channel data after filtering by the specified filter.
/// </summary>
///
/// <param name="filter">
/// The <see cref="IFilter"/> to be applied to the channel.
/// </param>
/// <param name="displayUnits"></param>
/// <returns>
/// The requested filtered channel <see cref="double"/> data.
/// </returns>
///
public double[] GetDataFilteredBy(IFilter filter, DataDisplayUnits displayUnits)
{
try
{
double[] filteredData;
if (UseFilterCaching)
{
IDictionary<DataDisplayUnits, double[]> displayUnitData;
lock (previouslyFilteredDataLock)
{
if (!_previouslyFilteredData.Keys.Contains(filter.Name))
_previouslyFilteredData.Add(filter.Name, new Dictionary<DataDisplayUnits, double[]>());
// First cache key should now exist, so work it, baby!
displayUnitData = _previouslyFilteredData[filter.Name];
}
lock (DisplayUnitLock)
{
if (displayUnitData.Keys.Contains(displayUnits))
filteredData = displayUnitData[displayUnits];
else
{
try
{
displayUnitData.Add(displayUnits, filteredData = filter.Apply(this, displayUnits, Serialization.File.UseLegacyTDCSoftwareFiltering));
}
catch (System.Exception ex)
{
throw new Exception("encountered problem adding; displayUnits " + displayUnits, ex);
}
}
}
}
else filteredData = filter.Apply(this, displayUnits, Serialization.File.UseLegacyTDCSoftwareFiltering);
// By hook or crook, filter data should be here.
return filteredData;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting data filtered by channel filter " + (null != filter && null != filter.Name ? "\"" + filter.Name + "\"" : "<NULL>"), ex);
}
}
private readonly IDictionary<string, IDictionary<DataDisplayUnits, double[]>> _previouslyFilteredData
= new Dictionary<string, IDictionary<DataDisplayUnits, double[]>>();
/// <summary>
/// Test the specified object for equality with this object.
/// </summary>
///
/// <param name="obj">
/// The <see cref="object"/> to be tested for equality.
/// </param>
///
/// <returns>
/// <see cref="bool"/> true if the specified object has memeberwise equality with
/// this object; false otherwise.
/// </returns>
///
public override bool Equals(object obj)
{
try
{
var that = obj as Channel;
return null != obj
&& DataEquals(that.UnfilteredData)
&& Number.Equals(that.Number)
&& PreTestZeroLevelAdc.Equals(that.PreTestZeroLevelAdc)
&& IsSubsampled.Equals(that.IsSubsampled)
&& UnsubsampledSampleRateHz.Equals(that.UnsubsampledSampleRateHz)
&& IsSupersampled.Equals(that.IsSupersampled)
&& UseEUScaler.Equals(that.UseEUScaler)
&& UnsupersampledSampleRateHz.Equals(that.UnsupersampledSampleRateHz)
&& _TimeOfFirstSampleSec.IsInitialized == that._TimeOfFirstSampleSec.IsInitialized && (TimeOfFirstSampleSecValid ? TimeOfFirstSampleSec == that.TimeOfFirstSampleSec : true)
&& Start.ToString().Equals(that.Start.ToString())
&& (ZeroMvInADC == that.ZeroMvInADC)
&& (WindowAverageADC == that.WindowAverageADC)
&& (UserCode == that.UserCode)
&& (IsoChannelName == that.IsoChannelName)
&& (UserChannelName == that.UserChannelName);
}
catch (System.Exception ex)
{
throw new Exception(
string.Format(
Strings.DTS_Slice_Control_Equals_ComparisonFailedString, null != obj ? "\"" + obj.ToString() + "\"" : Strings.DTS_Slice_Control_Event_Event_NullDasListString),
ex);
}
}
/// <summary>
/// Test the specified object's data list for equality with this object's
/// data list.
/// </summary>
///
/// <param name="thoseData">
/// The List of <see cref="UInt16"/> data objects to be compared
/// for equality with this module's equivalent.
/// </param>
///
/// <returns>
/// <see cref="bool"/> true if the two lists contain equivalent-valued members;
/// false otherwise.
/// </returns>
///
private bool DataEquals(List<short> thoseData)
{
try
{
if (null == thoseData || Data.Count != thoseData.Count)
return false;
for (var i = 0; i < thoseData.Count; i++)
if (!UnfilteredData[i].Equals(thoseData[i]))
return false;
return true;
}
catch (System.Exception ex)
{
throw new Exception(Strings.DTS_Slice_Control_Event_Module_Channel_DataEquals_ComparisonFailedString, ex);
}
}
/// <summary>
/// Return the hash code for this object.
/// </summary>
///
/// <returns>
/// The <see cref="int"/> hash code for this object.
/// </returns>
///
public override int GetHashCode()
{
try
{
return base.GetHashCode();
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting has code for " + GetType().FullName, ex);
}
}
/// <summary>
/// Convert this object to a DTS.Serialization.Test.Module.Channel.
/// </summary>
///
/// <returns>
/// A <see cref="DTS.Serialization.Test.Module.Channel"/> equivalent for this object.
/// </returns>
///
public abstract Serialization.Test.Module.Channel ToDtsSerializationTestModuleChannel(Serialization.Test.Module parentModule);
/// <summary>
/// Initialize this object from the specified DTS.Serialization.Test.Module.Channel.
/// </summary>
///
/// <param name="that">
/// A <see cref="DTS.Serialization.Test.Module.Channel"/> from which to initialize this object.
/// </param>
///
public abstract void FromDtsSerializationTestModuleChannel(Serialization.Test.Module.Channel that);
}
}
}
}