Wenn dein Problem oder deine Frage geklärt worden ist, markiere den Beitrag als "Lösung",
indem du auf den "Lösung" Button rechts unter dem entsprechenden Beitrag klickst. Vielen Dank!
05.09.2023, 10:38 (Dieser Beitrag wurde zuletzt bearbeitet: 05.09.2023 12:16 von VersuchundErprobung.)
wie der Beitrag schon vermuten lässt, habe ich ein Problem bei dem ich mit meinem Wissen nicht weiterkomme. Ich habe schon ein paar Lösungen im Forum gesehen, jedoch sind die auf meinen Fall meist nicht anwendbar, oder zumindest weiß ich nicht wie.
Um euch abzuholen erzähle ich erstmal etwas über die allgemeine Aufgabestellung: Ich programmiere ein neues Messprogramm für einen Prüfstand, welches mehrere digital und analog Signale visualisieren, umwandeln und abspeichern soll. Die verwendete Hardware ist nicht von NI sondern von einer kleinen Hardware-Schmiede names Geitmann und arbeitet mit einer dll. Passende Treiber dazu gab es vom Hersteller. Das Messprogramm ist als state machine verwirklicht. Da gibt es bestimmt bessere Wege. Soweit funktioniert es aber schon. Grob .
Nun zu meinem Problem:
Ich habe ein sich Blockgrößen-füllendes Array mit 0 und 5, aus welchem ich eine Frequenz lesen muss. Die Struktur sie wie folgt aus:
Ich habe mich mit einem VI schon versucht, führte zu keinem Erfolg.
Alternativ könnte ich die Daten auch noch anders aus dem Messsystem lesen:
Ich nutze gerade die MeasData, habe keine Erfahrung mit CAN.
Ich bin mir sicher, dass es die ein oder andere Frage bezügliche meiner Fragestellung aufkommen könnte. Stellt diese gerne
Vielen Dank für Hilfe!
Anzeige
05.09.2023, 11:05 (Dieser Beitrag wurde zuletzt bearbeitet: 05.09.2023 11:53 von GerdW.)
Zitat:Ich habe ein sich Blockgrößen-füllendes Array mit 0 und 5, aus welchem ich eine Frequenz lesen muss. Die Struktur sie wie folgt aus:
Wenn ich das richtig sehe, dann bekommst du (quasi) eine Waveform aus t0, dt und Y[].
Du nimmst jetzt deine Y[]-Daten und schaust, bei welchem Arrayindex der Wechsel von 0->5/5->0 (FALSE/TRUE) stattfindet. Aus dem Abstand dieser Wechsel kannst du dann mit dt den zeitlichen Abstand bestimmen. Dann nur noch f=1/T…
Jetzt mit Beispiel:
Der Cluster enthält deine "quasi Waveform": ich prüfe auf HIGH/LOW-Pegel per ">2.5", suche dann die rising edges und berechen aus deren Indices und dem dt die Zeit zwischen den beiden ersten Edges und als Reziprok die Frequenz…
Hallo GerdW,
Tatsächlich habe ich an den "händischen" Weg mir die Frequenz zu holen noch nicht gedacht. Danke für den Hinweis! In einem meiner Versuche habe ich aus meiner quasi Waveform eine Waveform gemacht und dann aus dieser versucht die Frequenz zu bekommen, führte aber zu nichts, da ich glaube das falsche VI dazu hatte.
Ich habe deine Lösung versucht nach zu bauen, jedoch ist der Teil mit den "rising edges" finden nicht so wirklich kompakt, wie es bei Dir ist und ich habe versucht das dort verwendete VI zu finden. Ist das ein von Dir erstelltes VI in dem For-Loop oder warum finde ich es nicht?
Ich versuche mich noch weiter und werde es die Tage testen. Melde mich nochmal.
Wenn ich weitere Fragen zu meinem Programm habe, die aber nicht unbedingt in die Datenerfassung reinpassen, wie könnte ich diese Dir am besten stellen? Wenn man durchs Forum schaut, sieht man Deine Expertise sehr oft und ich wäre dankbar für ein paar weitere Antworten, die dem ein oder anderen stillen Mitleser auch weiterhelfen könnte.
Einen schönen Tag allen Anwesenden!
VersuchundErprobung
Zitat:ich habe versucht das dort verwendete VI zu finden. Ist das ein von Dir erstelltes VI in dem For-Loop oder warum finde ich es nicht?
Das ist aus der Pt-by-Pt-Palette: PtByPt-BooleanCrossing.
(Außerdem hatte ich ein Snippet erstellt: runterladen und ins Blockdiagramm per Drag&Drop einfügen. Lies dir die LabVIEW-Hilfe zum Thema Snippet durch…)
Zitat:Wenn ich weitere Fragen zu meinem Programm habe, die aber nicht unbedingt in die Datenerfassung reinpassen, wie könnte ich diese Dir am besten stellen?
Einfach deine Frage stellen. Ich sehe sie dann schon…
(Ich gehe immer über "Beiträge letzte 1 / 2 / … Tage".)
P.S.: Wenn du ein VI anhängst, dann bevorzuge ich LV2019. Es gibt da im Menü File->Save for previous…
(05.09.2023 14:12 )GerdW schrieb: Das ist aus der Pt-by-Pt-Palette: PtByPt-BooleanCrossing.
Der Tipp war goldwert!
Ich habe es geschafft! Hier meine Lösung:
Es stellte sich heraus, dass nach dem von Dir vorgeschlagenen For-Loop das Array nur aus den Positionen der steigenden Flanke bestand, jedoch nicht aus den Abständen zwischen ihnen. Und genau diese brauche ich ja um die Periodendauer zu berechnen. Das habe ich mit einem weiteren Loop nachgeholt. Wahrscheinlich geht das auch übersichtlicher & ressourchensparender, aber so läuft es erstmal.
Beim Schreiben der Kommentare ist mit aufgefallen, dass ich auch noch die letzten Werte im Abstände-Array löschen müsste, da diese ja auch verfälscht sind. Meine Blockgröße beträgt 5000 bei einer Abtastrate von 10000 Hz. Sollte also ausreichend genau sein um eine Drehzahl zu ermitteln. Die Blöcke kommen einzelnd und nicht "stackend" an.
Gibt es eventuell einen schnelleren, einfacheren Weg? Oder sonstige Probleme, die ich nicht sehe?
06.09.2023, 14:29 (Dieser Beitrag wurde zuletzt bearbeitet: 06.09.2023 14:34 von GerdW.)
Zitat:Gibt es eventuell einen schnelleren, einfacheren Weg? Oder sonstige Probleme, die ich nicht sehe?
Statt der zweiten FOR-Loop:
Andere Probleme: Ich bevorzuge (Un)BundleByName, weil man dort
1. gleich das (hoffentlich) benamte Element im Cluster sieht
2. nur die benötigten Elemente unbundelt
3. beim Bundle nicht ALLE Elemente wieder einfügen muss, sondern nur die veränderten…
Wann immer du in einer FOR-Loop in jeder Iteration neue Elemente an ein vorher leeres Array hinzufügst, kannst du auch gleich einen autoindizierenden Output-Tunnel verwenden anstatt ShiftRegister und BuildArray! (Das gilt für deine zweite FOR-Loop als auch die letzte zur Verrechnung der Mittelwerte.)
Tipp: Schalte in den LabVIEW-Optionen das Feature zum standardmäßigen Anzeigen der Strukturkommentare an, dann hast du in jeder Loop/Case/Event automatisch ein Kommentarfeld…
Tipp: Verbinde das Enum ("Digital") direkt mit dem Selektor der Case-Struktur, ein Vergleich vorher ist hier unnötig!
(06.09.2023 14:29 )GerdW schrieb: 3. beim Bundle nicht ALLE Elemente wieder einfügen muss, sondern nur die veränderten…
ich habe kaum mal einen Grund dich zu korrigieren, aber das unterstellt, dass man immer alle Clusterelemente verbinden muss. Das ist nicht so. "Bundle" und "Bundle By Name" verhalten sich hier ziemlich gleich. Bei beiden muss der Eingang "Cluster" mit dem Cluster verbunden werden, damit die Daten erhalten bleiben.
Optisch meistens angenehmer ist "Unbundle By Name" und "Bundle By Name" aber die haben gegenüber "Unbundle" und "Bundle" mitunter einen deutlich messbaren Performancenachteil. Sie sind in immer etwas langsamer und zumindest bei manchen etwas complexeren Daten (Array, Cluster) ist das deutlich messbar. Wenn mein Code wirklich schnell sein soll/muss und es sich um etwas komplexere Datentypen handelt (Array,Cluster), dann nehme ich nach wie vor zur sicherheit "Unbundle". Zugegeben, der Unterschied spielt meistens keine Rolle.
Martin Henz
07.09.2023, 07:47 (Dieser Beitrag wurde zuletzt bearbeitet: 07.09.2023 08:12 von Martin.Henz.)
(06.09.2023 14:21 )VersuchundErprobung schrieb: Gibt es eventuell einen schnelleren, einfacheren Weg? Oder sonstige Probleme, die ich nicht sehe?
Das Problem aus einem wie auch immer geartetem periodischen Signal das kontinuierlich eingelesen wird, die Frequenz, Periodendauer oder Drehzahl zu ermitteln, ist ganz generell nicht trivial. Wenn dann ein nicht immer optimal funktionierender Sensor dazu kommt (z.B. Ausfall einzelner Impulse), wird es noch schwieriger. Das ist ganz sicher keine Aufgabe die für einen Anfänger geeignet ist.
Wenn dein Algorithmus für deinen Anwendungsfall funktioniert und für deine Zwecke ausreichend ist, dann belasse es einfach dabei. Ein wenig lässt es sich verbessern und vereinfachen.
Zum Beispiel
- die For-Schleife durch eine While-Schleife ersetzen und die Übergänge mit der Funktion "Search 1D Array" suchen.
- oder die For-Schleife mit Boolean Crossing durch "Threshold Detector.vi" ersetzen.
- in der ersten Schleife gleich die Differenz berechnen oder die Differenzberechnung ohne Schleife durchführen.
- die erste Periode wirfst du immer weg. Das wäre nicht nötig, wenn du das Shift-Register mit dem ersten Index initialisierst (anstatt der 0)
Die obigen Punkte sind nicht vollständig beschrieben, sondern sind nur grobe Hinweise, Gedanke und Ideen.
Dein Algorithmus funktioniert nur
- wenn mehr als eine Periode in einem Datenblock gemessen wurde. Niedrige Frequenzen kannst du damit nicht ermitteln
- wenn du ein rauschfreies Signal hast (es also digital nur zwischen 0 und 5 wechselt)
- wenn der Schwellwert von 2.5 zum Signal passt
Nachtrag: Vielleicht reicht für deinen Fall auch einfach eine FFT (Extract Single Tone Information.vi). Da steckt zwar einiges an Berechnungen dahinter, aber dann kommst du mit dem Aufruf eines einzigen fertigen VIs aus und musst dir ansonsten keine weiteren Gedanken machen. So ab 3.5Hz dürfte das funktionieren und da kommt auch dein Algorithmus an seine Grenzen.
Martin Henz
07.09.2023, 10:01 (Dieser Beitrag wurde zuletzt bearbeitet: 07.09.2023 10:03 von VersuchundErprobung.)
Viele Dank für die ganzen Anregungen/Ideen!
Das hilft mir wirklich viel!
Tatsächlich habe ich in meiner LabView Schulung (LabView Core1&2) beigebracht bekommen, dass "(Un)Bundle" schneller sein soll als "(Un)BundlebyName". Jedoch habe ich kein Gefühl dafür, ob und wie viel Auswirkungen das hat. Dazu fehlt mir die Erfahrung. Übersichtlicher und leichter zu lesen ist oft die "..byName" Variante.
Der Trick um die Abstände zu bestimmen, indem man das Array um einen Indiz verschiebt und dann die Differenz bildet, ist sehr hilfreich! Auch das mit den unnötigen Shift-Registern. Ich habe es angepasst.
Hier meine angepasste, minimierte und bereits erfolgreich auf Funktion getestete Version:
(07.09.2023 07:47 )Martin.Henz schrieb: - die erste Periode wirfst du immer weg. Das wäre nicht nötig, wenn du das Shift-Register mit dem ersten Index initialisierst (anstatt der 0)
Ist es nicht so, dass es an den "Cuts" zu verfälschten Abständen kommt, da mein Signal in Blöcke unterteilt wird alle 5000 Werte? Wenn die sehr stark verfälscht und/oder die Blockgrößen kleiner sind, haben diese größere Auswirkung auf die Mittelwertbildung. Daher entferne ich sie lieber.
Apropos Mittelwertbildung: die Mittelung über einen Block (5000 Werte, bei 10000Hz Abtastrate) ist natürlich nicht optimal. Zwar reicht mir für die Anzeige eine Frequenz von 2Hz, jedoch bei der Abspeicherung der Messwerte (also Abspeicherung des hier erstelltem Arrays) hätte ich dies ruhig nicht so grob gemittelt.
Das Signal ist weitesgehend rauschfrei und der Schwellenwert von 2,5 wird passend sein. Dieses Programm ist nur für ein Messsystem-Typ (3 Systeme, gleicher Hersteller).
Ich weiß von der Problematik bei Signalen mit geringer Frequenz. In meinem Anwendungsfall (Drehzahlen, Volumenstromzähler) wird es keine Frequenzen unter 30 Hz geben.
(07.09.2023 10:01 )VersuchundErprobung schrieb: Tatsächlich habe ich in meiner LabView Schulung (LabView Core1&2) beigebracht bekommen, dass "(Un)Bundle" schneller sein soll als "(Un)BundlebyName". Jedoch habe ich kein Gefühl dafür, ob und wie viel Auswirkungen das hat.
Nunja ... wenn du dich um Nanosekunden kümmerst :-)
es gibt die Aussage, dass die "By Name" Varianten über den Namen die Elemente finden. Als es eingeführt wurde, war das vermutlich auch so. Vom Prinzip her müsste das jedoch bereits der Compiler auflösen können und das scheint mir schon seit vielen Jahren der Fall zu sein. Es gibt aber dennoch ein paar, von mir nicht näher spezifizierbare Fälle in denen es noch einen messbaren Unterschied gibt. Zusammenfassend: vergiss es ...
Zitat:Ist es nicht so, dass es an den "Cuts" zu verfälschten Abständen kommt, da mein Signal in Blöcke unterteilt wird alle 5000 Werte?
Du detektierst die steigenden Flanken. Das Threshold VI liefert dummerweise als ersten Index eine Null, wenn der erste Messwert größer oder gleich 2.5 ist (ich hoffe ich schreibe jetzt nichts falsches). Einfach einmal genau ansehen. Du wirfst den ersten Index weg, wenn dieser gleich 0 ist.
(BTW: der ursprüngliche Ansatz war in diesem Punkt besser)
Jetzt hast du nur noch (echte) steigende Flanken und das Problem, dass die erste Periode eine falsche Zeit liefern kann, das gibt es nicht mehr.