Die Vorteile der grafischen Programmierung mit NI LabVIEW

Überblick

Seit über 20 Jahren wird NI LabVIEW von Ingenieuren und Wissenschaftlern bei der Erstellung von Mess-, Prüf-, Steuer- und Regelanwendungen eingesetzt. LabVIEW bietet eine große Auswahl an Funktionen und Werkzeugen, von interaktiven Assistenten bis zu konfigurierbaren, benutzerdefinierten Schnittstellen, und hebt sich durch seinen universellen grafischen Programmieransatz mit integriertem Compiler, Linker und Fehlerbehebungswerkzeugen von anderen Programmiersprachen ab.

Kurze Übersicht über die Entwicklung der Higher-Level-Programmierung

Um die Vorteile der grafischen LabVIEW-Programmierung besser bewerten zu können, ist es hilfreich, den Hintergrund der ersten Higher-Level-Programmiersprache näher zu beleuchten. Zu Beginn des modernen Computerzeitalters Mitte der 1950er Jahre entschied sich ein kleines Entwicklerteam bei IBM, eine praktischere Alternative für die Programmierung des gigantischen Großrechners IBM 704 (zu dieser Zeit ein Supercomputer) in einer Low-Level-Assembler-Sprache, der modernsten Programmiersprache der damaligen Zeit, zu entwickeln. Das Ergebnis war FORTRAN, eine für Entwickler besser lesbare Programmiersprache, die den Entwicklungsprozess beschleunigte.

Die Entwicklergemeinschaft war anfangs skeptisch, dass diese neue Methode besser sein würde als per Hand erstellte Assembler-Programme. Es stellte sich jedoch schnell heraus, dass von FORTRAN erzeugte Programme fast genauso effizient abliefen wie in Assembler geschriebene Programme. Gleichzeitig reduzierte FORTRAN die Anzahl der notwendigen Programmierbefehle um den Faktor 20. Daher wird FORTRAN häufig als die erste Higher-Level-Programmiersprache bezeichnet. So überraschte es nicht, dass FORTRAN schnell eine immer größere Akzeptanz unter Wissenschaftlern fand und bis heute eine einflussreiche Programmiersprache ist.

Auch fünfzig Jahre später ist diese Anekdote noch aktuell. Erstens haben in den letzten 50 Jahren Ingenieure immer weiter nach einfacheren und schnelleren Wegen gesucht, Probleme durch Computerprogrammierung zu lösen. Und zweitens tendierten die von Ingenieuren gewählten Programmiersprachen immer mehr in die Richtung einer höheren Abstraktionsebene. So erklärt sich die große Popularität und breite Akzeptanz der Programmiersprache G seit ihrer Einführung im Jahre 1986. G ist eine Programmiersprache mit hoher Abstraktionsebene, deren Ziel es ist, die Produktivität von Anwendern zu erhöhen und gleichzeitig dieselbe Ausführungsgeschwindigkeit wie Lower-Level-Sprachen wie z. B. FORTRAN, C und C++ zu ermöglichen.

LabVIEW: Grafisch, Datenflussprogrammierung

LabVIEW unterscheidet sich auf zweierlei Art von anderen universellen Programmiersprachen. Erstens findet die Programmierung in G durch das Verdrahten grafischer Symbole in einem Blockdiagramm statt. Dieser Programmcode wird anschließend direkt in Maschinencode kompiliert, welcher vom Computerprozessor ausgeführt werden kann. Obwohl G-Code grafisch dargestellt wird, umfasst er die gleichen Programmierkonzepte wie die meisten traditionellen Sprachen. So enthält G beispielsweise alle Standardkonstrukte wie Datentypen, Schleifen, Ereignismanagement, Variablen, Rekursion und objektorientierte Programmierung.

Abbildung 1: Eine While-Schleife wird in G intuitiv als grafische Schleife dargestellt, die solange ausgeführt wird, bis eine Stopp-Bedingung erfüllt wird.

Der zweite Hauptunterschied ist, dass G-Code, der in LabVIEW geschrieben wurde, den Regeln des Datenflussprinzips folgt, anstatt dem traditionelleren Ansatz der sequenziellen Ausführung einer Reihe an Befehlen, wie es in fast allen textbasierten Programmiersprachen wie z. B. C und C++ der Fall ist. Datenflusssprachen wie G (oder auch Agilent VEE, Microsoft Visual Programming Language und Apple Quartz Composer) betrachten Daten als das Hauptkonzept jedes Programms. Bei der datenflussorientierten Programmierung läuft ein Programm datengesteuert bzw. datenabhängig ab. Die Ausführungsreihenfolge wird durch den Fluss der Daten zwischen den Knoten im Programm bestimmt und nicht von sequenziellen Textzeilen.

Dieser Unterschied mag auf den ersten Blick unwesentlich erscheinen, allerdings sind die Auswirkungen enorm, da Entwickler sich nun fast ausschließlich auf die Datenpfade zwischen den Programmbereichen konzentrieren können. Die Knoten in einem LabVIEW-Programm (u. a. Funktionen, Strukturen wie Schleifen, Subroutinen u. v. m.) verfügen über Eingänge, verarbeiten Daten und erzeugen Ausgänge. Sobald die Eingänge eines beliebigen Knotens gültige Daten enthalten, führt der Knoten die Programmlogik aus, erzeugt Ausgangsdaten und überträgt die Daten an den nächsten Knoten des Datenpfads. Ein Knoten, der Daten von einem anderen Knoten erhält, kann erst dann ausgeführt werden, wenn der vorherige Knoten seine Ausführung beendet hat.

Vorteile der Programmierung in G

Intuitive grafische Programmierung

Wie die meisten Menschen lernen auch Ingenieure und Wissenschaftler durch das Betrachten und Verarbeiten von Bildern, ohne sich bewusst damit auseinanderzusetzen. Viele Ingenieure und Wissenschaftler können auch als „visuelle Denker“ bezeichnet werden, d. h., sie nutzen insbesondere visuelle Verarbeitung, um Informationen zu organisieren. Anders ausgedrückt: Sie denken am besten in Bildern. Dies wird in Universitäten und Hochschulen häufig noch weiter verstärkt, indem Studierende Lösungen zu Problemen als Prozessdiagramme darstellen sollen. Viele universelle Programmiersprachen erfordern jedoch das zeitintensive Erlernen der spezifischen textbasierten Syntax der jeweiligen Sprache und die anschließende Anwendung der Sprachenstruktur auf das zu lösende Problem. Die grafische Programmierung mit G bietet einen wesentlich intuitiveren Ansatz.

G-Code ist für Ingenieure und Wissenschaftler in der Regel einfacher zu verstehen, da sie mit dem Konzept der Visualisierung sowie der Darstellung von Prozessen und Aufgaben in Block- und Flussdiagrammen (die ebenfalls den Regeln des Datenflusses folgen) vertraut sind. Da datenflussbasierte Sprachen erfordern, dass die Programmstruktur auf dem Fluss der Daten basiert, werden Anwender angehalten, sich auf das zu lösende Problem zu konzentrieren. So erfasst ein typisches G-Programm z. B. auf mehreren Kanälen Temperaturdaten, überträgt diese anschließend an eine Analysefunktion und schreibt die analysierten Daten letztendlich auf die Festplatte. Der Fluss der Daten und die jeweiligen Schritte im Programm sind im LabVIEW-Blockdiagramm einfach nachzuvollziehen.

Abbildung 2: Daten werden mit der Erfassungsfunktion erfasst und über Verdrahtungen intuitiv an die Analysefunktion und anschließend an die Speicherfunktion weitergeleitet.

Interaktive Fehlerbehebungswerkzeuge

Da der grafische G-Code von LabVIEW einfach zu verstehen ist, gestalten sich auch Programmieraufgaben wie die Fehlerbehebung wesentlich intuitiver. LabVIEW bietet beispielsweise einzigartige Fehlerbehebungswerkzeuge, mit denen während der Programmausführung interaktiv beobachtet werden kann, wie Daten entlang der Verdrahtungen von einer Funktion zur nächsten übertragen werden (dieses wird in LabVIEW als Highlight-Funktion bezeichnet).

Abbildung 3: Die Highlight-Funktion bietet eine intuitive Möglichkeit, die Ausführungsreihenfolge des G-Codes nachzuvollziehen.

LabVIEW bietet zudem Fehlerbehebungsfunktionen für G, die mit denen in traditionellen Programmierwerkzeugen verglichen werden können. Auf diese Funktionen, u. a. Sonden, Haltepunkte und Hineinspringen/Überspringen/Hinausspringen, kann über die Werkzeugleiste des Blockdiagramms zugegriffen werden.

Abbildung 4: Die Werkzeugleiste des Blockdiagramms bietet Zugriff auf Fehlerbehebungswerkzeuge wie den Einzelschrittmodus.

Mit diesen Fehlerbehebungswerkzeugen ist es möglich, Daten an mehreren Stellen des Programms simultan zu untersuchen, die Ausführung zu unterbrechen und in Subroutinen zu springen, ohne dass eine komplexe Programmierung erforderlich wäre. Dies ist zwar auch in anderen Programmiersprachen möglich, jedoch ist es einfacher, den Programmstatus und die Beziehungen zwischen parallelen Codebereichen zu visualisieren.

Abbildung 5: Sonden sind effektive Werkzeuge in LabVIEW, um Werte, die entlang der Verdrahtungen übertragen werden, zu visualisieren. Dies gilt auch für parallele Codeabschnitte.

Abbildung 6: Im Sondenüberwachungsfenster können die Werte für alle Sonden der Anwendung (einschließlich Subroutinen) angezeigt werden.

Eine der gängigsten Fehlerbehebungsfunktionen in LabVIEW ist der immer aktivierte Compiler. Während Programmcode entwickelt wird, überprüft der Compiler kontinuierlich, ob Fehler aufgetreten sind, und bietet Semantik- und Syntax-Feedback für die Anwendung. Tritt ein Fehler auf, kann das Programm nicht ausgeführt werden. Dies wird durch einen durchbrochenen Pfeil in der Werkzeugleiste dargestellt.

Abbildung 7: Der durchbrochene Pfeil zeigt sofort an, ob im G-Code Syntaxfehler vorliegen.

Wird auf den durchbrochenen Pfeil geklickt, öffnet sich eine Liste mit zu behandelnden Problemen. Sobald diese Probleme gelöst wurden, kompiliert der LabVIEW-Compiler den Programmcode in Maschinencode. Sobald der Code kompiliert wurde, entspricht die Leistung des G-Programms in etwa der Leistung traditionellerer Sprachen wie C.

Abbildung 8: Die Fehlerliste zeigt detaillierte Erklärungen für jeden Syntaxfehler in der gesamten Codehierarchie.

Automatische Parallelität und Leistung

Datenflusssprachen wie LabVIEW ermöglichen automatische Parallelität. Im Gegensatz zu sequenziellen Sprachen wie C und C++ enthalten grafische Programme Informationen darüber, welche Teile des Codes parallel ausgeführt werden sollten. Ein gängiges Entwurfsmuster der Sprache G ist beispielsweise das Erzeuger/Verbraucher-Entwurfsmuster, bei dem zwei separate While-Schleifen unabhängig voneinander ausgeführt werden: Die erste Schleife erzeugt Daten, während die zweite Schleife die Daten verarbeitet. Obwohl sie parallel ausgeführt werden (u. U. mit unterschiedlichen Raten), werden zwischen den Schleifen über Queues, Standarddatenstrukturen in universellen Programmiersprachen, Daten ausgetauscht.

Abbildung 9: Das Erzeuger/Verbraucher-Entwurfsmuster von LabVIEW wird häufig für die Leistungssteigerung bei Anwendungen, die parallele Tasks erfordern, eingesetzt.

Aufgrund aktueller Entwicklungen bei Computerprozessoren ist Parallelität für Computerprogramme wichtig, da dadurch Leistungssteigerungen gegenüber rein sequenziellen Programmen erreicht werden können. Mehr als 40 Jahre lang haben Hersteller von Computerchips stetig Prozessortaktraten erhöht, um die Chipleistung zu steigern. Momentan sind jedoch weitere Erhöhungen der Taktgeschwindigkeiten zur Erzielung von Leistungssteigerungen wegen des Stromverbrauchs und der Wärmeabgabe nicht mehr realisierbar. Aufgrund dessen haben sich Hersteller auf neue Chiparchitekturen konzentriert, wobei mehrere Prozessoren auf einem Chip integriert sind.

Um die Leistungsvorteile von Multicore-Prozessoren nutzen zu können, müssen Anwendungen Multithreading-fähig sein (d. h., die Anwendung muss in Abschnitte aufgeteilt werden können, die unabhängig voneinander ausgeführt werden). Bei traditionellen textbasierten Sprachen müssen Threads explizit erstellt und verwaltet werden, um Parallelität zu implementieren. Dies ist eine große Herausforderung für Programmierer ohne großen Erfahrungsschatz auf diesem Gebiet.

Dank der parallelen Natur des G-Codes gestaltet sich die Implementierung von Multitasking und Multithreading in LabVIEW unkompliziert. Der integrierte Compiler arbeitet kontinuierlich im Hintergrund, um Codeabschnitte, die parallel ausgeführt werden können, zu identifizieren. Wann immer eine Verzweigung in einer Verdrahtung oder eine parallele Sequenz in den Knoten des Blockdiagramms auftritt, versucht der Compiler, den Code innerhalb eines von LabVIEW automatisch erstellten Threads parallel auszuführen. In der Computerfachsprache ist das eine „implizite Parallelität”, da Programmcode nicht speziell mit dem Zweck geschrieben werden muss, ihn parallel auszuführen. Die Sprache kümmert sich selbst um einen gewissen Grad an Parallelität.

Abgesehen vom Multithreading in einem Multicore-System bietet G eine noch bessere parallele Ausführung, indem die grafische Programmierung auf FPGAs ausgeweitet wird. FPGAs (Field-Programmable Gate Arrays) sind wiederprogrammierbare Schaltkreise, die über ein hohes Maß an Parallelität verfügen. Jeder Verarbeitungs-Task kann einem dedizierten Bereich des Chips zugewiesen und unabhängig ausgeführt werden. Dabei spielt die Anzahl der verfügbaren Verarbeitungskerne keine Rolle. Aufgrund dessen wird die Leistungsfähigkeit der Anwendung nicht eingeschränkt, wenn weitere Verarbeitungs-Tasks hinzugefügt werden.

In der Vergangenheit war die Programmierung von FPGAs Experten vorbehalten, die über fundierte Kenntnisse digitaler Hardwarebeschreibungssprachen verfügten. Jedoch haben auch immer mehr Anwender ohne FPGA-Expertise den Wunsch, FPGA-basierte benutzerdefinierte Hardware einzusetzen, um individuelle Timing- und Triggerroutinen, Hochgeschwindigkeits-Steuer- und -Regel- sowie RF- und Kommunikationsanwendungen und weitere Anwendungen zu erstellen, die zuverlässige Hardware für hohe Geschwindigkeiten, benutzerdefinierte Anpassung und hohen Determinismus erfordern. G-Code ist besonders geeignet für die FPGA-Programmierung, da er die Parallelität und den Datenfluss eindeutig abbildet. Des Weiteren gewinnt die Programmiersprache unter Entwicklern, die parallele Verarbeitung und deterministische Ausführung benötigen, immer mehr an Popularität.

Abbildung 10: Die Speicherverwaltung in LabVIEW ist optional, wobei fortgeschrittene Anwender die Speichernutzung überwachen und optimieren können.

Zeigt G-Code unerwartetes Verhalten, das mit den oben genannten Werkzeugen nicht behoben werden kann, stehen erweiterte Fehlerbehebungsfunktionen in Form des LabVIEW Desktop Execution Trace Toolkits zur Verfügung. Dieses Toolkit wurde für fortgeschrittenere Anwender konzipiert, die dynamische Codeanalysen durchführen wollen, u. a. zur:

Erkennung von Speicher- und Referenzverlusten
Isolierung des Ursprungs eines Ereignisses oder unerwünschten Verhaltens
Suche nach Anwendungsbereichen, deren Leistung verbessert werden kann
Identifizierung des letzten Aufrufs vor dem Auftreten eines Fehlers
Sicherstellung, dass die Anwendung auf verschiedenen Zielgeräten gleich ausgeführt wird

Einsatz von G mit anderen Sprachen

Obwohl G-Code eine exzellente Darstellung der Parallelität ermöglicht und die Speicherzuweisung übernimmt, ist er nicht unbedingt für jede Aufgabe ideal geeignet. Insbesondere mathematische Formeln und Gleichungen lassen sich häufig besser als Text darstellen. Aus diesem Grund kann LabVIEW mit verschiedenen Arten der textbasierten Programmierung kombiniert werden. Bei der Arbeit mit LabVIEW kann der Anwender wählen, ob er den textbasierten oder grafischen Ansatz bzw. eine Kombination aus beiden bevorzugt.

LabVIEW umfasst z. B. den Formelknoten, der, ähnlich wie C, textbasierte mathematische Funktionen und Ausdrücke auf dem Blockdiagramm evaluiert. Diese mathematischen Formeln können zusammen mit grafischem LabVIEW-Code ausgeführt und in diesen integriert werden.

Abbildung 11: Der Formelknoten nutzt eine ähnliche Syntax zu C und stellt mathematische Ausdrücke in einem textbasierten Format dar.

Einfache Möglichkeiten zur Problemlösung

LabVIEW und sein grafischer, datenflussbasierter Programmieransatz bieten einfachere Möglichkeiten für die Lösung von Problemen als traditionelle Lower-Level-Sprachen. Der Beweis hierfür liegt in der Langlebigkeit von LabVIEW. Die Hauptunterschiede der Programmierung in G liegen im intuitiven, grafischen Code und der datengesteuerten Ausführung. Zusammen bieten sie eine Programmiererfahrung, die die Gedankenprozesse des Anwenders besser widerspiegelt als andere Sprachen. Obwohl G eine Higher-Level-Sprache ist, kann aufgrund des integrierten LabVIEW-Compilers trotzdem eine Ausführungsleistung erzielt werden, die Sprachen wie C entspricht.