c# Gesucht: Implementierung des Swinging Door Algorithmus

Hallo zusammen,

zur Anzeige grosser Datenmengen in einem Chart moechte ich vorher etwas komprimieren (moeglichst verlustarm).
Der im Titel genannte Algorithmus ist fuer diesen Zweck ideal.
Leider finde ich im Netz keine geeignete Implementierung fuer C# oder Java..etc.

Hat jemand einen Tipp fuer mich?

Prinzipiell geht es darum: OSIsoft: Exception and Compression Full Details - YouTube
 
Zwischenbericht

Da ich scheinbar aktuell der Einzige bin, der sich mit diesem Problem konfrontiert sieht, lasse ich mal die Tastatur warmlaufen.
Sieht auf den zweiten Blick auch nicht besonders komplex aus, aber ich hätte mir gerne die Zeit gespart. Werde versuchen die Sache möglichst generisch anzugehen und wenn ich fertig bin, dann werde ich das Ergebnis hier posten.
 
C# - SwingingDoorAlgorithmus (vereinfacht)

Moin,

ich habe eine vereinfachte Version für das preprocessing erstellt. Primär wird der Algorithmus auf dem PI-Server eingesetzt, um DB-Platz einzusparen. Er eignet sich aber auch, um z.B. die Aktualisierung in einem Chart-Control zu beschleunigen, da bis zu 70% Datapoints (je nach Datenart) eingespart werden können. Ideal sind gleichmäßige Datenpunkte ohne Änderung über die Zeit oder Daten mit gleichmäßiger Tendenz. Ich nutze den Algorithmus zur Reduzierung meiner Wetterdaten vor der Ausgabe in einem WPF-Chart.

Hier ein Beispiel:

Compression.png


C# Quellcode:

Code:
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);
        }
    }
}

Beispielaufruf:

Code:
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);
 
Zurück
Oben