Eine Einführung

Objektorientierte Programmierung mit MATLAB
Kommentare

Die objektorientierte Programmierung (OO) ist eine Methodik in der Softwareentwicklung, bei der Zusammenhänge zwischen Daten und Algorithmen in Form von Objekten dargestellt werden. Dadurch können wieder verwendbare Komponenten erstellt werden, die in größeren Programmen einfach nach dem Baukastenprinzip zusammengesetzt werden. Für Wissenschaftler und Ingenieure ist dies eine effektive Möglichkeit, komplexe Systeme in Teilkomponenten zu zerlegen, zu verstehen und einmal geleistete Arbeit wiederzuverwenden. Das erleichtert auch die Verwaltung komplexer Softwareentwicklungen erheblich. Objektorientierte Arbeitsweisen sind von großer Bedeutung für die Entwicklung und Pflege großer Anwendungen und Datenstrukturen.

In diesem Artikel wird anhand der Implementierung einer typisch technischen Anwendung gezeigt, wie objektorientierte Methoden in der MATLAB-Sprache umgesetzt werden können. Die vorgestellten Beispiele beruhen auf Funktionen aus MATLAB 7.6, das mit dem Release 2008a ausgeliefert wird.

Anwendungsbeispiel: Analyse von Daten eines Sensorengitters

Als Sensorengitter (Abb. 1) bezeichnet man Anordnungen von Sensoren, mit deren Hilfe Medien wie Luft, Wasser oder der Erdboden abgetastet werden. Sensorengitter sind oft linear aufgebaut und werden beispielsweise für Radar- und Sonaranwendungen, im Mobilfunk und für viele andere Aufgaben eingesetzt. Indem man Daten an unterschiedlichen Punkten im Raum sammelt, geordnet nach Ankunftszeiten der Signale, lassen sich zusätzliche Informationen über das abgetastete Medium extrahieren.

Abb. 1: Ein Sensorengitter, das zwei entfernte elektromagnetische Quellen mit unbekannten Empfangswinkeln detektiert

In der hier geschilderten Anwendung dient das Sensorengitter zur Ermittlung der Empfangsrichtung (Direction of Arrival, DOA) mehrerer entfernter elektromagnetischer Quellen wie Funkbaken oder Radarsender. Im hier behandelten Szenario sollen die Winkel θ1 und θ2 der beiden Quellen relativ zur Blickrichtung des Sensorengitters bestimmt werden.

Die Sprache der objektorientierten Programmierung

Eine Softwareanwendung kann die unterschiedlichsten Kategorien oder Gegenstände abbilden. Dies können physikalische Objekte wie etwa Fahrzeuge oder Organismen, virtuelle Gebilde wie Finanzmärkte, aber auch Informationen wie etwa Testergebnisse sein. Bei der objektorientierten Programmierung werden diese Kategorien als Klassen dargestellt. Datenelemente oder Zustände werden dabei als Klasseneigenschaften behandelt, Operationen als Klassenmethoden implementiert. Ein Objekt ist eine Instanz einer Klasse – während der Ausführung eines Programms wird das Objekt gemäß der Klassendefinition erzeugt und zeigt das für diese Klasse festgelegte Verhalten. Alle in MATLAB-Variablen gespeicherten Werte gehören zu einer bestimmten Klasse. Zu diesen Werten gehören nicht nur solche, die üblicherweise als Objekte aufgefasst werden, wie etwa Zeitreihen- oder Zustandsraumobjekte, sondern auch einfache Double-Werte.

Klassen in MATLAB

Die Klasse einer Variablen lässt sich in MATLAB neben einer Reihe weiterer Merkmale in der Ausgabe des whos-Befehls identifizieren. Beispiele für solche Klassen sind double, char, int8, struct, undtimeseries.

>> a=1;
>> str=’Hello’;
>> whos
Name Size Bytes Class Attributes
a 1x1 8 double
tr 1x5 10 char

Zusammenstellung der Datenelemente und Operationen

Vor Beginn der Anwendungsentwicklung muss geklärt werden, welche Datenelemente benötigt werden und welche Operationen an diesen ausgeführt werden müssen. Wie bei den meisten Anwendungen, müssen zur Ausführung der notwendigen Operationen eine Reihe verschiedener Arten von Daten gespeichert und verfolgt werden. Im gewählten Beispiel sind dies:

  • Anzahl der Sensoren und Samples
  • Aufgezeichnete Daten-Samples
  • Abtastrate der Sensoren
  • Sensorenabstände
  • Sendewellenlänge(n) der entfernten Quellen
  • Wellenausbreitungsgeschwindigkeit
  • Name oder Beschreibung des Sensordatensatzes

Zur Abschätzung der Empfangsrichtungen der Quellen dient eine einfache FFT-basierte Methode. Diese Methode lässt sich auf mehrere Einzelteile herunterbrechen und so als Abfolge von Operationen implementieren. Zur Vereinfachung der Entwicklungsarbeit werden aber zunächst einige Hilfsoperationen implementiert. Für die gewählte Anwendung muss das Programm unter anderem:

  • den Datensatz aus synthetischen Daten oder echten Messdaten erzeugen
  • Werte und Parameter des Datensatzes prüfen und verändern
  • die abgetasteten Daten grafisch darstellen und damit deren Interpretation und Validierung erleichtern
  • das gemittelte Amplitudenquadrat der FFT des Datensatzes berechnen und es als Periodogramm darstellen
  • die Spitzen des Periodogramms finden, mit deren Hilfe die DOA der Quellen abgeschätzt wird.

Mit diesen Informationen lässt sich nun festlegen, welche Teile des Programms durch Klasseneigenschaften dargestellt werden und welche als Klassenmethoden implementiert werden.

Darstellung von Daten durch Klasseneigenschaften

Als erstes wird eine Klasse definiert, die das Sensorengitter beschreibt. Diese erste Beschreibung enthält nur die Datenelemente. Sie werden als Klasseneigenschaften dargestellt.

In MATLAB werden Klassen mithilfe von Klassendefinitions-Files definiert. Eine solche Datei enthält Codeblöcke aus Schlüsselwörtern und Endanweisungen, in denen die verschiedenen Merkmale der Klasse beschrieben werden. Das in Abbildung 2 gezeigte Definitions-File beschreibt die Klasse sads (kurz für Sensor Array Data Set). Alle Datenelemente, die zu ihrer Darstellung benötigt werden, sind in einem gemeinsamen Properties-Block aufgeführt.

Abb. 2. Das Klassendefinitions-File sads.m mit seinen Eigenschaften

[ header = Seite 2: Erzeugung von Objekten und Zugriff auf deren Eigenschaften ]

Erzeugung von Objekten und Zugriff auf deren Eigenschaften

Ein Objekt – oder eine Instanz – der eben definierten Klasse lässt sich nun erzeugen durch die Anweisung:

>> s=sads;

Eigenschaften weist man auf die gleiche einfache Weise Werte zu wie den Feldern einer Struktur, beispielsweise:

>> s.NumSensors=16;

Das Objekt mit allen seinen verfügbaren Eigenschaften sowie deren momentanen Werten lässt sich nun durch Eingeben seines Namens anzeigen.

>> s
s =
sads
properties:
NumSensors: 16
NumSamples: []
Data: []
SampleRate: []
Spacing: []
Wavelength: []
c: 300000000
Name: []
list of methods

Alle Eigenschaften außer NumSensors und c sind noch leer. Durch einen Doppelklick auf das Objekt im Workspace-Browser können alle Eigenschaften im Variablen-Editor eingesehen oder verändert werden. Die Eigenschaften werden also auch hier behandelt wie die Felder einer Struktur (Abb. 3).

Abb. 3. Das Sensorengitter-Objekt wird im Workspace Browser angezeigt (links). Seine Eigenschaften können im Variablen-Editor verändert werden (rechts)

In den Funktionen class und isa sowie mit dem Befehl whos wird der Datensatz nun als sads-Objekt identifiziert. Hierin unterscheidet er sich von einer Struktur.

>> class(s)
ans =
sads

Die Fähigkeit, die Klasse einer Variablen zu identifizieren ist wichtig, wenn man ein Programm schreiben will, das mit dem Datensatz arbeitet. Der Anwender kann dadurch unmittelbar alle verfügbaren Datenelemente sowie die daran erlaubten Operationen ermitteln.

Fehlerkontrolle

Wenn man Daten durch Strukturen ausdrückt, kann man diese Strukturen jederzeit um neue Feldnamen erweitern. Man definiert einfach den neuen Namen und weist ihm einen Wert zu. Diese Fähigkeit ist besonders praktisch in der Experimentier- oder Prototyping-Phase neuer Algorithmen. Schreibt man dabei aber einen Feldnamen einmal falsch, dann erzeugt man unbemerkt ein neues Feld, das später einen Fehler erzeugen kann, der sich nur schwer diagnostizieren lässt.

Im Gegensatz zu Strukturen kann man Objekte nicht beliebig durch Definition eines neuen Eigenschaftsnamens und Setzen eines Wertes um neue Eigenschaften erweitern. MATLAB gibt einen Fehler aus, sobald man den Eigenschaftsnamen eines Objekts falsch schreibt. Diese zusätzliche Ebene der Fehlerkontrolle erweist sich als nützlich, wenn ein Anwender auf das Objekt zugreift, der damit nicht so vertraut ist wie der Autor, was insbesondere bei der Entwicklung umfangreicher Anwendungen häufig der Fall ist.

Festlegung von Zugriffsarten und Zugriffsrechten

Mit Klassen lässt sich der Zugriff auf Objekteigenschaften umfassend kontrollieren. So kann man beispielsweise die Veränderung von Eigenschaften verbieten, Eigenschaften verbergen oder sie dynamisch berechnen lassen. Die Art des Zugriffs auf Eigenschaften wird durch Definition von Eigenschafts-Attributen im Klassendefinitions-File festgelegt.

Das Klassendefinitions-File aus Abb. 2b wird dazu durch Unterteilung der aufgelisteten Eigenschaften in mehrere neue Eigenschaftsblöcke mit Eigenschafts-Attributen erweitert, in denen sich die Datenelemente eindeutig voneinander unterscheiden (Abb. 4) Im vorliegenden Fall sind das die Attribute GetAccess, Constant und Dependent.

Abb. 4. Das Klassendefinitions-File sads.m mit Eigenschaftsattributen

Die Veränderung einer Eigenschaft verbietet man mit dem Attribut Constant, wie hier bei der Lichtgeschwindigkeit c geschehen. Da konstante Eigenschaften sich nicht ändern, kann man auf sie zugreifen, indem man ganz einfach den Klassennamen referenziert.

>> sads.c
ans =
300000000

Den Schreibzugriff auf eine Eigenschaft verbietet man durch Setzen des Attributs SetAccess auf private. Um eine Eigenschaft ausschließlich für die auf sie angewandten Methoden sichtbar zu machen, setzt man das Attribut GetAccess ebenfalls auf private, wie in Abbildung 4 mit der Eigenschaft Wavelength geschehen.

Namen oder Merkmale privater Eigenschaften kann man beliebig verändern, ohne dass dies Auswirkungen auf irgendwelche Nutzer des zugehörigen Objekts hat. Dieser auch Verkapselung oder Encapsulation genannte „Black Box“-Ansatz zur Definition eines Programmteils verhindert, dass ein Nutzer eines Objekts von einem bestimmten Detail oder Merkmal der Implementierung abhängig wird, das möglicherweise später verändert wird und damit einen Bruch im Programmcode erzeugt.

Mithilfe des Attributs Dependent lässt sich bewirken, dass eine Eigenschaft nur auf Anforderung berechnet wird. Danach wird eine Get-Methode definiert, die beim Zugriff auf die Eigenschaft automatisch aufgerufen wird. Einzelheiten dazu sind im Kapitel „Zugriff auf Eigenschaften mit Get- und Set-Methoden“ dieses Artikels beschrieben. In der vorliegenden Anwendung sind die Eigenschaften NumSensors und NumSamples auf Dependent gesetzt.

[ header = Seite 3: Implementierung von Operationen mit Klassenmethoden ]

Implementierung von Operationen mit Klassenmethoden

Methoden, also auf ein Objekt anwendbare Operationen, werden als Funktionsliste in einem Methoden-Block definiert. Eine Klasse kann viele verschiedene Arten von Methoden enthalten, von denen jede ihrem eigenen Zweck dient und auf ganz bestimmte Weise definiert ist. Im folgenden Abschnitt werden verschiedene Methodentypen vorgestellt.

Das Definitions-File der Klasse sads wird zunächst um einen Methodenblock erweitert, der zur Aufnahme aller künftig erzeugten Methoden bestimmt ist (Abb. 5).

Abb. 5. Das im MATLAB Editor angezeigte Klassendefinitions-File sads.m mit seinen Methoden. Der Übersicht halber wurde ein Großteil des Programmcodes durch die Codefaltungs-Funktion verborgen

Definition einer Konstruktor-Methode

Zuerst wird eine Konstruktor-Methode definiert, mit deren Hilfe der Anwender die Werte einiger wichtiger Parameter bereits bei der Erzeugung des Objekts festlegen kann. Die Konstruktor-Methode wird häufig zur Initialisierung und Validierung von Daten eingesetzt. Das Objekt wird nun durch folgende Eingabe erzeugt:

>> s=sads(Daten, Wellenlämge, Abtastrate, Abstand, Name);

Implementierung anwendungsspezifischer Methoden

Danach müssen die Methoden implementiert werden, die die für den Anwendungszweck erforderlichen Operationen am Datensatz ausführen. Die meisten dieser Methoden nutzen das Objekt als Eingabeargument (beispielsweise obj) und greifen, wie in der folgenden Methode gezeigt, durch Referenzierung dieser Variablen auf die Objekteigenschaften zu (beispielsweise obj.NumSamples):

function [mags,fflip]=magfft(obj, zpt)
mag=zeros(obj.NumSamples, zpt);
...
end

Die Referenzierung von Eigenschaften über Objektvariablen erfordert zwar zusätzliche Syntax, ist aber nützlich, weil sie Objektvariablen eindeutig von lokalen Funktionsvariablen – etwa mag im obigen Beispiel – abgrenzt.

Aufrufen von Methoden

Methoden werden auf die gleiche Weise aufgerufen wie Funktionen. Jedes Objekt wird hierbei als ein Argument der Methode eingegeben. Beim Aufruf der Methode, die das Periodogramm erzeugt, mit den passenden Argumenten erhalten wir das in Abbildung 6 gezeigte Diagramm.

 Abb. 6. Winkelabhängige Darstellung des Periodogramms

>> magfftplot(s,128)

Ruft man nun die Methode zur Berechnung der Empfangsrichtung der Quellen auf

>> angles=doa(s)
angles =
-10.1642 18.9953

so erhält man zwei Werte, die den beiden Spitzen in Abbildung 6 entsprechen. Sie liegen relativ nahe an den tatsächlichen Werten von –10° und 20° in Abbildung 1.

Zugriff auf Eigenschaften mit Get- und Set-Methoden

Durch Definition mit bestimmten Eigenschaften verknüpfter Set- und Get-Methoden können, wie bereits erwähnt, Eigenschaften validiert oder von Bedingungen abhängig gemacht werden. Die Get-Methode für die Eigenschaft NumSensors lautet:

function NumSensors=get.NumSensors(obj)
NumSensors=size(obj.Data,2);
end

Get- und Set-Methoden werden beim Zugriff auf Eigenschaften automatisch aufgerufen, beispielsweise durch

>> N=s.NumSensors;

Definition von Methoden mit vorhandenen MATLAB-Funktionen durch Overloading

Durch Overloading lassen sich vorhandene MATLAB-Funktionen so umdefinieren, dass sie als Name in der Liste der Klassenmethoden auftauchen und auf Objekte angewandt werden können. Auch Operatoren und sogar Indexierungen können überladen werden, indem man Methoden mit entsprechenden Namen einsetzt. In diesem speziellen Fall wird die plot-Funktion aus MATLAB als Grafik-Methode überladen und damit eine Visualisierungsfunktion für den Datensatz geschaffen, die den meisten Anwendern vertraut ist (Abb. 7).

Abb. 7. Durch Overloading erzeugte und für den Datensatz des Sensorgitters optimierte Grafikmethode

>> plot(s)

Diese Grafikmethode ist genau auf die vorliegende Anwendung zugeschnitten: Sie zeigt den Datensatz auf zweckdienliche Weise an und enthält alle zu seinem Verständnis benötigten Informationen. Sie wird nur an Objekten ausgeführt, für die sie explizit definiert wurde. Diese Vorgehensweise ist deutlich robuster als die, die Reihenfolge der im MATLAB-Pfad aufgeführten Verzeichnisse immer so zu manipulieren, dass aus möglicherweise vielen verschiedenen Funktionen gleichen Namens wirklich immer nur die gewünschte aufgerufen wird.

Weiterentwicklung der Anwendung

Die in diesem Artikel erzeugte Klasse repräsentiert den Datensatz für das Sensorengitter und enthält eine Reihe von Operationen, mit denen sich Daten analysieren lassen, insbesondere die zur Richtungsermittlung dienende Hauptoperation. Diese Klasse kann nun beispielsweise genutzt werden, um die Leistung der FFT-basierten Methode in unterschiedlichen Szenarien zu ermitteln.

Die Anwendung lässt sich außerdem mithilfe weiterer OO-Techniken erweitern. Man könnte beispielsweise:

  • Unterklassen vorhandener Klassen mit Vererbung definieren und dabei die Definition einer weiter gefassten Kategorie zur Schaffung einer spezifischeren Unterkategorie wiederverwenden
  • Statische Methoden erzeugen, mit deren Hilfe sich Operationen für eine Klasse als Ganzes definieren lassen
  • Handle-Klassen mit Referenzverhalten definieren und so die Erzeugung von Datenstrukturen wie Linked Lists ermöglicht oder mit großen Datensätzen arbeiten zu können, ohne diese kopieren zu müssen
  • Ereignisse und Listener definieren und damit Eigenschaften oder Aktionen von Objekten überwachen

Mithilfe dieser Techniken lassen sich die Beziehungen und das Verhalten innerhalb der Anwendung weitergehend definieren als bis hierher gezeigt, wodurch sich insbesondere komplexere Programme leichter handhaben lassen.

Weil die hier vorgestellte Anwendung mit objekt-orientierten Methoden erzeugt wurde, ist sie robust genug, um nun auch von anderen Anwendern genutzt und sogar gepflegt zu werden. Sie lässt sich außerdem problemlos in eine bestehende Software-Infrastruktur integrieren.

Glossar Objekt-Orientierte Programmierung

Klasse: Eine Kategorie oder Menge von Objekten Klassendefinitions-File: Ein MATLAB-File, das das Verhalten einer Klasse festlegt Methode: Eine Operation, die an einem Objekt ausgeführt werden kann Objekt: Eine in einem Workspace vorhandene Instanz einer Klasse Eigenschaft: Ein zu einem Objekt gehöriges Daten- oder Zustandselement

 

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -