Schnelle Datenübertragung, Datenspeicherung und Datenvisualisierung

Burkhard

Level-2
Beiträge
161
Reaktionspunkte
2
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Freunde der Hochsprachenprogrammierung.

Ich habe mit der DotNetSiemensPLCToolBoxLibrary eine Applikation entwickelt, mit der ich Daten aus der Siemens S7-SPS lesen, die aktuellen Werte anzeigen und in Dateien abspeichern kann.

Ich moechte nun waehrend die Erfassung laeuft, die die Werte in einem DataGridView anzeigen. Ich stelle mir das so vor, dass sich das GridView dann kontinuierlich mit Zeilen fuellt.

In einem Background-Thread werden die Werte von der S7 gelesen und in eine DataTable geschrieben. Alle 30 Millisekunden faellt eine neue Zeile in der DataTable an. Sehr schnell habe ich an die 100.000 Zeilen in der Tabelle.

Im GUI-Thread habe ich ein DataGridView mit Binding-Source an diese DataTable verbunden.

Im Debugger laeuft das ganze irgendwie. Aber wenn ich die Exe ohne Debugger starte, dann friert das Programm manchmal ein. Ich habe ein wenig experimentiert und eine Exe erzeugt die ohne Einfrieren laeuft, aber wenn ich dann weitere Aenderungen am Programm durchfuehre, habe ich wieder Probleme.

Ich bin auf der Suche nach einem grundsaetzlichen Hinweis, wie man bei solchen Problemstellungen vorgeht, denn ich glaube ich habe hier ein grundsaetzliches Architektur-Problem in der Herangehensweise.

Wie werde grosse Datenmengen, die in einem Background-Thread anfallen am besten gespeichert. Ist die DataTable hier das richtige Instrument? Wie Zeige ich diese Daten dann am besten im UI-Thread an?
 
Hallo Burkhard,

was spricht den Deine Konsole (Vermutlich Visual Studio?) beim Ausführen des Programms im Debugging Modus? (Irgendwelche Exceptions?) Ist der "Invoke" zwischen den Threads sauber gelöst?

Bevor Du das Programm als Stand-Alone Exe betreibst erstelle es mal als "Release"! - Führst Du das Programm auf der gleichen Maschine aus wie beim Debuggen? Sind alle Verweise als Lokale Kopie gesetzt?

Für einfaches Abspeichern gibt es evtl. schönere Lösungen als ein DataSet. Grundsätzlich sollte es aber funktionieren.

Gruß aus der Pfalz
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,
ich würde das gar nicht über einen DataTable und Binding lösen - wobei ich gestehen muss, dass ich einen DGV in diesem Zusammenhang und in dieser Form noch nie verwendet habe.
Hast du mal versucht, jeden neuen Datensatz als neue Row hinzuzufügen ?
Hast du in deinem Thread am Ende ein Thread.Sleep(0) oder größer damit die Applikation selbst auch noch die Chance hat, ihre Events durchzubekommen ?

Was mich hier allerdings auch noch interessieren würde :
Wie bekommst du zuverlässig alle 30 ms auf diese Weise Daten von der SPS ? Das kann ich mir irgendwie so gar nicht vorstellen. Es könnte von da her also auch genauso sein, dass dir dein Programm deswegen einfriert.

Gruß
Larry
 
Ich glaube auf jeden Fall nicht das es flüssig laufen wird wenn man einer DGV alle 30ms eine Zeile hinzufügt! Vlt. gehts mit WPF einem DataGrid und einer Observable Collection wenn die Ui Virtualisierung aktiv ist! Aber auch nur Vlt! Ich glaubs irgenwie nicht! du kannst doch die daten auch puffern und nur alle z.B. 500ms als block hinzufügen?
 
Hallo,

also das Lesen der Daten alle 30ms funktioniert, das habe ich ja bereits in einem anderen Thread gezeigt, lieber LarryLaffer. Auch das Schreiben der Daten in die Datei funktioniert verzögerungsfrei, mit Schwankungen zwischen 20 und 35 ms.

Ich habe mich entschieden die 4 Threads die die Daten aus der SPS lesen nicht zu syncronisieren. Sonst wuerde ja der langsamste Thread immer den Takt vorgeben. Die Schreiben ganz unabhaengig von einernder ihre Daten in eine Erebnis-Tabelle. Das klappt soweit auch ganz gut.

Morgen werde ich nach mal Zeitmessungen machen um zu kontrollieren ob auch das Schreiben der Daten in die DataTable genau so verzögerungsfrei funktioniert wie das Schreiben in die Datei. Ich baue alle 30ms eine Row mit einem Zeitstempel zusammen und füge dann die Row der Datetable hinzu. Nach 10 Minuten Aufzeichnungszeit kontrolliere ich den Jitter der Zeitstempel.

Beim Datenbinden an das DataGridview gibt es immer mal wieder Schwankungen um die 200ms. Ich habe nachgedacht und finde sowieso, dass diese riesige Datenmenge in einem DGV sowieso niemand anschauen kann und will.

Wichtiger ist die grafische Darstellung der Daten in Charts, denn ein Bild sagt mehr als tausend Worte, bzw. Zahlen. Darum ist der nächste Schritt die Bindung der Datatable an ein Chart.

Hat einer von euch Erfahrungen mit Echtzeit-Charts, wenn Daten alle 30ms anfallen? Ich habe früher mit dem Scope-View-Analyzer von Beckhoff gearbeitet und die arbeiten da auch mit Puffern, das sieht man daran wie sich die Diagramme aufbauen. Auch mit dem Autem PLC-Analyzer habe ich gerarbeitet und da sieht man, dass die grafische Darstellung auf das allernötigste reduziert wurde um genug Performance für die Erfassung und Speicherung der Daten zu haben.

Gibt es da vielleicht eine OpenSource Library für die Echtzeitdarstellung von Messwerten?
 

Anhänge

  • working version.zip
    3,1 MB · Aufrufe: 42
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Hast du in deinem Thread am Ende ein Thread.Sleep(0) oder größer damit die Applikation selbst auch noch die Chance hat, ihre Events durchzubekommen ?

Ja, ich habe einen Thread.Sleep(20) in meinem Haupt-SPS-Thread drin. Der UI-Thread ruft pro SPS den SPS-Thread auf, dieser wiederum ruft pro Connection einen Connection-Thread auf.

Wie bekommst du zuverlässig alle 30 ms auf diese Weise Daten von der SPS ? Das kann ich mir irgendwie so gar nicht vorstellen.

Doch frag ma den Jochen, mit der Toolboxlibrary geht das. Die Zykluszeit der Erfassung schwankt zwischen 20ms und 35 ms. Dabei nutzt man soviele Connections zur S7 wie eben frei sind und liest über jede Connection pro Lesezyklus eine PDU.
 
Hallo Burkhard,

was spricht den Deine Konsole (Vermutlich Visual Studio?) beim Ausführen des Programms im Debugging Modus? (Irgendwelche Exceptions?) Ist der "Invoke" zwischen den Threads sauber gelöst?

IM Debugging-Mode gibt es keine Exzeptions. Die Delegates für die Cross-Thread Operations beim Zugriff auf Controls des UI-Threads sind auch alle OK. Für eine Cross-Thread-Operation beim Schreiben in ein Data-Set brauche ich kein Delegate/Invoke, da reicht ein SycLock m.E. aus.

Bevor Du das Programm als Stand-Alone Exe betreibst erstelle es mal als "Release"! - Führst Du das Programm auf der gleichen Maschine aus wie beim Debuggen? Sind alle Verweise als Lokale Kopie gesetzt?

Ja, als Release habe ich es jetzt auch kompiliert und ich teste es auf der gleichen Maschine. Alle Referenzen sind ins Release Verzeichnis kopiert. Es ist wirklich bei der Multi-Thread-Programmierung so, dass es da Merkwürdigkeiten gibt, die auch der Debugger nicht erkennt.

Wenn einer von euch mal Zeit hat, kann er sich ja mein Projekt mal runterladen und anschauen. Probiert mal bitte die Sub "ShowDataGridView2(...)" aus der in frmMain untersten Sub "ToolStripButtonUpdate_Clicked" in die darueberliegende Sub "EventOperation2FinishedRaised" zu kopieren, so dass sie direkt unter "ShowDataGridview1(...)" steht.

Dann wieder einen Build machen. Im Debugger läuft es, aber die Standalone-Exe friert ein, sobald der Datenaustausch mit der S7 startet und das Event kommt. Ich kapier nicht wieso es laueft wenn ich das Event manuell über den Button zeitversetzt steuere.
 
Zuletzt bearbeitet:
Ja, als Release habe ich es jetzt auch kompiliert und ich teste es auf der gleichen Maschine. Alle Referenzen sind ins Release Verzeichnis kopiert. Es ist wirklich bei der Multi-Thread-Programmierung so, dass es da Merkwürdigkeiten gibt, die auch der Debugger nicht erkennt.

Ja absolut - deine Applikation hat im Debug-Modus/und auch innerhalb/ausserhalb der IDE ein anderes Zeitverhalten
damit bekommst du z.B. mehr/weniger Events durch oder Fehler in deiner Synchronisation werden damit verborgen/kasschiert

so eine Frage, deine Einfrierproblem und dein Datenweg über einen DataTable+Bindings lassen mich irgendwie an der Stabilität deiner 30ms-Aussagen zweifeln :)
hab schon genug Mit-Threads-ist-es-schneller-Beispiele gesehen die schneller aber instabiler liefen - nach Korrektur der Synchronisation waren diese wieder auf erwartetem Niveau unterwegs

Ein Benchmark der nicht stundenlang mit hoher Wiederholrate, gemittelt und ohne IO wie Console,GUI,Dateiausgabe ausserhalb der IDE gefahren wurden ist bedeutungslos - weil es einfach zu viel Rauschanteil in der Messung gibt

ein nackter C/C++ Test mit AGLink(in meinen Messungen bisher immer am schnellsten) + eine Liste deiner Variablen/und wie du sie auf n Verbindungen splittest (nicht der Algorithmus sonder nur welche Variablen in welcher Reihenfolge auf welche Verbindung) würde da eine gute Testgrundlage bieten
 
Da muss ich ja WPF lernen. Damit habe ich noch nie gearbeitet. Ich habe heute einfach mal das Chart-Control von Microsoft ausprobiert. Was fuer Vorteile hat den das Chart-Control aus deinem WPF-Toolkit gegenueber den Standard-Chart von MS?
 
Ganz grundsätzlich finde ich den Vorschlag von Jochen (Beitrag #4) ganz gut.
Warum nicht die eingehenden Werte in einer List (z.B.) speichern und diese quasi als FiFo benutzen um deren Inhalte dann wieder in deinen DGV oder auch in den Chart (asynchron oder wie Zeit ist) zu übertragen.
Der Chart hat übrigens vom Grundverhalten m.E. das gleiche Problem - er ist ein grafisches Control das sich in dem wie auch immer gewünschten Intervall neuzeichnen (Invalidate) muss.
Du solltest berücksichtigen, dass auch dass so seine Zeit braucht.

Ich habe gelesen, dass deine Anwendung funktioniert. Ich habe aber auch gelesen, dass deine Anwendung immer mal wieder einfriert. Beachte bitte, dass das Überfrachten mit Events (auch Invalidate oder Refresh ist so etwas) genau dazu führen kann. Außerdem gibt es da (ich weiß zu wenig über dein Projekt) auch noch den geliebten GC (Garbage Collector) ...

Gruß
Larry
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Leider ist vb.net keine Deterministische und Zyklus-Orientierte Programmiersprache, wo das Speicherabbild am Anfang eines Zyklus gelesen und am Ende eines Zyklus geschrieben wird und jeder Zyklus garantiert nur die eingestellte Zeit von z.B. 1 bis 10 ms benoetigt, so wie zB. TwinCat.

Waere LabView vielleicht die bessere Wahl zum Lesen, Verarbeiten, Anzeigen und Speichern sehr grosser Datenmengen?
 
Zuletzt bearbeitet:
Tja ...
nach meiner Meinung macht es LabView (in der Frequenz) auch mit dem gleichen Trick. Du hast da ja eine Mess-Hardware dran (z.B. NI) und die überträgt ihre Messwerte dann auch blockweise (z.B. über Ethernet) an den PC mit der Software.

TwinCat kann dir auch nicht sicher garantieren, dass deine Task-Zykluszeit immer unter dem einstellten Wert bleibt. Das hängt immer von deinem in dem Task laufenden Programm ab. Wenn du es mit der Zykluszeit allerdings übertreibst dann hättest du da (aber genauso auch bei Siemens) einen Watchdog, der dir das "unter die Nase reibt".

So, wie ich das sehe, ist die Frage bei dir nicht die Realisierbarkeit ("ob") der Aufgabe sondern mehr das "wie". Ich würde an der Stelle mal ein bißchen "feilen" ...

Gruß
Larry
 
TwinCat lauft in echter harter RealTime, das heisst, es ist egal was das Betriebssystem macht, der Prozessor arbeitet den TwinCat Task immer mit der gleichen Zykluszeit (mit minimalem Jitter) ab und du hast einen Realtime-Slider mit dem du den Performance Anteil des Prozessors zwischen TwinCat und Windows kontrollieren kannst und auch einen Balken siehst wie die momentane Echtzeitauslastung ist, und natuerlich wie du bereits erwaehnt hast, gewarnt wirst, falls die Performance nicht reicht.

TwinCat kann in der NC eine ziemlich grosse Anzahl von Servo-Achsen (10) gleichzeitig berechnen und hat fuer die PLC eine Zykluszeit bis minimal 1 ms. Bei einem ausreichend schnellen PC, kann dann auch ein ziemlich umgangreiches PLC Projekt mit dieser Zykluszeit abgearbeitet werden und wenn der User am Windows rumfummelt hat das keine Auswirkungen auf die Zykluszeit. Das ist ja das gute an der SoftSPS mit RTOS oder RTX.

Aber sei es drum, bei PC Applikationen unter Normal-Windows hat man diese Vorteile eben nicht. Ich habe mal ein paar Versuche mit meinem Programm unternommen und tatsaechlich festgestellt, dass das Updaten des Charts in meinem SPS-Thread Zykluszeitschwankungen verursacht, die umso groesser werden, je groesser die Datenmenge ist, die an den Chart gebunden wird. Die Basis-Datenerfassungsrate liegt bei mir um die 30ms. Immer wenn ich den Update-Button betaetige, dann gibt es einen Nadel-Peak der am Anfang um die 200ms und gegen Ende meiner Erfassung um die 1000ms liegt.

Mein Plan ist nun, die Update-Funktion so zu programmieren, dass das Chart nicht immer wieder geloescht und von Null aufgebaut wird, sondern dass immer nur neue Punkte hinzugefuegt werden. Wenn das Updaten dann jede Sekunde einmal erfolgt, dann sollte es eine Verbesserung geben, die auch deutlich sichtbar sein sollte.
 

Anhänge

  • screen1.JPG
    screen1.JPG
    211,2 KB · Aufrufe: 22
  • screen2.JPG
    screen2.JPG
    248,2 KB · Aufrufe: 19
  • screen3.JPG
    screen3.JPG
    230,4 KB · Aufrufe: 22
  • thread architecture.jpg
    thread architecture.jpg
    81,5 KB · Aufrufe: 21
  • working version.zip
    3,3 MB · Aufrufe: 6
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Mein Plan ist nun, die Update-Funktion so zu programmieren, dass das Chart nicht immer wieder geloescht und von Null aufgebaut wird, sondern dass immer nur neue Punkte hinzugefuegt werden. Wenn das Updaten dann jede Sekunde einmal erfolgt, dann sollte es eine Verbesserung geben, die auch deutlich sichtbar sein sollte.

Das wäre dann im Prinzip die vorgeschlagene FIFO-Geschichte (die so in dieser Form m.E. auch mit einem DGV funktionieren würde).

Es könnte natürlich auch noch gehen, wenn du einen OnTheFly-Chart brauchst (also ein Chart der z.B.) jeweils nur die letzten 1000 Messwerte darstellt), dass du dir einen eigenen Chart selbst erstellst. Das Graphics-Object stellt ja das dafür Benötigte im Großen und Ganzen zur Verfügung. Was man nur schauen (also ausprobieren) müßte wäre welche Datenablage hier die besten Ergebnisse bringt (Array, List/Collection).

Gruß
Larry

Nachsatz:
Auf jeden Fall : deine Untersuchungen hierzu sind wirklich gut und sehr aufschlußreich ... :) :s12:
 
Zuletzt bearbeitet:
Die Update-funktion fuer das Chart-Control ist nun differentiell, das heisst, es werden immer nur die Punkte hinzugefuegt die seit dem letzten Update hinzugekommen sind.

Dadurch hat sich das Zeitverhalten wesentlich verbessert. Bei druecken des Update-Buttons gibt es nur noch Zykluszeit-Aenderungen von 250ms statt 1000ms. Das bedeutet eine Verbesserung um 400 Prozent!

Grundsaetzlich muss man leider sagen, dass sich die Programmiersprache vb.net nicht fuer harte Echtzeitanwendungen eignet. Echtzeit bedeutet in dem Fall nicht "besonders schnell" sondern "deterministisch", das heisst, man kann Erwarten dass ein Thread innerhalb garantierter Intervalle aufgerufen wird und sein Abarbeitungs-Intervall nicht in Abhaengigkeit von der Auslastung anderer Threads in Mitleidenschaft gezogen wird, wie das bei mir eben der Fall ist.

Fuer die Anforderung "Harte Echtzeit" gibt es Echtzeitbetriebssysteme (RTOS) und fuer Windows gibt es IntervalZero RTX, oder Kithara, welche aber nur fuer Visual Studio C++ (Kithara, RTX) oder Delphi (Kithara) zur Verfuegung stehen und zudem kostenpflichtig sind.

http://www.intervalzero.com/german/

http://www.kithara.de/en/products/realtime-suite

Dieser Artikel befasst sich ebenso mit dem Thema "Realtime" und Visual Studio:

http://www.folding-hyperspace.com/real-time-programming-tips/tip-11-is-net-suitable-for.html

Hat jemand von euch Erfahrungen mit diesen Software-Paketen und kann sagen, wie die Anwendungsfreundlichkeit ist?
 

Anhänge

  • screen5.JPG
    screen5.JPG
    214,3 KB · Aufrufe: 15
Zuletzt bearbeitet:
Wenn ich die Update-Funktion nicht sporadisch mit dem Button, sondern aller 500ms aktiviere, und dann aller 2000ms ein Axis-Re-Calculation+Redraw des Charts mache sieht die Sache so aus...

Wenn ich dann die Priority des Process auf RealTime stelle bekomme ich nochmal eine Verbesserung, wie man am Vergleich beider Aufzeichnungen sehen kann.

Code:
[SIZE=1]Dim myProcess As System.Diagnostics.Process = System.Diagnostics.Process.GetCurrentProcess()
myProcess.PriorityClass = System.Diagnostics.ProcessPriorityClass.RealTime
[/SIZE]

Es ist offenbar so, dass die differentielle Uebertragung der Punkte in die Curve-List des Charts zwar einiges an Geschwindigkeits-Vorteil bringt, aber das Redraw des Charts muss ja dennoch die gesamte Kurve zeichnen und die wird ja immer groesser! Man sieht in der zweiten Messung, dass, wenn ich das Fenster minimiere, nur die Punkteliste aktualisiert wird, aber kein Redraw stattfindet und dann die Zykluszeit wieder korrekt bei 30s liegt, bis ich das Fenster wird maximiere.


Wie bereits gesagt koennte ein FILA (First-in-Last-Out) Buffer, der immer nur z.B. 10.000 Punke darstellt schon was bringen. Ich koennte den Chart so konfigurieren, dass die Zeit-Achse mit jedem Update entsprechend skaliert wird, so dass man immer nur 5 Minuten sieht, und man nach dem Ende der Messung, quasi Offline, mit Zoom-to-Default, wieder alle Messwerte sehen kann.
 

Anhänge

  • Capture2.JPG
    Capture2.JPG
    59,6 KB · Aufrufe: 15
  • Capture3.JPG
    Capture3.JPG
    65,4 KB · Aufrufe: 11
Zuviel Werbung?
-> Hier kostenlos registrieren
Grundsaetzlich muss man leider sagen, dass sich die Programmiersprache vb.net nicht fuer harte Echtzeitanwendungen eignet. Echtzeit bedeutet in dem Fall nicht "besonders schnell" sondern "deterministisch", das heisst, man kann Erwarten dass ein Thread innerhalb garantierter Intervalle aufgerufen wird und sein Abarbeitungs-Intervall nicht in Abhaengigkeit von der Auslastung anderer Threads in Mitleidenschaft gezogen wird, wie das bei mir eben der Fall ist.

du schreibst es so als wäre das eine neue Erkenntnis - die ganzen .Net-Sprachen sind nicht Hart-Echtzeit- und kaum Soft-Echtzeitfähig (zu wenig statisch, viel zu viel dynamic/Heap fuer jeden Pups, häufig laufender asychroner GC)
genau so wie z.B. WPF wegen seinem Design sehr dynamisch/adaptiv ist - aber dafür auch Ressourcen frisst als gäbe es kein Morgen
 
Ich konnte durch die Abschaltung des Rechen- und Grafik-Intensiven Progress-Bar, der waehrend der Aufzeichnungen aus dem Background-Thread aktualisiert wurde, die Performance meiner Applikation enorm steigern. Ich habe 16 Minuten Werte aus der SPS gelesen und diese mit sehr zuverlaessiger Zykluszeit von 30ms im Chart darstellen koennen. Am Ende waren es 50.000 Messwerte.

Zur Echtzeitfaehigkeit von vb.net. Die mangelnde Hard-Readltime-Faehigkeit ist mir bisher nur aus Artikeln und Buechern bekannt. Ich habe bisher immer die Soft-Realtime-Faehigkeiten genutzt und wollte dies nun alles mal in ein paar Experimenten fuer mich selber bestaetigen.

Mit TwinCat 2 habe ich selber auch schon sehr viel Erfahrung gesammelt und kenne daher die Faehigkeiten die ein echtes Hard-Realtime-System bieten kann.

Hat einer von Erfahrung mit C++ und RTX?
 

Anhänge

  • Capture4.JPG
    Capture4.JPG
    216,7 KB · Aufrufe: 14
Die mangelnde Hard-Readltime-Faehigkeit ist mir bisher nur aus Artikeln und Buechern bekannt.

.Net UND dein darunter liegendes Windows sind hier das Problem

Ich habe bisher immer die Soft-Realtime-Faehigkeiten genutzt

so wie du das schreibst klingt es so als wäre Hard oder Soft-Realtime so einen Art Option zum einschalten
nur so als Frage: Dir ist klar das Harte Echtzeit nur ein Zeitverhalten garantiert nicht das es besonders schnell ist
- deswegen bin ich mir nicht ganz sicher warum du hier überhaupt Hart/Soft-Echtzeit ansprichst, deine (GUI)Komponenten/Implementierungen
sind doch einfach nur zu langsam eine höhere Datenrate zu stemmen - oder? Was hat das mit Hart/Soft-Echtzeit zu tun?

Hat einer von Erfahrung mit C++ und RTX?

ich arbeite bei sowas mit C/C++ - damit kann man einfach viel gezielter (weil man gezwungen ist) die Heap-Bewegung usw. kontrollieren - wenn es denn wichtig ist
einen Geschwindigkeitsvergleichen zwischen .Net und C++ resultierendem Code ist zu Anwendungsspezifisch deswegen kann man dazu kaum oder nur schlechtes sagen

die RTX ist eine Soft-SPS und "könnte" dir kürzere Abtastraten als 30ms bringen - oder meinst du RTX mit C++ programmieren?

fuer den Test der GUI-Performanz kannst du ja auch mal Testweise ein anderes Toolkit benutzten das auf Ausgabegeschwidigkeit getrimmt ist
z.B. https://visualstudiogallery.msdn.microsoft.com/d09aa844-247a-4aa6-b591-cca32f1b8b3f (http://arction.com/) als Trial mit mit GPU/Direct2D Backend - oder andere dieser Art
 
Zuletzt bearbeitet:
Zurück
Oben