Hallo,
ich bastel seit einiger Zeit an einem Programm zur Erfassung und Visualisierung/Auswertung von Schwingungsmessdaten.
Ich habe das Gefühl, je weiter ich komme, desto grundsätzlichere Probleme ergeben sich...
Ich habe aufgrund von Problemen bei der Verarbeitung jetzt also mal das Grundkonzept geändert bzw. versucht es zu ändern...
Ich habe dazu mal alles relevante mittels LabVIEW nachgebaut, um es einfach und verständlich hier zu zeigen.
Wie man im Screenshot sieht, werden die Messdaten nicht kontinuierlich aufgenommen sondern immer in einem Puffer von x Samples. Dieses x ist vom User frei wählbar. Ich gehe ab jetzt einfach mal von 400 aus. Nach dem "DAQmx - Lesen" sollen die Signalverlaufsdaten "aneinander gereiht" werden, so dass für die Verarbeitung keine separierten 400-Sample-Stückchen anfallen. Das führt nämlich zu Problemen in der Verabeitung (zB Integrieren: Knicke alle 400 Sample und damit Verzerrung der Ergebnisdaten).
Damit der Graf trotzdem nicht immer länger wird und man überhaupt nichts mehr sieht, werden nur jeweils die letzten 400 (oder eben x vom User eingestellten) Samples im Graf gezeichnet.
Das Problem hier ist zum einen natürlich der Speicher, der bei einer langen Messung extrem groß sein müsste. Also müsste man sozusagen 'nacheilend' das Array, in dem alles aneinander gerieht wird, auch wieder löschen...? Hier habe ich keine Idee für die Umsetzung dieses Gedankens.
Problematisch ist aber auch wie man überhaupt wieder sauber einen Signalverlauf erzeugt. In die Komponenten zerlegen, diese aneinandereihen und es dann weider zu einem Signalverlauf zusammenbasteln funktioniert nicht, weil aus dem Zeitstempel dann ein Array wird, was LabVIEW nicht akzeptiert. (Hier frage ich mich eh: Wieso gibt es nur EINEN Zeitstempel alle 400 (bzw x) Samples? Sollte es nicht zu jedem Sample einen Zeitstempel geben?)
Danke schonmal für jeden Hinweis...
Wenn du einen Zeitstempel hast, kennst du alle anderen...weil du zeitlich äquidistante Samples aufgrund der eingestellten Rate der HW hast!
Ja, das ist schon richtig. Aber wenn es dann doch mal einen Sprung gibt, wodurch auch immer, zieht sich der Fehler überall durch.
Aber gut..., es ist gängig, dass man sich darauf verlässt, ja?
' schrieb:Wie man im Screenshot sieht, werden die Messdaten nicht kontinuierlich aufgenommen sondern immer in einem Puffer von x Samples.
Die Ausdruckweise "nicht kontinuierlich aufgenommen" würde ich hier nicht verwenden. Sie ist im gegebenen Zusammenhang misverständlich.
Die Daten selbst werden natürlich kontinuierlich aufgenommen. Dafür sorgt der DaqMX (resepktive der MAX). Der hat nämlich selber einen Zwischenpuffer, der von deinem Puffer der Größe 400 völlig unabhängig ist. Das bedeutet letztendlich, dass die Daten für sich gesehen nie einen Sprung haben können!
Zitat:Nach dem "DAQmx - Lesen" sollen die Signalverlaufsdaten "aneinander gereiht" werden, so dass für die Verarbeitung keine separierten 400-Sample-Stückchen anfallen.
Genau so mach ich das auch immer. Nicht mit Signalverlauf, sondern nur mit 2DArr. Die Zeitbezug ergibt sich relativ zur ersten Datensatz.
Zitat:Damit der Graf trotzdem nicht immer länger wird und man überhaupt nichts mehr sieht, werden nur jeweils die letzten 400 (oder eben x vom User eingestellten) Samples im Graf gezeichnet.
Würde ich auch so machen - wenn meine Messungen nicht nach maximal 3 Minuten von selbst beendet wären.
Zitat:Das Problem hier ist zum einen natürlich der Speicher, der bei einer langen Messung extrem groß sein müsste.
Sehe ich überhaupt kein problem drinn. Solange eine annehmbare Maximalzeit (bei einem Raster von 1ms) nicht überschritten wird. Das (2D-)Array wird für die maximale Auslastung initialisiert. Ein mitlaufender Zähler zeigt die tatsächliche Anzahl der Elemente an.
Zitat:Also müsste man sozusagen 'nacheilend' das Array, in dem alles aneinander gerieht wird, auch wieder löschen...?
Im Prinzip auch kein Problem (nur eine Arbeit): Einfach einen Ringpuffer verwenden. Die Daten, die vom DaqMX gelesen werden, werden in den Ringpuffer, der ein 2DArr ist, geschrieben. Dieses Array wird mit wenigen (LV-)Befehlen in zwei Teile zerlegt, die hintereinander gesetzt werden. Grenze für die beiden Teile ist die Schreibposition des Ringpuffers.
Zitat:Problematisch ist aber auch wie man überhaupt wieder sauber einen Signalverlauf erzeugt.
Ich verwende keinen Signalverlauf. Nur 2DArr. Der zeitliche Zusammenhang ist durch das Abtastraster im MAX fetsgelegt.
Zitat:Hier frage ich mich eh: Wieso gibt es nur EINEN Zeitstempel alle 400 (bzw x) Samples? Sollte es nicht zu jedem Sample einen Zeitstempel geben?
Der Abstand der Messwerte innerhalb eines 400er-Samples ist konstant(!) und festgelegt(!). Es ist also ausreichend, den Start der 400 Samples zu wissen. Beachte, dass der Zeitstempel Datum und Uhrzeit angibt - was aber für manche Messungen überhaupt nicht relevant ist.
Zitat:Genau so mach ich das auch immer. Nicht mit Signalverlauf, sondern nur mit 2DArr. Die Zeitbezug ergibt sich relativ zur ersten Datensatz.
OK, das mit dem Zeitbezug werde ich dann ebenfalls so lösen. Und du erzeugst also ein 2D-Array (Messwert + Zeit) und gibst den Inhalt dann an den Grafen? Das muss ich mal testen. Nur: Wie kann ich einen vorhandenen Grafen für einen anderen Datentyp nutzen? Der ist jetzt auf Signalverlauf eingestellt und ich finde nichts, wo ich das ändern kann...
Zitat:Zitat:Das Problem hier ist zum einen natürlich der Speicher, der bei einer langen Messung extrem groß sein müsste.
Sehe ich überhaupt kein problem drinn. Solange eine annehmbare Maximalzeit (bei einem Raster von 1ms) nicht überschritten wird. Das (2D-)Array wird für die maximale Auslastung initialisiert. Ein mitlaufender Zähler zeigt die tatsächliche Anzahl der Elemente an.
Naja, ich habe noch nicht erwähnt, dass ich Frequenzen bis 3 MHz messe... Das ändert deine Meinung eventuell
Zum Thema 'Array vorher für maximale Auslastung initialisieren und dann reinschreiben':
So wie in diesem Beispiel?
http://www.LabVIEWforum.de/index.php?s=&am...ost&p=76063
Zitat:Im Prinzip auch kein Problem (nur eine Arbeit): Einfach einen Ringpuffer verwenden. Die Daten, die vom DaqMX gelesen werden, werden in den Ringpuffer, der ein 2DArr ist, geschrieben. Dieses Array wird mit wenigen (LV-)Befehlen in zwei Teile zerlegt, die hintereinander gesetzt werden. Grenze für die beiden Teile ist die Schreibposition des Ringpuffers.
OK, danke für den Tipp. Ich merke mir mal das Stichwort 'Ringpuffer' und werde mich demnächst da reinarbeiten. Da habe ich bisher nichts mit zu tun gehabt.
Vielen Dank für die ausführliche Antwort. Das hat schon sehr geholfen!
' schrieb:Und du erzeugst also ein 2D-Array (Messwert + Zeit) und gibst den Inhalt dann an den Grafen?
Nicht "Messwert+Zeit" sondern lediglich mehrere Kurven. Mehrere Kurven über die Zeit ergeben ein 2DArray. Der Graph ist also kein Signalverlauf sondern ein ganz normaler T-Y-Graph (Zeit-YWert), dessen X-Achse die Zeit ist und bei 0 beginnt.
Zitat:Der ist jetzt auf Signalverlauf eingestellt und ich finde nichts, wo ich das ändern kann...
"Umstellen" geht ganz einfach: Den gewünschten Typ einfach an das Anzeigeelement des Graphen anschließen. Es muss das Anzeigeelement sein, lokale Variablen oder Value-Propertys gehen nicht.
Zitat:Naja, ich habe noch nicht erwähnt, dass ich Frequenzen bis 3 MHz messe... Das ändert deine Meinung eventuell
Och, das käme auf eine Hochrechnung und die Größe des Speichers an. Und außerdem muss man nicht DBL nehmen U16 geht womöglich auch.
Hinweis:
Eines solltest du jedenfalls nicht machen: Daten zur Laufzeit an ein Array anhängen.
Anhängen kosten Zeit und Speicher. Je mehr Daten bereits vorhanden sind, desto mehr Zeit und Speicher wird für das Anhängen benötigt.
Zitat:So wie in diesem Beispiel
Jawohl.
Zitat:Nicht "Messwert+Zeit" sondern lediglich mehrere Kurven. Mehrere Kurven über die Zeit ergeben ein 2DArray. Der Graph ist also kein Signalverlauf sondern ein ganz normaler T-Y-Graph (Zeit-YWert), dessen X-Achse die Zeit ist und bei 0 beginnt.
Ach klar, wieder falsch gedacht. Wir sind ja hier vor dem splitten und ohne Zeitstempel... Sry
Zitat:"Umstellen" geht ganz einfach: Den gewünschten Typ einfach an das Anzeigeelement des Graphen anschließen.
LabVIEW ist manchmal ZU einfach:)Danke...
Zitat:Och, das käme auf eine Hochrechnung und die Größe des Speichers an. Und außerdem muss man nicht DBL nehmen U16 geht womöglich auch.
Stimmt! Naja, mit dem Problem befasse ich mich im nächsten Schritt. Aber mit einem Ringpuffer sollte das Problem ja sowieso erledigt sein. Wenn die Messung aufgezeichnet wird, ist die Messzeit eben begrenzt - das ist akzeptabel.
Zitat:Eines solltest du jedenfalls nicht machen: Daten zur Laufzeit an ein Array anhängen. Anhängen kosten Zeit und Speicher. Je mehr Daten bereits vorhanden sind, desto mehr Zeit und Speicher wird für das Anhängen benötigt.
Hm. Also NICHT den Befehl "Array erstellen" verwenden? Der fügt ja auch Daten an ein vorhandenes Array an... ("Verbindet mehrere Arrays oder fügt Elemente an ein n-dimensionales Array an.")
Oder beziehst du dich jetzt nur auf "Daten zur Laufzeit"? Die Laufzeit muss ich doch nicht extra behandeln, die ergibt sich doch aus der Abtastfrequenz und Sampleanzahl... So ganz weiß ich nicht was du meinst.
' schrieb:Hm. Also NICHT den Befehl "Array erstellen" verwenden? Der fügt ja auch Daten an ein vorhandenes Array an... ("Verbindet mehrere Arrays oder fügt Elemente an ein n-dimensionales Array an.")
Jawohl. Auch das nicht verwenden.
Das Problem ist der Speichermanager - respaktive das, was er machen muss.
Gesetzt der Fall zu hast Daten als Array vorliegen. Dann wird hierfür ein genau definierter Bereich im Speicher verwendet. Wenn du jetzt an diese Daten, also an diesen Speicherbereich, neue Daten, also einen anderen Speicherbereich, anhängen willst - muss der Speichermanager einen neuen Speicherbereich zur Verfügung stellen. Dieser neue Bereich, der so groß sein muss wie die beiden einzelnen zusammen, kann aber ein ganz ein anderer sein als der erste bereits vorhandene Bereich. Das hat aber fatale Auswirkungen! Der Speichermanager muss neuen Speicher allozieren. Und dann muss der komplette erste (und auch der wohl eher sehr kleine zweite) Bereich umkopiert werden. Und Listen anpassen. Und Speicher aufräumen. Und das alles absturzsicher. Da hat der Speichermanager schon was zu tun.
Und jetzt überlege mal, was passiert, wenn dieser Vorgang 20mal pro Sekunde über eine Dauer von 3 Minuten bei einer Größenänderung von ....
Wenn man also Replace verwendet, fällt das alles weg. Kopiert wird nur der kleine neue Bereich. Und das geht auch ohne Speichermanager.
Zitat:"Daten zur Laufzeit"?
Mit "Laufzeit" würde ich jetzt nicht die Daten also solche, sondern das Programm gemeint haben. Und zum Programm gehört das, was der Speichermanager machen muss.
' schrieb:Das Problem ist der Speichermanager - respaktive das, was er machen muss.
Hi IchSelbst,
das mit dem "Concatenate Array" für große Arrays ist mir ja bekannt...das wird langsam!
Ich bin mir jetzt nicht sicher, ob das hier ne Abhilfe wäre...
[
attachment=21538]
Sachmawattdazu!
Gruß
Achim
' schrieb:Sachmawattdazu!
Kann keine Abhilfe sein!
Aus einem ganz einfachen Grund: Wenn Eingang und Ausgang bezogen auf die Operation eine unterscheidliche Größe haben,
muss der Speichermanager immer einspringen. Gleiche Größe besteht eben bei "Replace". Bei "Erzeuge aus Mehreren" und "Anhängen" sind eben Ein- und Ausgang unterschiedlich groß. Das Inplacement-Element soll ein
Replace erzwingen. Das geht aber nur, wenn der Platz dafür bereits vorhanden ist. Das Implacement könnte intelligent aufgebaut sein und bereits zur Entwicklungszeit entsprechende Optimierungen vornehmen. Das hat aber dann seine Grenzen, wenn die Operation kontinuierlich (also in While-Schleife mit Operationsdaten rückgekoppelt in Schieberegistern) stattfindet. Und das ist gerade in inserem Falle wohl immer der Fall.
Bei reinen Clustern kann das Inplacement gut angewendet werden. Normalerweise wird der Cluster entbundelt, bearbeitet, und neu gebundelt. Alleine schon im BD sieht man, dass ein neuer Datenfluß entsteht (Wire!). Dieser Datenfluß verbraucht aber Speicher und Zeit (Speichermanager ...). Das Inplacement erzwingt, dass trotz sichtbarem Wire kein neuer Speicher bereit gestellt werden muss. Es wird mit dem Speicher des Clusters gearbeitet: Trotz logischer Verzeigung eines Wires kein neuer Datenfluß. Das erspart mindestens zwei Kopieroperationen.