Get started
Interactive: STL and robustness
Learn STL and quantitative robustness.
Signal Temporal Logic describes properties about what a signal should do over time, and it produces a robustness which is just a signed number about how well a trace satisfied that property. We'll look at how to actually calculate robustness given a signal and a handful of formulas.
The editor below runs SENTIL in Python, in your browser. Change the trace or the formula and press Run, then check the arithmetic against the worked numbers further down. The full playground lives at /playground.
The signal we will use
The signal is speed and we take five samples that are measured every second.
| 0 | 1 | 2 | 3 | 4 | |
|---|---|---|---|---|---|
speed | 12 | 9 | 7 | 4 | 6 |
import sentil
from sentil import Formula
trace = sentil.Trace([0, 1, 2, 3, 4], {"speed": [12, 9, 7, 4, 6]})
phi = Formula.parse("G (speed > 5)")
print(phi.robustness(trace)) # -1.0use sentil::{Formula, Trace};
let mut trace = Trace::new(vec![0.0, 1.0, 2.0, 3.0, 4.0])?;
trace.add_signal("speed", vec![12.0, 9.0, 7.0, 4.0, 6.0])?;
let phi = Formula::parse("G (speed > 5)")?;
println!("{}", phi.robustness(&trace)?);-1#include "sentil.h"
#include <stdio.h>
double times[] = {0.0, 1.0, 2.0, 3.0, 4.0};
double speed[] = {12.0, 9.0, 7.0, 4.0, 6.0};
sentil_trace_t *trace = sentil_trace_from_signal(times, 5, "speed", speed, 5);
sentil_formula_t *phi = sentil_formula_parse("G (speed > 5)");
double rho = 0.0;
sentil_formula_robustness(phi, trace, &rho);
printf("%.1f\n", rho);-1.0#include <sentil/sentil.hpp>
#include <iostream>
sentil::Trace trace({0, 1, 2, 3, 4}, "speed", {12.0, 9.0, 7.0, 4.0, 6.0});
sentil::Formula phi = sentil::Formula::parse("G (speed > 5)");
std::cout << phi.robustness(trace) << "\n";-1import io.github.sedislab.sentil.Formula;
import io.github.sedislab.sentil.Trace;
try (Trace trace = Trace.create(new double[] {0, 1, 2, 3, 4});
Formula phi = Formula.parse("G (speed > 5)")) {
trace.addSignal("speed", new double[] {12, 9, 7, 4, 6});
System.out.println(phi.robustness(trace));
}-1.0using Sentil
phi = formula("G (speed > 5)")
trace = Trace(collect(0.0:1.0:4.0), "speed", [12.0, 9.0, 7.0, 4.0, 6.0])
println(robustness(phi, trace))-1.0trace = sentil.Trace([0 1 2 3 4], 'speed', [12 9 7 4 6]);
phi = sentil.Formula.parse('G (speed > 5)');
fprintf('%g\n', phi.robustness(trace));-1sentil check -f 'G (speed > 5)' -t speed.csv --semantics discretecheck
formula G (speed > 5)
trace speed.csv
semantics discrete
verdict violated
robustness -1.000000Change the formula string and rerun. Every result below comes from that same trace.
Predicates
The smallest formula compares a term against a constant. Its robustness is the signed distance to the boundary: f(x) - c for > and >=, and c - f(x) for < and <=.
Take speed > 5 at . The signal reads 12, so robustness is . The property holds with seven units to spare. Now take speed < 10 at . That scores , a violation, because the signal starts two units above the ceiling.
Evaluated across the whole trace, speed > 5 produces a robustness signal, one value per sample:
| 0 | 1 | 2 | 3 | 4 | |
|---|---|---|---|---|---|
speed - 5 | 7 | 4 | 2 | -1 | 1 |
The dip to at is the only violation.
Boolean connectives
Once we solve for the predicates and get a number, the boolean operators then work on numbers. Conjunction takes the minimum, disjunction the maximum, negation flips the sign, and implication, phi -> psi, is max(-rho_phi, rho_psi).
Conjunction is the minimum because a formula is only as satisfied as its weakest part. Consider (speed > 5) & (speed < 10) at . The first conjunct scores , the second , and the minimum is . The conjunction fails, and it fails by the amount the ceiling is breached.
G is the worst case over a window
G[a, b] phi, read always, says phi holds at every point from to . Its robustness is the infimum of the inner robustness over that window.
Unbounded, G (speed > 5) takes the infimum of , which is at . That sets the verdict for the whole trace. If we relax the threshold, the worst case improves. G (speed > 3) scores and its infimum is : the property holds, with the tightest moment again at where the margin is one.
Bound the window and only the samples inside it count. G[0, 2] (speed > 5) at looks at , the values , and reports . The violation at sits outside the window, so within the first two seconds the property holds comfortably. The same G[0, 2] (speed > 5) at looks at , the values , and reports . In this case, the violation is part of the considered values so it doesn't hold.
Exercise
The window moves with the evaluation time. What does G[1, 2] (speed > 5) score at t = 3?
F is the best case over a window
F[a, b] phi, read eventually says phi holds at some point from to . Its robustness is the supremum of the inner robustness over that window.
F (speed > 10) scores the predicate speed - 10 across the trace, , and takes the supremum, at . The speed climbs above ten at exactly one instant, and that one instant is enough to satisfy an F.
Exercise
The unbounded F (speed > 10) scored 2. What does F[1, 2] (speed > 10) score at t = 0?
Until
U, read until, is the one binary temporal operator. phi1 U[a, b] phi2 wants a witness time where phi2 holds, with phi1 maintained the whole way there.
Read (speed > 5) U (speed < 8) at . The first predicate scores and the second, 8 - speed, scores . The best witness is : there speed < 8 holds with margin , and speed > 5 held with margin at least over , so the witness contributes . Later witnesses look tempting on speed < 8 alone, but by the speed has already broken the speed > 5 guard, which caps their contribution at . The supremum over all witnesses is , so the property holds.
Exercise
Your turn to write one. Over the first two seconds the speed never reaches 10. Write that as a formula.
Where to go next
The exact recursive definition for every operator, including the past-time forms and dense-time interpolation, is on the robustness semantics and temporal operators pages. To run these formulas against your own data instead of a fixed table, follow your first monitor. When you are ready for signals under sensor noise, the sign of the number gives way to a probability in the PrSTL lesson.
Robustness semantics
The full quantitative semantics for boolean, temporal, and probabilistic operators.
Temporal operators
Every operator walked through with worked examples, including the past-time forms.
Your first monitor
Install SENTIL and run these formulas on a trace of your own in about five minutes.
PrSTL and probability
Add sensor noise and the sign of the number becomes a satisfaction probability.