Ereignisbasierte Python-Traceschrittvorlagen erstellen

Das Vorgehen zum Anlegen einer neuen Traceschrittvorlage wurde bereits im Abschnitt Allgemeines Vorgehen erläutert. Während das Anlegen von Signalen und Parametern für alle Vorlagearten identisch ist, unterscheidet sich die Implementierung der eigentlichen Analysevorschrift deutlich.

Für eine ereignisbasierte Python-Traceschrittvorlage hat man die Möglichkeit, eigene Python-Funktionen (sog. Next-Funktionen) zu erstellen und an Signale zu binden. Das Binden der Python-Funktionen an Signale hat dabei zum Ziel, dass ecu.test während der Traceanalyse die Python-Funktionen aufruft und dabei die konkreten Werte der Signale übergibt, an welche die Funktionen gebunden sind. Zu beachten ist, dass Next-Funktionen nur zu jenen Zeitstempeln aufgerufen werden, zu denen mindestens ein angebundenes Signal einen Messwert aufweist. Zusätzlich zu diesen Python-Funktionen stehen noch eine Init- und eine Finalize-Funktion zur Verfügung, die zu Beginn bzw. am Ende jedes Analysedurchlaufes aufgerufen werden und dafür vom Entwickler mit Python-Code befüllt werden können.

../../../../../_images/TraceStepTemplates_PythonEventBasedExample.png

Die Schnittstellen der Init- und Finalize-Funktionen:

def Init(dataContainer, parameters, report):
    ...
def Finalize(dataContainer, parameters, report):
    ...

Beiden Funktionen werden beim Aufruf durch ecu.test zwei Parameter übergeben:

dataContainer:

Stellt den Zugriff auf ecu.test-Variablen zur Verfügung. Die Beschreibung der Schnittstelle ist in der Dokumentation der Trace Analysis API zu finden.

parameters:

Ein Python-Dictionary, in dem zu jedem in der Vorlage definierten Parameter der im Traceschritt angegebene Parameter-Wert hinterlegt ist.

report:

Stellt den Zugriff auf den Testreport zur Verfügung. Die Beschreibung der Schnittstelle ist in der Dokumentation der Trace Analysis API zu finden.

Die Schnittstelle der Funktionen (Next-Funktionen), die an Signale gebunden werden, ist wie folgt:

def Next(event, hold, dataContainer, parameters, report):
    ...

Diese Funktionen werden durch ecu.test chronologisch aufsteigend für jeden Zeitstempel einmal aufgerufen, an dem eines der Signale, an welche die Funktion gebunden ist, einen Messwert aufweist. Haben zu einem Zeitstempel mehrere Signale einen Messwert, so wird die Funktion trotzdem nur einmal aufgerufen. Alle Signale, die einen Messwert zum Zeitstempel aufweisen, werden im Parameter event der Funktion übergeben.

Genannten Funktionen werden beim Aufruf durch ecu.test vier Parameter übergeben:

event:

Stellt den Zugriff auf das aktuelle Traceevent bereit. Darüber können der Zeitstempel (event.GetTime()) sowie die aktuellen Signalwerte (event.GetValue("SignalName")) abgefragt werden. Die Beschreibung der Schnittstelle ist in der Dokumentation der Trace Analysis API zu finden.

hold:

ecu.test übergibt hier ein Objekt, welches als eine Art Halteregister den jeweils letzten bekannten Signalwert aller Signale, an die der Traceschritt gebunden ist, bereit hält. Wie auf dem event-Objekt können auch hier mittels hold.GetValue("SignalName") die Signal-Werte abgefragt werden. Die vollständige Beschreibung der Schnittstelle ist wiederum in der ecu.test-API-Dokumentation zu finden.

dataContainer:

Stellt den Zugriff auf ecu.test-Variablen und die Parameter zur Verfügung. Die vollständige Beschreibung der Schnittstelle ist wiederum in der ecu.test-API-Dokumentation zu finden.

parameters:

Ein Python-Dictionary, in dem zu jedem in der Vorlage definierten Parameter der im Traceschritt angegebene Parameter-Wert hinterlegt ist.

report:

Stellt den Zugriff auf den Testreport zur Verfügung. Die Beschreibung der Schnittstelle ist in der Dokumentation der Trace Analysis API zu finden.

dataContainer-Objekt als Variablen-Speicher

Wie in Python üblich, sind alle in Funktionen verwendeten Variablen lokal, das heißt, bei jedem Aufruf einer Funktion sind sie wieder „leer“. Um Zwischenergebnisse über mehrere Aufrufe der Funktionsaufrufe hinweg persistent zu halten, bietet ecu.test das Objekt dataContainer an. ecu.test übergibt während eines Analysedurchlaufes an alle Funktionen eines Traceschrittes dasselbe dataContainer-Objekt. Dies kann genutzt werden, um beispielsweise in der Init-Funktion mittels dataContainer.zwischenergebnis = 0 eine eigene persistente Variable anzulegen, auf die dann in den Next-Funktion und auch der Finalize-Funktion lesend und schreibend zugegriffen werden kann.

Beispiel MinimumMaximum

Anhand der mitgelieferten Traceschrittvorlage „MinimumMaximum“ soll die grundlegende Funktionsweise Python-basierter Traceschrittvorlagen verdeutlicht werden:

../../../../../_images/TraceStepTemplates_MinMaxExample.png

MinimumMaximum-Traceschrittvorlage mit zum Editieren geöffneter Next-Methode

Über die Schaltfläche (1) wird ein neues Signal angelegt. Dabei sollte ein aussagekräftiger Name gewählt werden (2) (im Beispiel „Signal“). Dieses Signal abstrahiert den Namen, der in der Aufnahme vorhanden ist von dem, der in der Traceschrittvorlage verwendet wird. Somit kann die gleiche Vorlage für die Auswertung verschiedener Signale ohne Anpassungen verwendet werden. Über (3) wird eine neue Funktion erstellt, der in (4) ein Name zugewiesen wird. Über die Schaltfläche (5) werden die Signale ausgewählt, bei deren Vorkommen in der Aufnahme die Funktion aufgerufen wird.

Im Beispiel wird bei jedem Vorkommen des Signals die Funktion Next aufgerufen. Dabei wird der aktuelle Signalwert der Variablen value zugewiesen (value = event.GetValue("Signal")).

Die beiden Variablen dataContainer.min und dataContainer.max werden in der Init-Funktion initialisiert:

def Init(dataContainer, parameters, report):
    dataContainer.min = ''   # min(x, '') yields x
    dataContainer.max = None # max(x, None) yields x

Zum Schluss wird mithilfe der Funktion Finalize das Ergebnis ausgegeben:

def Finalize(dataContainer, parameters, report):
    report.SetResultText("Min: %s\nMax: %s" \
           % (dataContainer.min, dataContainer.max))

Der Ablauf ist nun folgender:

Nehmen wir an, das Signal hat die Werte 2, 1, -5, 6, 0. Beim ersten Vorkommen wird die Funktion Next aufgerufen. Die Variable value ist mit 2 belegt. Die Funktion min von datacontainer.min ("")und 2 liefert 2. Somit steht in datacontainer.min eine 2. Die Funktion max von datacontainer.max (None)und 2 liefert ebenfalls eine 2. Somit steht nach dem ersten Funktionsaufruf in datacontainer.min und datacontainer.max eine 2. Beim zweiten Funktionsaufruf wird nun min von 2 und 1 und max von 2 und 1 gebildet. Somit steht in datacontainer.min eine 1 und in datacontainer.max eine 2. Mit den weiteren Werten wird genauso verfahren, so dass zum Schluss in datacontainer.min eine -5 und in datacontainer.max eine 6 zu finden ist, die in der Finalize-Funktion in den Testreport geschrieben werden.

Standardvorlagen anpassen am Beispiel CalculateMinMax

Standardvorlagen lassen sich nicht direkt editieren. Man kann jedoch eine Kopie der Standardvorlage bearbeiten und wie eine eigene Vorlage verwenden.

Im Tab Traceschrittvorlagen finden Sie im Dateibaum zu den Standardvorlagen unter StandardTraceStepTemplates/Calculate die Vorlage „CalculateMinMax“. Da Standardvorlagen nicht editiert werden können, kopieren Sie sich die Vorlage zunächst in die „Eigenen Vorlagen“. Machen Sie hierzu einen Rechtsklick auf der Vorlage CalculateMinMax und wählen Sie im Kontextmenü den Eintrag Kopieren. Anschließend machen Sie einen Rechtsklick im Dateibaum zu den Eigenen Vorlagen, also zum Beipiel einen Rechtsklick auf den Order TraceStepTemplates und wählen Einfügen. Es erscheint ein Dialog mit der Frage, ob die Referenzen von Packages, die die Vorlage CalculateMinMax verwenden, auf die Kopie zeigen sollen. Schließen Sie diesen Dialog durch einen Klick auf Nein. Die Kopie der Vorlage wird jetzt im Dateibaum zu den eigenen Vorlagen angezeigt. Per Doppelklick lässt sich die Kopie der Vorlage zum Editieren öffnen.

Info

Hat eine eigene Vorlage die gleiche ID wie eine Standardvorlage, so wird bei Referenzierung der ID immer die eigene Vorlage herangezogen. Wird beispielsweise eine Kopie von CalculateMinMax im Unterordner Calculate gespeichert, so wird die Standardvorlage durch die eigene Vorlage verdeckt.