2010-12-08 10 views
7

Ich vermasse einige Systemleistungsdaten, um sie in einer Datenbank zu speichern. Aus diesen Datenpunkten zeichne ich Liniendiagramme im Zeitverlauf. In ihrer Natur sind diese Datenpunkte etwas laut, d. jeder einzelne Punkt weicht zumindest ein wenig vom lokalen Mittelwert ab. Wenn Sie das Liniendiagramm direkt von einem Punkt zum nächsten zeichnen, entstehen gezackte Graphen. In einem großen Zeitmaßstab wie> 10 Datenpunkten pro Pixel wird dieses Rauschen zu einem breiten gezackten Linienbereich komprimiert, der beispielsweise 20px hoch statt 1px wie in kleineren Maßstäben ist.Wie kann ich geglättete/abgerundete/gekrümmte Liniendiagramme zeichnen? (C#)

Ich habe über Linienglättung, Anti-Aliasing, Vereinfachung und all diese Dinge gelesen. Aber alles, was ich gefunden habe, scheint um etwas anderes zu gehen.

Ich brauche kein Anti-Aliasing, .NET macht das schon für mich, wenn ich die Linie auf dem Bildschirm zeichne.

Ich will keine Vereinfachung. Ich brauche die extremen Werte, zumindest die meisten.

Ich denke, es geht in Richtung Spline-Kurven, aber ich konnte nicht viele Beispielbilder finden, um zu bewerten, ob das beschriebene Ding was ich will. Ich fand jedoch ein hochwissenschaftliches Buch bei Google Books, voll mit halbseitenlangen Formeln, die ich jetzt nicht lesen wollte ...

Um Ihnen ein Beispiel zu geben, schauen Sie sich einfach den Systemmonitor von Linux/Gnome an Anwendung. Ich zeichne die aktuelle CPU/Speicher/Netzwerk-Nutzung mit einer geglätteten Linie. Das mag ein wenig vereinfacht sein, aber ich würde es versuchen und sehen, ob ich es optimieren kann.

Ich würde C# -Code bevorzugen, aber Algorithmen oder Code in anderen Sprachen ist auch in Ordnung, solange ich es ohne externe Referenzen nach C# portieren kann.

+0

Ist Ihnen bekannt, dass Windows (und .net) ein integriertes Leistungsindikatorsystem haben? Ich möchte nur sicherstellen, dass Sie das Rad nicht neu erfinden (nicht sagen, dass es sich notwendigerweise auf Ihren Fall bezieht). –

+0

Meine Daten werden auf einem Linux-Server gesammelt und bestehen aus einer Vielzahl verschiedener Quellen, für die ich anderen Code habe. Die Daten sollen zur Verwendung in einer Desktop- (interaktiven) oder Web-Anwendung oder möglicherweise per E-Mail verschickten Berichten unter der Mono-Laufzeit visualisiert werden. Die Entwicklung erfolgt mit Visual Studio unter Windows. – ygoe

Antwort

6

Sie können Datenglättung durchführen. Verwenden Sie anstelle der realen Daten einen einfachen Glättungsalgorithmus, der die Spitzenwerte wie einen Savitzky-Golayfilter beibehält.

You can get the coefficients here.

Die am einfachsten zu tun ist:

die Top-Koeffizienten von der Website nehmen ich verbunden:

// For np = 5 = 5 data points 
var h = 35.0; 
var coeff = new float[] { 17, 12, -3 }; // coefficients from the site 
var easyCoeff = new float[] {-3, 12, 17, 12, -3}; // Its symmetrical 
var center = 2; // = the center of the easyCoeff array 

// jetzt für jeden Punkt aus Ihren Daten Sie einen geglätteten Punkt berechnen:

smoothed[x] = 
    ((data[x - 2] * easyCoeff[center - 2]) + 
    (data[x - 1] * easyCoeff[center - 1]) + 
    (data[x - 0] * easyCoeff[center - 0]) + 
    (data[x + 1] * easyCoeff[center + 1]) + 
    (data[x + 2] * easyCoeff[center + 2]))/h; 

Die ersten 2 und die letzten 2 Punkte können Sie bei Verwendung von 5 Punkten nicht glätten.

Wenn Sie möchten, dass Ihre Daten "geglättet" werden, können Sie mit Koeffizienten mit größeren Datenpunkten experimentieren.

Jetzt können Sie eine Linie durch Ihre "geglätteten" Daten zeichnen. Je größer Ihre np = Anzahl der Punkte, desto glatter Ihre Daten. Aber Sie verlieren auch die Spitzengenauigkeit, aber nicht so viel, wenn Sie einfach einige Punkte zusammenrechnen.

+1

Ich habe jetzt eine Variante von diesem implementiert. Zuerst mittle ich die rohen Quellendatenpunkte auf ~ 3 Werte pro Pixel. Dies führt zu einer einheitlicheren Datendichte beim Rendern von Datenmonaten mit unterschiedlicher Auflösung von Sekunden bis Minuten. Ich führe dann diese Werte durch die größte Koeffizientenliste, die auf der anderen Seite gefunden werden kann. Es erzeugt tatsächlich mehr geglättete Linien in der Grafik. Aber sehr kleine und extreme Spitzen erzeugen in der Grafik lustige Effekte. Es oszilliert stark in die andere Richtung um die Kurve, wo das Extrem ist. Ich denke, es kommt von den negativen Koeffizienten. – ygoe

1

Ich denke, was Sie suchen, ist eine Routine, um Splines bereitzustellen. Hier ist ein Link Splines beschreiben:

http://en.wikipedia.org/wiki/Spline_(mathematics)

Wenn das der Fall ist, ich habe keine Empfehlungen für eine Spline-Bibliothek, sondern eine erste Google-Suche drehte sich ein auf einen Haufen legen.

Entschuldigung für keinen Code, aber hoffentlich wissen die Terminologie wird Ihnen bei Ihrer Suche helfen.

Bob

0

Reduzieren Sie die Anzahl der Datenpunkte, mit MIN/MAX/AVG, bevor Sie sie anzeigen. Es wird schöner aussehen und es wird schneller sein

2

Sie können das nicht im Grafikcode beheben. Wenn Ihre Daten laut sind, wird auch die Grafik laut, egal, welche Art von Linienglättungsalgorithmus Sie verwenden. Sie müssen die Daten zuerst filtern. Erstellen Sie einen zweiten Datensatz mit Punkten, die aus den ursprünglichen Daten interpoliert werden. Eine Anpassung an die kleinsten Quadrate ist eine übliche Technik. Mittelwertbildung ist einfach zu implementieren, neigt aber dazu, Extreme zu verbergen.

0

Grafiken des Netzwerkverkehrs verwenden oft einen gewichteten Durchschnitt. Sie können einmal pro Sekunde in eine kreisförmige Liste der Länge 10 eintasten und für den Graphen bei jeder Probe den Durchschnitt der Proben grafisch darstellen.

Wenn 10 nicht ausreicht, können Sie viele weitere speichern. Sie brauchen nicht den Durchschnitt von Grund auf neu zu berechnen, entweder:

new_average = (old_average*10 - replaced_sample + new_sample)/10 

Wenn Sie alle 10 nicht speichern möchten, können Sie jedoch mit diesem nähern:

new_average = old_average*9/10 + new_sample/10 

Viele Router Verwenden Sie dies, um Speicherplatz zu sparen. Dies steigt exponentiell in Richtung der aktuellen Verkehrsrate.

Wenn Sie dies tun implementieren, so etwas tun:

new_average = old_average*min(9,number_of_samples)/10 + new_sample/10 
number_of_samples++ 

das anfängliche Ramp-up zu vermeiden. Sie sollten auch das Verhältnis 9/10, 1/10 einstellen, um die Zeitvorperiode jedes Samples tatsächlich zu reflektieren, da Ihr Timer nicht exakt einmal pro Sekunde auslöst.