Feedback

C# - SwingingDoorAlgorithmus (vereinfacht)

Veröffentlicht von am 03.07.2016
(0 Bewertungen)
Problem: Beim WPF-Chart-Control dauert die Aktualisierung bei > 1000 Datenpunkten sehr lange.
Lösung: Reduzierung redundanter Datenpunkte im Pre-Processing durch Anwendung des SwingingDoorAlgorithmus.

Dieser Algorithmus ist verlustbehaftet und eignet sich daher nur bedingt zur Datenreduzierung in einer Datenbank (PI-Server). Bei der optischen Darstellung der Daten in einem Chart fallen die fehlenden Datenpunkte nicht auf, da alle notwendigen Stützpunkte, je nach Toleranz-Einstellung, erhalten bleiben.

Beispielaufruf:


SDA.SwingingDoorAlgorithmus.ExMax = new TimeSpan(24, 0, 0);
SDA.SwingingDoorAlgorithmus.ExDev = .2f;

SDA.SwingingDoorAlgorithmus.CompMax = new TimeSpan(24, 0, 0);
SDA.SwingingDoorAlgorithmus.sMax = 0.2f;
SDA.SwingingDoorAlgorithmus.sMin = 0.2f;

SDA.SwingingDoorAlgorithmus.data_reduction(ref valTemperatur);
SDA.SwingingDoorAlgorithmus.data_reduction(ref valLuft);
SDA.SwingingDoorAlgorithmus.data_reduction(ref valWind);
SDA.SwingingDoorAlgorithmus.data_reduction(ref valRegen);
namespace SDA
{
    /// <summary>
    /// Reducing redundant data points
    /// </summary>
    public class SwingingDoorAlgorithmus
    {
        /// <summary>
        /// Exception Max - max time of empty values between 2 reprorted values
        /// </summary>
        public static TimeSpan ExMax = new TimeSpan(24,0,0);
        /// <summary>
        /// Slope Max - max time of empty values between 2 reprorted values
        /// </summary>
        public static TimeSpan CompMax = new TimeSpan(24, 0, 0);
        /// <summary>
        /// Exception Dev - max deviation from the snapshot-value
        /// </summary>
        public static float ExDev = 1.0f;
        /// <summary>
        /// Slope - min deviation from the snapshot-value
        /// </summary>
        public static float sMin = 1.0f;
        /// <summary>
        /// Slope - max deviation from the snapshot-value
        /// </summary>
        public static float sMax = 1.0f;
        /// <summary>
        /// Compression activated (true/false)
        /// </summary>
        public static bool compression = true;

        /// <summary>
        /// Main-Methode call
        /// </summary>
        /// <param name="RawValues">ref List[KeyValuePair[DateTime, float]]</param>
        public static void data_reduction(ref List<KeyValuePair<DateTime, float>> RawValues)
        {
            if (RawValues.Count < 3) { return; }

            Exception(ref RawValues);

            if (compression)
            {
                Compression(ref RawValues);
            }
        }
        /// <summary>
        /// Reducing redundant, horizontal data points
        /// </summary>
        /// <param name="RawValues">Liste[KeyValuePair[DateTime, float]]</param>
        private static void Exception(ref List<KeyValuePair<DateTime, float>> RawValues)
        {
            //Last Saved Record
            KeyValuePair<DateTime, float> SnapShot = RawValues[0];
            //The previous record
            KeyValuePair<DateTime, float> PrevValue = RawValues[0];

            //All records except the first and until the penultimate process..
            for (int i = 1; i < RawValues.Count-2; i++)
            {
                if (RawValues[i].Key - SnapShot.Key > ExMax)
                {
                    //Time threshold has been exceeded - save DS

                    //Predecessor is now
                    PrevValue = RawValues[i];
                    //The current DS is the new Snapshot
                    SnapShot = RawValues[i];
                }
                else if (Math.Abs(RawValues[i].Value - SnapShot.Value) > ExDev)//The current record triggers Exception!
                {
                    //The current DS is the new Snapshot
                    SnapShot = RawValues[i];

                    //if the last spoked DS is not the predecessor
                    if (RawValues[i - 1].Key != PrevValue.Key)
                    {
                        //Add predecessors again
                        RawValues.Insert(i - 1, PrevValue);
                        //Index 1 position forward
                        i++;
                    }

                    //Predecessor is now current DS
                    PrevValue = RawValues[i];
                }
                else //Can be omitted..
                {
                    //Predecessor is now the current DS
                    PrevValue = RawValues[i];
                    //remove DS - Index 1 position back
                    RawValues.RemoveAt(i--);
                }
            }
        }
        /// <summary>
        /// Reducing the data points with the same tendency
        /// </summary>
        /// <param name="RawValues">Liste[KeyValuePair[DateTime, float]]</param>
        private static void Compression(ref List<KeyValuePair<DateTime, float>> RawValues)
        {

            //Last Saved Record
            KeyValuePair<DateTime, float> SnapShot = RawValues[1];
            //The previous record
            KeyValuePair<DateTime, float> PrevValue = RawValues[0];

            double ParentSlope = 0.0f;

            //All records except the first and last process..
            for (int i = 1; i < RawValues.Count-1; i++)
            {

                double slope = Slope((float)SnapShot.Key.ToOADate(), SnapShot.Value, (float)RawValues[i].Key.ToOADate(), RawValues[i].Value);

                if (double.IsNaN(slope) || double.IsInfinity(slope))
                {
                    //Ignore, move next
                }
                else if (RawValues[i].Key - SnapShot.Key > CompMax)
                {
                    //Time threshold has been exceeded - save DS

                    //Predecessor is now.. 
                    PrevValue = RawValues[i];
                    //The current DS is the new Snapshot
                    SnapShot = RawValues[i];

                    ParentSlope = slope;
                }
                else if (slope > (ParentSlope + sMax) || slope < (ParentSlope - sMin))//The current record triggers Exception!
                {
                    //The current DS is the new Snapshot
                    SnapShot = RawValues[i];

                    //If the last spoked DS is not the predecessor
                    if (RawValues[i].Key != PrevValue.Key)
                    {
                        //Add predecessors again
                        RawValues.Insert(i, PrevValue);
                        //Index 1 position forward
                        i++;
                    }

                    //Predecessor is now.. 
                    PrevValue = RawValues[i];

                    ParentSlope = slope;
                }
                else //Can be omitted..
                {
                    Debug.Print("Compressed: PS" + ParentSlope + " AS" + slope);
                    //Predecessor is now..
                    PrevValue = RawValues[i];
                    ParentSlope = slope;
                    //remove DS - Index 1 position back
                    RawValues.RemoveAt(i--);
                }
            }
        }
        /// <summary>
        /// computing trend
        /// </summary>
        /// <param name="x1">previous Timestamp</param>
        /// <param name="y1">previous Value</param>
        /// <param name="x2">Timestamp</param>
        /// <param name="y2">Value</param>
        /// <returns></returns>
        private static double Slope(double x1, double y1, double x2, double y2)
        {
            return (y2- y1) / (x2 - x1);
        }
    }
}

Kommentare zum Snippet

 

Logge dich ein, um hier zu kommentieren!