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