Erstellen einer eigenen arraybasierten NumPy-Traceschrittvorlage

Nach der Anbindung des zu analysierenden Signals „CarSpeed“ soll nun die eigentliche Traceanalyse erstellt werden. Dies geschieht im Rahmen dieses Tutorials mithilfe einer arraybasierten NumPy-Traceschrittvorlage, in der die Analysevorschrift zunächst unabhängig von der konkreten Signalanbindung (und damit möglichst allgemeingültig und gut wiederverwendbar) spezifiziert wird.

Klicken Sie zum Anlegen der Traceschrittvorlage im Tab Traceschrittvorlagen des Aktionsfensters unter Eigene Vorlagen auf das Icon für neue Traceschrittvorlagen und wählen Sie den Eintrag NumPy arraybasiert aus. (Im Handbuch werden im Abschnitt Allgemeines Vorgehen die verschiedenen Arten von Traceschrittvorlagen und ihre Erstellung erläutert.)

../../_images/Tutorial_CreateNewArrayBasedTraceStepTemplate.png

Erstellen einer neuen arraybasierten NumPy-Traceschrittvorlage

Nehmen Sie im daraufhin erscheinenden Dialog folgende Eintragungen vor:

  • Vergeben Sie im Bereich Allgemein den Namen CheckThreshold als ID für die Traceschrittvorlage.

  • Geben Sie optional einen Beschreibungstext ein.

  • Legen Sie im Bereich Signale per Klick auf CreateNewBtn ein Eingangssignal (Richtung IN) mit dem Namen Signal an.

  • Legen Sie im Bereich Parameter per Klick auf CreateNewBtn die folgenden zwei Parameter an:

    • Eingabeparameter (Richtung IN) namens threshold vom Typ FLOAT

    • Ausgabeparameter (Richtung OUT) namens maxValue vom Typ FLOAT

Der fertig ausgefüllte Dialog sollte wie folgt aussehen:

../../_images/Tutorial_ArrayBasedTraceStepTemplate_CheckThreshold.png

Wizard zum Erstellen arraybasierter NumPy-Traceschrittvorlagen

Anders als bei anderen Traceschrittvorlage-Typen ist dieser Dialog als Wizard zu verstehen, d.h. nach Betätigen der Schaltfläche Generieren werden die vorgenommenen Eintragungen in einer Python-Klasse umgesetzt, die den zuvor unter ID angegebenen Namen trägt und die Traceschrittvorlage vollständig beschreibt. Diese Python-Klasse wird automatisch geöffnet - je nach Einstellung entweder im in ecu.test integrierten oder in einem externen Python-Editor.

Bemerkung

Wenn Sie einen externen Editor verwenden, können Sie die Typüberprüfung und die automatische Vervollständigung aktivieren, indem Sie die mit ecu.test ausgelieferten Interfaces hinzufügen. Siehe Trace Analysis API.

Die Methoden GetDescription(), GetSignals() und GetParameters() der generierten Klasse spiegeln die eben im Dialog vorgenommenen Eintragungen wieder und erlauben eine nachträgliche Anpassung (Ein erneutes Öffnen des Wizard-Dialogs zur Nachbearbeitung einer einmal generierten Python-Klasse ist nicht möglich!):

@classmethod
def GetDescription(cls):
    """
    Returns the description of the trace step.

    :rtype: unicode
    """
    return 'Checks whether the given signal exceeds the given threshold'
@classmethod
def GetSignals(cls):
    """
    Returns the incoming and outgoing signals of the trace step.

    :rtype: list[SignalDefinition]
    """
    return [
        SignalDefinition('Signal', 'IN', optional=False, description=''),
        ]
@classmethod
def GetParameters(cls):
    """
    Returns the input and return parameters of the trace step.

    :rtype: list[ParameterDefinition]
    """
    return [
        ParameterDefinition('threshold', 'IN', description=''),
        ParameterDefinition('maxValue', 'OUT', description=''),
        ]

Die eigentliche Analysevorschrift der Traceschrittvorlage muss in der Methode Process() (ganz am Ende der generierten Klasse) eingefügt werden. Erklärungen zu den Parametern dieser Methode können dem generierten DocString sowie dem Abschnitt Arraybasierte NumPy-Traceschrittvorlagen erstellen und der Trace Analysis API Referenz entnommen werden. Für die im Rahmen dieses Tutorials vorliegende Aufgabenstellung - der Suche nach Schwellwertverletzungen - ist die Methode Process() wie folgt zu implementieren:

def Process(self, parameters, report, timeAxis, ranges, signals):
    """
    ...

    """

    # Copy parameters to local variables
    threshold =  parameters['threshold']

    # Maximum value, we have found so far. Initially this is NaN (not a number).
    maxValue = float('NaN')

    # Process() is called only once and receives a list of trigger ranges (or one range that
    # spans the entire time domain, when not using a trigger block). Here we iterate over each
    # of the ranges.
    for triggerRange in ranges:
        # triggerRange.GetValues() returns the values of the specified signal as a NumPy array,
        # which is cropped to the range, i.e. triggerRange.GetValues('Signal')[0] returns the first
        # value within the range, triggerRange.GetValues('Signal')[-1] returns the last.
        values = triggerRange.GetValues('Signal')

        # Analogously, triggerRange.GetTimestamps() returns the timestamps, cropped to the current
        # range. No signal name needs to be specified, as all signals are mapped to a common time axis.
        timestamps = triggerRange.GetTimestamps()

        # Check, whether triggerRange contains any values
        if values.size > 0:
            # values.max() returns the maximum value within the current range. The global
            # maxValue is updated accordingly.
            maxInRange = values.max()
            maxValue = max(maxInRange, maxValue)

            # thresholdExceededMask is an new Boolean array that contains True wherever the
            # corresponding element in values exceeds the given threshold.
            thresholdExceededMask = values > threshold

            # Report FAILED, when threshold is exceeded at least once
            if thresholdExceededMask.any():
                triggerRange.SetResultFailed()
                triggerRange.SetResultText('Threshold exceeded. Maximum in range: {}.'.format(maxInRange))

            else:
                triggerRange.SetResultSuccess()

        else:
            triggerRange.SetResultText('No values in the given trigger range.')

        # The report shall contain contiguous sub-ranges, where the threshold is either
        # satisfied or exceeded. The method CalculateRanges() can be used to create such
        # sub-ranges from a Boolean mask.
        reportElements = {
            False: ('Check OK', report.RESULT_ID_SUCCESS),
            True: ('Check FAILED', report.RESULT_ID_FAILED),
        }

        for subRange in self.CalculateRanges(thresholdExceededMask):
            triggerRange.Range(
                timestamps[subRange[0]], timestamps[subRange[1]-1],
                reportElements[subRange[2]][0], reportElements[subRange[2]][1])

    # Write back the determined maximum value
    parameters['maxValue'] = maxValue

Nach dem Speichern der fertig editierten Python-Klasse ist die neu erstellte arraybasierte NumPy-Traceschrittvorlage im Reiter Traceschrittvorlagen des Aktionsfensters verfügbar. Da die Vorlage über einen Ausgabeparameter verfügt, muss vor ihrer Verwendung in der Traceanalyse eine Packagevariable angelegt werden, die später den ausgegebenen Wert entgegennimmt. Klicken Sie dazu im Reiter Variablen rechts und wählen Sie im erscheinenden Kontextmenu Neue Variable ‣ Numeric. Nennen Sie die neue Variable MaximumSpeed.

../../_images/Tutorial_CreateNewPackageVariable.png

Erstellen einer neuen Packagevariable

Kein Schreiben UND Lesen von Packagevariablen innerhalb einer Episode

Bei Packagevariablen ist zu beachten, dass auf diese in einer Episode, in welcher sie geschrieben werden, nicht lesend zugegriffen werden kann. Das Auslesen ist erst in der nächsten Episode möglich.

Fügen Sie anschließend die neu erstellte Vorlage CheckThreshold per Drag-and-drop aus dem Reiter Traceschrittvorlagen des Aktionsfensters in die Traceanalyse ein.

../../_images/Tutorial_ArrayBasedTraceStepTemplate_List.png

Die Traceschrittvorlage „CheckTreshold“ unter „Traceschrittvorlagen“ im Aktionsfenster

Nehmen Sie im daraufhin erscheinenden Dialog zur Parametrierung der Traceschrittvorlage die folgenden Eintragungen vor:

  • Binden Sie an das Eingangssignal Signal der Vorlage das generische Signal Signal0.

  • Legen Sie den Eingangsparameter threshold auf 75 fest.

  • Binden Sie an den Ausgangsparameter maxValue die eben erstellte Variable MaximumSpeed. Dazu können Sie in der entsprechenden Zelle Wert der Parametertabelle die Pfeiltaste nach unten auf der Tastatur drücken und die Variable aus der angezeigten Liste von Vorschlägen auswählen.

Der fertig ausgefüllte Dialog sollte wie folgt aussehen:

../../_images/Tutorial_ArrayBasedTraceStepTemplate_CheckThreshold_Parameterized.png

Parametrierung der Traceschrittvorlage

Fügen Sie nun noch einen Plot hinzu, in dem das Signal und die Ergebnisse des Traceschritts CheckThreshold visualisiert werden sollen. Klicken Sie dazu unter Episoden und Traceschritte am linken Rand des Traceanalyse-Editors auf die Schaltfläche Plot_Symbol (Neuer Plot) und übernehmen Sie die vorgeschlagenen Optionen per Klick auf OK.

Die fertige Analyse sollte wie folgt aussehen:

../../_images/Tutorial_ArrayBasedTraceStepTemplate_Ready.png

Fertige Traceanalyse

Nach Ausführen der Traceanalyse (durch Klick auf die im vorherigen Bild gekennzeichnete Schaltfläche links oben in der Toolbar des Traceanalyse-Editors) wird im Reiter Testreport das folgende Ergebnis angezeigt:

../../_images/Tutorial_ArrayBasedTraceStepTemplate_Report.png

Ergebnis der Traceanalyse

Dem Report sind die folgenden zentralen Analyseergebnisse zu entnehmen:

  1. Der Grenzwert von 75 km/h wurde nicht eingehalten. Die Traceanalyse liefert deshalb als Ergebnis FAILED.

  2. Die maximale Geschwindigkeit betrug 75,5 km/h.

  3. Die Grenzwertverletzung fand zwischen Messzeit 44,400800 und 44,450200 statt.

Weitere Informationen

Das Erstellen eigener Traceschrittvorlagen stellt einen wesentlichen Aspekt der Traceanalyse mit ecu.test dar. Eine Schritt-für-Schritt-Anleitung zum Erstellen von Traceschrittvorlagen befindet sich im Abschnitt Erstellen von Traceschrittvorlagen, der speziell für arraybasiere NumPy-Traceschrittvorlagen im Abschnitt Arraybasierte NumPy-Traceschrittvorlagen erstellen fortgeführt wird. Dort sind auch weitere Beispiele aufgeführt, die auf dieses Tutorial aufbauen.