/*
* DTS.Slice.Control.Event.Module.Channel.SaeJ211Filter.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
using System;
using DTS.Common.DAS.Concepts.DAS.Channel;
using DTS.Common.Utilities;
using DTS.Common.Utilities.DotNetProgrammingConstructs;
using DTS.Common.Utilities.Logging;
using DTS.Common.Utilities.SaeJ211;
namespace DTS.Slice.Control
{
public partial class Event
{ // *** see DTS.Slice.Control.Event.cs ***
public partial class Module
{ // *** see DTS.Slice.Control.Event.Module.cs ***
public partial class Channel
{ // *** see DTS.Slice.Control.Event.Module.Channel.cs ***
///
/// Base class for all SaeJ211-based event module channel filters. It is intended
/// that fixed-filter-setting filters be derived from this class that will set their
/// filter setting using the protected constructor.
///
public class SaeJ211Filter
: Filter
{
public SaeJ211Filter(SaeJ211Filter originalFilter)
{
OriginalType = originalFilter.OriginalType;
_CutoffFrequencyHz.Value = originalFilter.CutoffFrequencyHz;
}
///
/// Initialize an instance of the DTS.Utility.SaeJ211Filter class.
///
///
///
/// The to be applied by this filter (ad hoc
/// filters that correspond to CFC values will be converted to the CFC, hence the
/// "original" qualification).
///
///
public SaeJ211Filter(ChannelFilter originalType)
{
try
{
switch (OriginalType = originalType)
{ //
// Try to set the frequency value according to type. Note that we can't set to
// "ad hoc" using this particular constructor as we don't know what frequency
// should be associated with it.
//
case ChannelFilter.AdHoc:
throw new Exception("cannot initialize SaeJ211 filter using only ChannelFilter of type " + OriginalType.ToString());
default:
_CutoffFrequencyHz.Value = (double)originalType;
break;
}
}
catch (System.Exception ex)
{
throw new Exception("encountered problem constructing " + GetType().FullName, ex);
}
}
///
/// Initialize an instance of the DTS.Utility.SaeJ211Filter class.
///
///
///
///The ad hoc frequency of this filter.
///
///
public SaeJ211Filter(double cutoffFrequencyHz)
{
try
{
OriginalType = ChannelFilter.AdHoc;
_CutoffFrequencyHz.Value = cutoffFrequencyHz;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem constructing " + GetType().FullName, ex);
}
}
///
/// Get value indicating whether or not this filter matches one of the
/// specified CFC values.
///
override public bool IsCfc
{
get
{
try
{ //
// If we're not unfiltered and we're not ad hoc, then we
// must be CFC-compliant.
//
return Type != ChannelFilter.Unfiltered
&& Type != ChannelFilter.AdHoc;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem determining whether or not filter corresponds to a CFC value", ex);
}
}
}
///
/// Convert the specified frequency into a ChannelFilter type.
///
///
///
/// The frequency to be converted.
///
///
///
/// The best matching type. A CFC match is preferred;
/// if one does not exist, "ad hoc" will be selected (if frequency > 0).
///
///
private ChannelFilter ConvertFrequencyToChannelFilter(double frequency)
{
try
{
var matchingFilterType = ChannelFilter.Unfiltered;
if (frequency > 0)
{
matchingFilterType = ChannelFilter.AdHoc;
var cfcCoder = new CfcValueAttributeCoder();
foreach (int filterValue in Enum.GetValues(typeof(ChannelFilter)))
if (frequency == filterValue)
matchingFilterType = (ChannelFilter)filterValue;
}
return matchingFilterType;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem trying to match frequency to CRC value", ex);
}
}
///
/// Get the "best fitting" value for this filter.
///
override public ChannelFilter Type
{
get
{
try
{
var actualType = OriginalType;
switch (OriginalType)
{
case ChannelFilter.AdHoc:
actualType = ConvertFrequencyToChannelFilter(CutoffFrequencyHz);
break;
default:
//
// Don't waste time on stuff we don't need to convert.
//
actualType = OriginalType;
break;
}
return actualType;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem determining filter type", ex);
}
}
}
public char IsoDescription => new IsoDescriptionAttributeCoder().DecodeAttributeValue(OriginalType)[0];
///
/// Get the cutoff frequency value.
///
override public double CutoffFrequencyHz => _CutoffFrequencyHz.Value;
private readonly Property _CutoffFrequencyHz
= new Property(
typeof(SaeJ211Filter).Namespace + ".SaeJ211Filter.CutoffFrequencyHz",
-1,
true
);
///
/// The ing done by this object.
///
public ChannelFilter OriginalType
{
get => _OriginalType.Value;
private set => _OriginalType.Value = value;
}
private readonly Property _OriginalType
= new Property(
typeof(SaeJ211Filter).Namespace + ".SaeJ211Filter.OriginalType",
ChannelFilter.Unfiltered,
false
);
private const string CutoffFrequencyUnitString = "Hz";
///
/// The name of this filter.
///
public override string Name
{
get
{
try
{
if (null == _Name)
{
var cult = new System.Globalization.CultureInfo("");
_Name = ChannelFilter.AdHoc == Type
? CutoffFrequencyHz.ToString(cult) + CutoffFrequencyUnitString
: new DescriptionAttributeCoder().DecodeAttributeValue(Type);
}
return _Name;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem generating name string for " + GetType().FullName, ex);
}
}
}
private string _Name = null;
///
/// Apply this filter to the specified channel.
///
///
///
/// The to be filtered.
///
///
///
/// The array of filtered EU data.
///
///
public override double[] Apply
(
Channel channel,
DataDisplayUnits displayUnits,
bool bUseLegacyTDCSoftwareFilterAdjustment
)
{
try
{
var filterUtility = new FilterUtility();
filterUtility.Cfc = Type;
filterUtility.AdHocFrequency = CutoffFrequencyHz;
filterUtility.SampleRate = channel.ParentModule.SampleRateHz;
double[] data;
switch (displayUnits)
{
case DataDisplayUnits.Adc:
if (channel.UnfilteredData is Serialization.SliceRaw.File.PersistentChannel)
{
if (channel.UnfilteredData is ILargeDataAware)
if (!(channel.UnfilteredData as ILargeDataAware).IsDataArraySized)
throw new Serialization.SliceRaw.File.PersistentChannel.DataTooBigForArrayException("Data is too big to be viewed or filtered.");
using (var persistentUnfilteredData =
channel.UnfilteredData as Serialization.SliceRaw.File.PersistentChannel)// ;
{
var dataCount = persistentUnfilteredData.Count;
data = new double[dataCount];
for (var i = 0; i < dataCount; i++)
data[i] = persistentUnfilteredData[(ulong) i];
}
//persistentUnfilteredData.Dispose();
}
else if (channel.UnfilteredData is Serialization.TDAS.File.PersistentChannel)
{
if (channel.UnfilteredData is ILargeDataAware)
if (!(channel.UnfilteredData as ILargeDataAware).IsDataArraySized)
throw new Serialization.TDAS.File.PersistentChannel.DataTooBigForArrayException("Data is too big to be viewed or filtered.");
using (var persistentUnfilteredData =
channel.UnfilteredData as Serialization.TDAS.File.PersistentChannel)// ;
{
var dataCount = persistentUnfilteredData.Count;
data = new double[dataCount];
for (var i = 0; i < dataCount; i++)
data[i] = persistentUnfilteredData[(ulong)i];
}
//persistentUnfilteredData.Dispose();
}
else data = channel.UnfilteredData.ConvertAll(delegate(short datum) { return (double)datum; }).ToArray();
break;
case DataDisplayUnits.Eu:
data = channel.UnfilteredDataEu.ToArray();
break;
case DataDisplayUnits.Mv:
data = channel.UnfilteredDataMv.ToArray();
break;
default:
throw new NotImplementedException("handling for display unit type \"" + displayUnits.ToString() + "\" has not been implemented");
}
return filterUtility.ApplyFilter(data, new FilterUtility.InvalidDataDelegate(delegate()
{
var msg = string.Format("Invalid data in channel: {0}.", channel.ChannelDescriptionString);
//var dr = System.Windows.Forms.MessageBox.Show(msg, "Warning", System.Windows.Forms.MessageBoxButtons.OK);
APILogger.Log(msg);
throw new Exception(msg);
}), bUseLegacyTDCSoftwareFilterAdjustment);
}
catch ( System.Exception ex )
{
throw new Exception( "encountered problem applying filter \"" + Name + "\" to channel", ex );
}
}
///
/// Apply this filter to the specified channel.
///
///
///
/// The to be filtered.
///
///
/// controls whether filtered data is adjusted by one sample to match TDC behavior
/// 8747
///
///
/// The array of filtered EU data.
///
public override double[] Apply
(
double [] data,
double sampleRate,
bool bUseLegacyTDCSoftwareFilterAdjustment
)
{
try
{
var filterUtility = new FilterUtility();
filterUtility.Cfc = Type;
filterUtility.AdHocFrequency = CutoffFrequencyHz;
filterUtility.SampleRate = sampleRate;
return filterUtility.ApplyFilter(data, new FilterUtility.InvalidDataDelegate(delegate()
{
var msg = string.Format("Invalid data in channel.");
//var dr = System.Windows.Forms.MessageBox.Show(msg, "Warning", System.Windows.Forms.MessageBoxButtons.OK);
APILogger.Log(msg);
throw new Exception(msg);
}), bUseLegacyTDCSoftwareFilterAdjustment);
}
catch (System.Exception ex)
{
throw new Exception("encountered problem applying filter \"" + Name + "\" to channel", ex);
}
}
///
/// Generate a string representation of this object.
///
///
///
/// A representation of this object.
///
///
public override string ToString( )
{
try
{
return Name;
}
catch ( System.Exception ex )
{
throw new Exception( "encountered problem generating the string value for " + GetType( ).FullName, ex );
}
}
///
/// Generate a string representation of this object.
///
///
///
/// A representation of this object.
///
///
public override string ToBaseString()
{
try
{
return Name;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem generating the string value for " + GetType().FullName, ex);
}
}
///
/// Determines whether this filter and the specified filter are the same.
///
///
///
/// The filter to be compared with this one.
///
///
///
/// true if the filters are the same, false otherwise.
///
///
public override bool Equals( object obj )
{
try
{
if (null == obj as SaeJ211Filter) { return false; }
return Name.Equals( ( obj as SaeJ211Filter ).Name, StringComparison.OrdinalIgnoreCase );
}
catch ( System.Exception ex )
{
throw new Exception(
"encountered problem equality checking filter \""
+ Name
+ "\" with filter "
+ ( null != obj && obj is SaeJ211Filter && null != ( obj as SaeJ211Filter ).Name ? "\"" + ( obj as SaeJ211Filter ).Name + "\"" : "" ), ex );
}
}
///
/// provides an index for a given
/// since we override Equals we should override get hashcode to ensure that any to objects considered
/// "Equal" are also hashed to the same location, however the result index does not need to be unique
/// between non equal objects.
/// 6/10/2010 - dtm
///
///
public override int GetHashCode()
{
return Name.ToLower().GetHashCode();
}
///
/// Create a filter from the specified string.
///
///
///
/// The representation of the filter to be instantiated.
///
///
///
/// A equivalent of the
/// specified string. Throws an exception if object could not be created.
///
///
static public Filter Parse( string serialization )
{
try
{
Filter filter = null;
if ( !string.IsNullOrEmpty( serialization ) )
{
if ( serialization.Contains( CutoffFrequencyUnitString ) )
{
var cult = new System.Globalization.CultureInfo("");
filter = new DefaultSaeJ211Filter(double.Parse(serialization.Replace(CutoffFrequencyUnitString, ""), cult));
}
else
{
foreach ( ChannelFilter filterType in Enum.GetValues( typeof( ChannelFilter ) ) )
{
var coder = new DescriptionAttributeCoder( );
if ( coder.DecodeAttributeValue( filterType ).Equals( serialization, StringComparison.OrdinalIgnoreCase ) )
filter = new DefaultSaeJ211Filter( filterType );
}
}
}
return ( null != filter ? filter : new SaeJ211Filter( ChannelFilter.Unfiltered ) );
}
catch ( System.Exception ex )
{
throw new Exception( "encountered problem parsing string " + ( null != serialization ? "\"" + serialization + "\"" : "" ) + " into filter", ex );
}
}
}
}
}
}
}