Skip to main content

Ausdrücke

Bedingungen, Rückfallbedingungen, der ausschlaggebende Wert und die Platzhalter in Alarmtexten sind alle dieselbe Sprache, ausgewertet im selben Kontext. Alles, was eine Bedingung lesen kann, kann auch ein Text nennen.

Die Sprache ist CEL (Common Expression Language) — eine kleine, ausdrucksstarke Sprache für genau solche Bedingungen. Ein Ausdruck hat keinen Zugriff auf Uhrzeit, Netzwerk oder Datenbank; er sieht ausschließlich, was auf dieser Seite steht. Genau das macht es unbedenklich, Bedingungen von Benutzern schreiben zu lassen.


Die goldene Regel

Prüfen Sie vor jedem Aggregat, ob das Fenster Werte enthält.

values.size() > 0 && values.max() > props.level_max

Ein Aggregat über ein leeres Fenster ist ein Fehler, kein Nullwert — und ein Fehler bedeutet: der Lauf hat für dieses Objekt kein Ergebnis, weckt also nicht und klärt nicht. Ohne den vorangestellten values.size() > 0-Wächter hört eine Regel bei jedem Datenausfall stillschweigend auf zu arbeiten.

Das ist Absicht: ein Mittelwert über nichts hat keinen Wert, und stillschweigend 0 zu antworten würde ein leeres Fenster wie eine gemessene Null aussehen lassen — also genau die Lücke verdecken, die die Plattform bemerken soll.


Verfügbare Variablen

VariableTypInhalt
valuesListeDie Werte des Fensters, zeitlich aufsteigend. Für ungültig erklärte Punkte sind nicht enthalten
timesListe von ZeitpunktenDie Zeitstempel dazu, gleiche Länge und Reihenfolge wie values
window.fromZeitpunktBeginn des Fensters (gehört dazu)
window.toZeitpunktEnde des Fensters (gehört nicht dazu)
window.durationDauerLänge des Fensters
preceding.valueWertDer letzte Messwert vor dem Fenster. Fehlt, wenn im Rückblick keiner liegt
preceding.timeZeitpunktSein Zeitstempel
params.<x>beliebigKonstanten der Regel
props.<x>beliebigEffektive Eigenschaften des Signals, einschließlich geerbter
asset.props.<x>beliebigEigenschaften des Assets, an dem das Signal hängt
siblings.<name>.props.<x>beliebigEigenschaften eines Nachbarobjekts, über seinen Namen
signal.nameTextName des überwachten Signals
signal.unitTextSeine Einheit. Wird mitgeführt, aber nie geprüft oder umgerechnet

Drei Dinge, die man dazu wissen muss:

  • Ein leeres Feld ist nicht vorhanden. Eine Eigenschaft ohne Wert — auch ein leerer Text — erscheint nicht. has(props.x) antwortet dann falsch.
  • Zahlen sind Kommazahlen. Werte aus params, props und asset.props kommen als Kommazahl an, damit ein als 80 gepflegter Grenzwert sich sauber gegen jedes Aggregat vergleicht. Texte und Wahrheitswerte bleiben unverändert.
  • Nachbarobjekte tragen nur Eigenschaften, keine Messreihen. siblings gibt Zugriff auf Stammdaten, nicht auf die Werte eines zweiten Signals.
Ein fehlender Schlüssel ist ein Fehler

props.x an einem Objekt, das x nicht trägt, beendet den Lauf für dieses Objekt ohne Ergebnis — es wird nicht zu false. Wollen Sie einen fehlenden Wert behandeln, fragen Sie mit has(props.x) danach. Objekte, denen ein von der Regel gelesener Schlüssel vollständig fehlt, schließt die Regel von vornherein aus, siehe Welche Objekte überwacht werden.


Funktionen auf der Messreihe

Aufgerufen als Methode auf einer Liste, in der Regel auf values:

FunktionErgebnisBedeutung
values.size()GanzzahlAnzahl der Werte im Fenster
values.first()WertErster Wert des Fensters
values.last()WertLetzter Wert des Fensters
values.min()KommazahlKleinster Wert
values.max()KommazahlGrößter Wert
values.sum()KommazahlSumme
values.mean()KommazahlArithmetisches Mittel
values.median()KommazahlMedian
values.stddev()KommazahlEmpirische Standardabweichung (mit n-1)
values.mad()KommazahlMedian der absoluten Abweichungen vom Median — das ausreißerrobuste Streuungsmaß
values.range()KommazahlSpannweite, also Maximum minus Minimum
values.quantile(p)KommazahlQuantil, p zwischen 0 und 1, linear interpoliert
values.delta()KommazahlGrößter Betrag eines Sprungs zwischen zwei aufeinanderfolgenden Werten
delta()KommazahlDieselbe Funktion ohne Empfänger geschrieben
slope(dauer)KommazahlSteigung der Regressionsgeraden über das Fenster, in Signaleinheit je angegebener Dauer, z. B. slope(duration("1h"))
maxGap()DauerGrößter Abstand zweier aufeinanderfolgender Punkte, einschließlich der Ränder
x.abs()KommazahlBetrag einer Kommazahl, z. B. (values.last() - values.first()).abs()

maxGap() zählt die Ränder mit

Der linke Rand ist der letzte Punkt vor dem Fenster, der rechte das Fensterende. Damit erkennt die Funktion auch eine Lücke, die vor dem Fenster begonnen hat, und ein Signal, das innerhalb des Fensters verstummt ist. Gibt es keinen vorangehenden Punkt, ist der linke Rand der Fensterbeginn — über die Zeit davor ist nichts bekannt.

maxGap() ist die einzige dieser Funktionen, die ein leeres Fenster nicht als Fehler behandelt: ohne jeden Punkt ist die Lücke die ganze betrachtete Strecke, und das ist genau die Antwort, die eine Lückenerkennung braucht.

Wann eine Funktion mit einem Fehler endet

FallBetroffene Funktionen
Leeres FensterAlle Aggregate sowie first() und last() — nicht maxGap() und nicht size()
Weniger als zwei Wertestddev(), delta(), slope()
p außerhalb von 0 bis 1quantile(p)
Dauer nicht positivslope(dauer)
Alle Punkte auf demselben Zeitstempelslope(dauer)
Nicht-numerische Werte im FensterAlle rechnenden Aggregate. Ein Statussignal mit dem Wert "OK" hat keinen Mittelwert, und ihn zu erfinden würde auf Unsinn alarmieren

Jeder dieser Fälle beendet den Lauf für dieses Objekt ohne Ergebnis — er weckt nicht und klärt nicht.


Sprachmittel von CEL

Neben den obigen Funktionen stehen die Standardmittel von CEL zur Verfügung:

MittelBeispiel
Vergleiche und Rechnenvalues.max() > 80.0, values.mean() - props.offset
Logik&&, ||, !, Klammern
Bedingter Ausdruckhas(props.limit) ? props.limit : 100.0
Existenzprüfunghas(props.level_max)
Dauer aus Textduration("900s"), duration("15m")
Enthalten inprops.state in ["Betrieb", "Anfahren"]
Zeichenkettensignal.name.startsWith("Pegel"), .contains(...), .endsWith(...), .matches(...)
Listen-Makrosvalues.exists(v, v > 100.0), values.all(v, v > 0.0), values.filter(v, v > 80.0).size(), values.map(v, v * 2.0)

Die Makros exists, exists_one, all, filter und map sind absichtlich nicht durch eigene Funktionen ersetzt. Ihre Durchläufe sind auf die Punktgrenze des Fensters beschränkt, eine Schleife kann also nicht davonlaufen.

Was nicht verfügbar ist, meldet die Prüfung beim Speichern — probieren ist hier billiger als raten.


Was ein Ausdruck ergeben muss

FeldErwartetes Ergebnis
Ausdruck einer KritikalitätsstufeWahrheitswert. Eine Regel, deren Bedingung eine Zahl ergibt, lässt sich nicht speichern
RückfallbedingungWahrheitswert
Ausschlaggebender WertBeliebig — Zahl oder Text
Platzhalter im AlarmtextBeliebig; das Ergebnis wird als Text eingesetzt

Platzhalter in Texten

Zwischen {{ und }} steht ein gewöhnlicher Ausdruck:

Pegel {{ signal.name }} liegt bei {{ values.max() }} cm

Sie werden einmal beim Auslösen aufgelöst und mit dem Alarm gespeichert. Lässt sich einer nicht auswerten, bleibt er als geschriebener Text stehen — der Alarm entsteht trotzdem. Der ausschlaggebende Wert wird genauso formatiert wie in den Platzhaltern, damit derselbe Wert nicht an einer Stelle als 92 und an der anderen als 92.0 erscheint.


Grenzen

GrenzeWertBei Überschreitung
Punkte im Fenster50.000Der Lauf endet für dieses Objekt ohne Ergebnis. Verkleinern Sie das Fenster
Zeichen je Ausdruck4.000Die Regel lässt sich nicht speichern
Rechenzeit je Auswertung100 msDer Lauf endet für dieses Objekt ohne Ergebnis

Kleine Rezeptsammlung

AufgabeAusdruck
Grenzwert überschrittenvalues.size() > 0 && values.max() > props.level_max
Mittelwert über Grenzwertvalues.size() > 0 && values.mean() > props.motor_temp_max
Unterschreitungvalues.size() > 0 && values.min() < props.tank_level_min
Kein Wert oder große Lückevalues.size() == 0 || maxGap() > duration(params.max_gap)
Eingefrorenes Signalvalues.size() > 1 && values.range() < 0.01
Sprung zwischen zwei Wertenvalues.size() > 1 && values.delta() > props.max_step
Anhaltender Anstiegvalues.size() > 1 && slope(duration("1h")) > props.max_rise_per_hour
Ausreißer gegen robuste Streuungvalues.size() > 2 && (values.last() - values.median()).abs() > 3.0 * values.mad()
Grenzwert nur, wenn gepflegthas(props.level_max) && values.size() > 0 && values.max() > props.level_max
Nur im Betrieb prüfenasset.props.state == "Betrieb" && values.size() > 0 && values.max() > props.level_max

Vollständige Regeln mit Zeitplan, Entprellung und Texten stehen unter Beispiele und Fehlersuche.