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