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.
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 mittelshold.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:
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.