7.6 Semantics
This chapter describes the behavioral semantics of scenarios, scenario modifiers, and actions of ASAM OpenSCENARIO. ASAM OpenSCENARIO is a declarative and constraint-based language where a scenario model may not only define one concrete behavior, but a whole family of behaviors, with different possible values for parameters such as vehicle speeds, scenario durations, or environmental conditions. Therefore, the semantics definition of ASAM OpenSCENARIO is also of a declarative nature and based on the notion of trace acceptance as explained in Section 7.6.1, “Semantic foundations”.
This standard does not provide any operational semantics, which means that it does not define how to choose the next step in the execution of an ASAM OpenSCENARIO model based on a given trace prefix. Any operational semantics is valid as long as, given an ASAM OpenSCENARIO model, it produces traces that are accepted by that model according to the declarative semantics. One reason for this standard not to provide any operational semantics is that different use cases may require different operational semantics. In some cases, it may be sufficient to produce only one particular trace of the possible traces described by a given ASAM OpenSCENARIO model. In other cases, it may be desired to produce a representative variety of the possible traces or to choose traces in a way that quickly reaches some coverage goal.
This section is structured as follows:
-
The semantic foundations contain some preliminary definitions (see Section 7.6.1, “Semantic foundations”).
-
The following sections cover the semantics aspects of language concepts related to scenarios and actions (see Section 7.6.2, “Scenarios” and Section 7.6.3, “Actions”).
7.6.1 Semantic foundations
A trace is a timed behavior occurring in a traffic system, or a model thereof, such as a simulation. An ASAM OpenSCENARIO 2.0 model (or scenario model in short) consists of a tree of composed scenarios and actions that specify a set of traces that it accepts. All other traces are rejected.
Figure 4 shows a set of traces accepted by an ASAM OpenSCENARIO model as a tube. The traces are single threads. The traces are accepted if they are enclosed in the tube. Traces not enclosed in the tube are rejected.
Trace acceptance is not related to passing or failing tests. If an ASAM OpenSCENARIO model does not accept a trace, it means that the behavior is outside the scope of the ASAM OpenSCENARIO model. Test criteria can only be evaluated for accepted traces, meaning, if the behaviors are within the scope of the ASAM OpenSCENARIO model.
An ASAM OpenSCENARIO model is inconsistent if the set of traces that it accepts is empty. This can happen because of contradictions in constraints. For example, requiring a car to drive faster than 50 km/h and slower than 50 km/h at the same time. In a test setting, it can also happen that a vehicle under test causes a trace to be rejected. That is, because the vehicle under test is uncontrollable from the perspective of the test system, it may force the traffic system into a state that violates constraints of the ASAM OpenSCENARIO model. Moreover, the satisfiability of an ASAM OpenSCENARIO model also depends on particular driver models and physics models that are combined with the ASAM OpenSCENARIO model and influence how the traffic system objects behave.
The following chapters contain more precise definitions of some key concepts.
7.6.1.1 Actor system
An ASAM OpenSCENARIO model defines a possible system of actor objects, which can be vehicles, other moving objects, or also static or virtual objects. This set of actor objects is called the actor system or traffic system. Each actor object has a set of fields as defined by its type definition. A field has a type that specifies a domain of possible values. Domains can be discrete (such as int or enum values) or continuous (real-valued, such as speed or acceleration). Domains can also be compound types (see Section 7.3.5, "Compound types"), such as structs or actor types.
7.6.1.2 State
The state of an actor system is an actor system with a valuation of the actor objects' fields. A valuation is a mapping for each field to a value from the domain defined by the field’s type.
\(\theta(o, \rho, t) = v\) is the valuation of the field \(\rho\) of the actor object \(o\) at time \(t\).
7.6.1.3 Trace
A trace \(\pi\) is a continuous-time sequence of actor system states. \(\pi(t)\) identifies the actor system state at time \(t\), where \(t\) is a real number, meaning that \(\pi\) is a function \(\pi: \mathbb{R}_{\geq 0} \rightarrow S\) where \(S\) is the set of states. Traces can have arbitrary lengths but are always finite.
All states in a trace share the same actor system and only the valuations of their fields change over time.
Notation:
-
\(\pi[t_a,t_b]\) is the subtrace of a trace \(\pi\) from the closed interval starting at time \(t_a\) and ending at time \(t_b\), that is, including the states at \(t_a\) and \(t_b\).
7.6.1.4 Behavior invocation tree
An ASAM OpenSCENARIO model has one main scenario that can invoke one or more other behaviors (a behavior being either a scenario or an action). Each invoked scenario has a scenario type that defines how, again, that scenario invokes other behaviors. Actions are atomic behaviors, meaning that they are not composed of other behaviors (from the perspective of an ASAM OpenSCENARIO model). The scenario invocation relationships give rise to a behavior invocation tree that is defined by the ASAM OpenSCENARIO model, where the root is the main scenario, the leaves are action invocations, and intermediate nodes are scenario invocations.
7.6.1.5 Behaviors versus behavior invocations
The concepts scenario and scenario invocation relate as follows:
-
A scenario (also scenario type or scenario declaration) describes a set of possible behaviors (traces) involving some set of actor objects in some actor systems.
-
A scenario invocation happens when a scenario refers to another scenario as part of its behavior definition.
When invoking a scenario, the invoking (parent) scenario may specify additional constraints, especially for which actor objects the invoked (child) scenario must apply, by constraining how fields of the invoked scenario may bind to actor objects in an actor system.
Moreover, the invoking scenario may specify at what time and for which duration the invoked scenario shall apply.
For example, a scenario defining a certain choreography of vehicle movements may invoke an overtaking
scenario and specify which vehicle shall overtake which other vehicle, possibly also constraining the time and duration of this maneuver, the speeds of the vehicles, and so on.
Therefore, semantically, a scenario invocation describes a subset of the possible behaviors described by its scenario type; especially a scenario invocation refines when these behaviors shall occur.
Figure 5 shows how the set of traces accepted by a scenario \(Sc_0\) is a subset of the composition of the traces accepted by the scenario invocations \(sc_1:Sc_1\) and \(sc_2:Sc_2\). The traces accepted by the scenario invocations \(sc_1:Sc_1\) and \(sc_2:Sc_2\) are themselves subsets of the traces accepted by their type scenarios \(Sc_1\) and \(Sc_2\), reduced by constraints specified in the invoking scenario \(Sc_0\).
The terminology of scenario and scenario invocation also maps to actions: actions and action invocations are distinguished in the same way as scenarios and scenario invocations, except that actions cannot invoke any other scenarios or actions, because actions are atomic. As scenarios and actions are behaviors, we also call scenario invocations and action invocations more generally behavior invocations.
7.6.1.6 Accepting a trace
An ASAM OpenSCENARIO model only accepts a trace if its main scenario also accepts the trace. A trace is an element of the possible behaviors described by its main scenario. This depends on, for example, whether the time and value constraints formulated by the scenario are satisfied by the trace and whether, recursively, all behavior invocations accept subtraces of the given trace.
The next sections contain a more detailed definition of the different conditions for when a scenario accepts a given trace.
7.6.2 Scenarios
A scenario describes the behavior of one or several actors in a traffic system. This chapter is divided into the following parts:
Each section adds necessary conditions for trace acceptance.
For more information about scenarios in the context of ASAM OpenSCENARIO, refer to the Scenario definition.
7.6.2.1 Composition operators
A scenario invokes one or more behaviors (scenarios or actions) or directives using three composition operators.
-
serial
: The serial (sequential) composition of scenarios -
parallel
: The parallel composition of scenarios -
one_of
: The one-of composition of scenarios (at least one of a set of scenarios must hold)
In addition, a scenario can invoke a single scenario, action, or directive directly in the do
section.
In the following subsections, the semantics of these three composition operators are defined. The subsections also contain the semantics of the direct invocation.
The semantics is expressed in terms of conditions for trace acceptance. For compositionality reasons, a definition of when a scenario accepts the following elements is required:
-
A given trace \(\pi[t_{start},t_{end})\)
-
A trace over a right-open time interval between the following times:
-
A start time \(t_{start}\)
-
An end time \(t_{end}\)
-
For formal definitions, the left-pointing triangle symbol \(\triangleleft\) is introduced. This triangle symbol indicates that a scenario invokes another scenario or a composition of other scenarios. For example, \(Sc_0 \triangleleft b_1:B_1\) means that scenario \(Sc_0\) specifies a direct invocation \(b_1\) of the behavior (type) \(B_1\); \(Sc_0 \triangleleft \texttt{serial}(b_1:B_1, b_2:B_2)\) means that scenario \(Sc_0\) specifies a serial composition of the behavior invocations \(b_1:B_1\) and \(b_2:B_2\).
In the following subsections, trace acceptance is defined for behaviors that are non-zero time. That means that zero-time behaviors, for example, emit directives (that emit events), are excluded from the trace acceptance conditions defined in the following subsections. However, the zero-time directives influence trace acceptance in other ways, and this is defined in their particular subsection in this chapter, see for example Section 7.6.2.5.2, “Emit (event)”.
7.6.2.1.1 Direct invocation
A scenario can invoke a single scenario or action directly in the do
section.
The invocation can express specific required values or ranges of values for any of the scenario parameters. Details are shown in Code 43:
scenario vehicle.accelerate:
target_speed: speed
do drive(duration: [2s..4s]) with:
speed(speed: target_speed, at: end)
Here, the action drive()
of the parent actor of this scenario is invoked with a speed modifier.
The parameter duration
of the drive
scenario is required to be between 2 and 4 seconds.
The speed
modifier specifies a target speed to be reached at the end of the execution of the drive action invocation (which also is the end of this scenario).
A scenario \(Sc_0 \triangleleft b_1:B_1\) (\(Sc_0\) specifies a direct scenario invocation \(b_1:B_1\)) accepts a trace \(\pi[t_a,t_b)\) only if \(b_1:B_1\) accepts \(\pi[t_a,t_b)\).
7.6.2.1.2 Serial composition
A scenario can invoke a series of two or more behaviors. Code 44 shows a scenario \(\texttt{two_phases}\) that specifies two driving phases of a vehicle:
-
The first phase (phase1) starts with the vehicle at a standstill (speed = 0 kph) and ends with the vehicle’s speed at 10 kph.
-
The second phase (phase2) starts, where the vehicle is driving with a speed between 10 and 15 kph. The duration of this series of behavior invocations must be between 10 and 30 seconds.
scenario vehicle.two_phases:
do serial (duration: [10s..30s]):
phase1: drive() with:
speed(speed: 0kph, at: start)
speed(speed: 10kph, at: end)
phase2: drive() with:
speed(speed: [10kph..15kph])
Code 44 contains no constraints on the duration of the two invoked behaviors. This means, that this scenario accepts any trace as long as the trace fulfills the following conditions:
-
The trace must be between 10 and 30 seconds long.
-
The trace must describe the behavior of a vehicle.
-
The vehicle starts at a standstill (phase1).
-
At some point the vehicle reaches 10 kph.
-
Then the vehicle continues driving at a speed between 10 and 15 kph (phase2).
Note that during the first phase, the acceleration does not need to be monotonic.
The acceleration may even include values higher than 10 kph and lower than 0 kph, as long as a speed of 10 kph is reached at least once, so that phase1
and phase2
can happen within 10 to 30 seconds.
More formally, a scenario that specifies a serial composition of \(n\) behavior invocations accepts a trace only if it is possible to partition the trace into \(n\) segments such that the \(i\)th scenario invocation accepts the \(i\)th segment. If a serial composition also specifies an optional minimum and maximum time duration, the trace duration must be within the specified range.
For a more concise formal definition, an alternative notation of the minimum and maximum duration parameters is introduced:
-
\(\Delta_{min}\): Minimum duration (default is \(0\))
-
\(\Delta_{max}\): Maximum duration (default is \(\infty\))
A scenario \(Sc \triangleleft \texttt{serial}[\Delta_{min}, \Delta_{max}](b_1 : B_1, .., b_n : B_n)\) accepts a trace \(\pi[t_0,t_n)\) only if
-
\(\Delta_{min} \leq (t_n - t_0) \leq \Delta_{max}\) and
-
there exist times \(t_1, ... , t_{n-1}\) with \(t_0 < t_1 < \ldots < t_{n-1} < t_n\) such that behavior invocation \(b_i:B_i\) accepts \(\pi[t_{i-1},t_{i})\) for all \(i \in 1, .., n\).
For Code 44 this means that a trace \(\pi[t_0,t_n)\) is accepted by this example scenario only if
\(\pi[t_0,t_n)\) can be divided into two subtraces \(\pi[t_0,t'), \pi[t',t_n)\) (one for each of the invocations phase1
and phase2
) such that
-
phase1
accepts \(\pi[t_0,t')\): at time \(t_0\) the speed of the actor is 0 kph and at the time \(t'\) the speed is 10 kph (in between it may have any speed, even grater than 10 kph or less than 0 kph). -
phase2
accepts \(\pi[t',t_n)\): the speed of the actor does not exceed the boundaries of 10 and 15 kph during \([t',t_n)\). -
The difference between \(t_n\) and \(t_0\) is greater or equal to 10 seconds or less than or equal to 30 seconds.
7.6.2.1.3 One-of composition
The one-of composition operator models the alternative occurrence of one scenario from a set of two or more scenarios.
In the following example it is specified for a vehicle to either stay on lane 0 and decrease speed from 100 kph to 0 kph or to change lane from 0 to 1 and keep the speed within 60 to 100 kph. This way a vehicle either brakes on lane 0, for example, because of an obstacle, or changes the lane to avoid the obstacle and keeps on driving. The duration constraint expresses that either scenario must happen within 10 to 30 seconds.
scenario vehicle.one_of:
do one_of(duration : [10s..30s]):
phase_a: drive() with:
speed(speed: 100kph, at: start)
speed(speed: 0kph, at: end)
lane(0)
phase_b: drive() with:
speed(speed: [60kph..100kph])
lane(0, at: start)
lane(1, at: end)
More formally, a scenario \(Sc \triangleleft \texttt{one\_of}[\Delta_{min}, \Delta_{max}](b_1:B_1, ... ,b_n:B_n)\) accepts a trace \(\pi[t,t')\) only if
-
\(\Delta_{min} \leq (t' - t) \leq \Delta_{max}\) and
-
at least one behavior invocation \(b_i:B_i\), \(i \in 0, ..., n\) accepts \(\pi[t,t')\).
7.6.2.1.4 Parallel composition
The parallel composition operator models the parallel or otherwise overlapping occurrence of two or more scenarios. The operator takes a list of two or more behavior invocations. The first one is called the primary behavior invocation and the others are called secondary behavior invocations. The operator furthermore accepts four parameters:
-
overlap
: Specifies an overlap kind, which can beequal
,start
,end
,initial
,final
,inside
,full
, andany
. Default isstart
. -
start_to_start
: Specifies the allowed offset between the start of the primary behavior invocation and the starts of the secondary behavior invocations. This parameter is optional. -
end_to_end
: Specifies the allowed offset between the end of the primary behavior invocation and the ends of the secondary behavior invocations. This parameter is optional. -
duration
: Specifies the overall duration of the parallel behavior invocations, from the first start of an invoked behavior until the last end of an invoked behavior. This parameter is optional.
The following listing shows an example of the parallel operator.
scenario parallel_phases:
v1, v2: vehicle
do parallel():
phaseA: v1.drive() with:
speed(speed: 0kph, at: start)
speed(speed: 10kph, at: end)
phaseB: v2.drive() with:
speed(speed: [10kph..15kph])
position(distance: [5m..100m], behind: v1, at: start)
Here, phaseA
specifies that actor v1
accelerates from 0 kph to 10 kph.
In parallel, phaseB
specifies that another actor v2
is driving with a speed between 10 and 15 kph.
At the start of the scenario, v2
should be 5 to 100 meters behind v1
.
parallel()
is used here without any parameters.
This means that the overlap kind defaults to start
and both phases must start at the same time but may end at different times.
More details on the available parameters can be found in the next subsection.
Overlap parameter semantics
If a scenario invokes a number of behaviors using the parallel operator with parallel(equal)
, it means that all invoked behaviors start and end at the same time, meaning a true parallel occurrence of the invoked behaviors.
The other overlap kinds are less strict.
The overlap kind start
, which is the default if no other overlap kind is specified, requires that all invoked behaviors start at the same time, but can end at different times.
The converse holds for the overlap kind end
: The end times must be equal, but start times can be different.
The overlap kinds initial
and final
require that the secondary behavior invocations cover the start, or the end, of the primary behavior invocation.
Figure 6 illustrates which parallel or overlapping occurrences of the primary behavior invocation and the secondary behavior invocations are allowed with the overlap kinds equal
, start
, end
, initial
, and final
.
The overlap kind inside
requires that the secondary behavior invocations are fully overlapped by the primary behavior invocation.
full
, by contrast, requires that all secondary behavior invocations are fully overlapped by the primary behavior invocation.
The overlap kind any
places no requirement on the overlapping of the invoked scenarios except that there must exist at least one point in time where all scenarios overlap.
Figure 7 illustrates the overlappings allowed by inside
, full
, and any
.
Values for offset and duration parameters
The start_to_start
and end_to_end
parameters specify what time offsets are allowed from the start time of the primary behavior invocation to the start time of each secondary behavior invocation.
The values for these parameters can be a range of times (like start_to_start: [-5s..3s]
) or a single positive or negative time value (like start_to_start: -5s
).
A positive offset means that the secondary behavior invocations start after the primary behavior invocations and negative offsets mean that the secondary behavior invocations start before the primary behavior invocation.
Figure 8 illustrates different cases of start_to_start
values.
The end_to_end
constraint works in the same way for end times.
More formally, the semantics of the parallel operator is as follows. For a more concise formal definition, an alternative notation of the parameters is introduced:
-
\(\Delta_{min}\): Minimum duration (default is \(0\))
-
\(\Delta_{max}\): Maximum duration (default is \(\infty\))
-
\(\Delta_{start-min}\): Minimum difference between the start of the primary behavior invocation and the start of each secondary behavior invocation (default is \(-\infty\))
-
\(\Delta_{start-max}\): Maximum time difference between the start of the primary behavior invocation and the start of each secondary behavior invocation (default is \(\infty\))
-
\(\Delta_{end-min}\): Minimum time difference between the end of the primary behavior invocation and the end of each secondary behavior invocation (default is \(-\infty\))
-
\(\Delta_{end-max}\): Maximum time difference between the end of the primary behavior invocation and the end of each secondary behavior invocation (default is \(\infty\))
-
\(\chi\): Overlap kind
A scenario \(Sc \triangleleft \texttt{parallel}[\Delta_{min}, \Delta_{max}, \chi, \Delta_{start-min}, \Delta_{start-max}, \Delta_{end-min}, \Delta_{end-max}](b_0:B_0, .., b_n:B_n)\) accepts a trace \(\pi[t, t')\) only if for all \(i \in [0..n]\) there exist times \(t^{b_i}_{start}\) and \(t^{b_i}_{end}\) such that
-
\(\Delta_{min} \leq t' - t \leq \Delta_{max}\), meaning the duration of \(\pi[t, t')\) is between \(\Delta_{min}\) and \(\Delta_{max}\).
-
\(t \leq t^{b_i}_{start} < t^{b_i}_{end} \leq t'\), meaning the time stamps \(t^{b_i}_{start}\) and \(t^{b_i}_{end}\) mark time intervals between \(t\) and \(t'\).
-
\(b_i\) accepts \(\pi[t^{b_i}_{start}, t^{b_i}_{end})\), meaning each parallel behavior invocation accepts a subtrace of \(\pi[t, t')\) where \(t^{b_i}_{start}\) and \(t^{b_i}_{end}\) mark the beginnings, respectively, the ends of the subtrace.
-
\(\forall j \in [1..n]\) it holds that all start and end times of the secondary behavior invocations respect the start_to_start and end_to_end offsets relative to the primary scenario:
-
\(t^{b_j}_{start} - t^{b_0}_{start}\geq \Delta_{start-min}\)
-
\(t^{b_j}_{start} - t^{b_0}_{start}\leq \Delta_{start-max}\)
-
\(t^{b_j}_{end} - t^{b_0}_{end}\geq \Delta_{end-min}\)
-
\(t^{b_j}_{end} - t^{b_0}_{end}\leq \Delta_{end-max}\)
-
-
There exists a time \(t_{\bowtie}\) such that \(t^{b_i}_{start} \leq t_{\bowtie}\) and \({\bowtie} \leq t^{b_i}_{end}\), meaning there exists a point in time where all parallel behavior invocations overlap.
-
There exists a \(j\) with \(t^{b_j}_{start} = t\), meaning one of the parallel behavior invocations accepts a subtrace of \(\pi[t, t')\) starting at time \(t\). Or, in other words, there is no time at the beginning of the trace that is not covered by any of the parallel behavior invocations.
-
There exists a \(k\) with \(t^{b_k}_{end} = t'\), meaning one of the parallel scenarios accepts a subtrace of \(\pi[t, t')\) ending at time \(t'\). Or, in other words, there is no time at the end of the trace that is not covered by any of the parallel behavior invocations.
-
If \(\chi = \texttt{equal}\) then it holds that \(t^{b_i}_{start} = t\) and \(t^{b_i}_{end} = t'\). This is equivalent to saying that \(\pi[t, t')\) is accepted by \(b_i\) (\(\forall i \in [0..n]\)), meaning the trace satisfies all parallel behavior invocations.
-
If \(\chi = \texttt{start}\) then \(t^{b_i}_{start} = t\). That is, all behavior invocations accept some subtrace of \(\pi[t, t')\) starting at \(t\).
-
If \(\chi = \texttt{end}\) then \(t^{Sc_i}_{end} = t'\). That is, all behavior invocations accept some subtrace of \(\pi[t, t')\) ending at \(t'\).
-
If \(\chi = \texttt{inside}\) then \(\forall j \in [1..n]\) it holds that \(t^{b_0}_{start} \leq t^{b_j}_{start}\) and \(t^{b_0}_{end} \geq t^{b_j}_{end}\).
-
If \(\chi = \texttt{full}\) then \(\forall j \in [1..n]\) it holds that \(t^{b_0}_{start} \geq t^{b_j}_{start}\) and \(t^{b_0}_{end} \leq t^{b_j}_{end}\).
-
If \(\chi = \texttt{initial}\) then \(\forall j \in [1..n]\) it holds that \(t^{b_j}_{start} \leq t^{b_0}_{start} \leq t^{b_j}_{end}\).
-
If \(\chi = \texttt{final}\) then \(\forall j \in [1..n]\) it holds that \(t^{b_j}_{start} \leq t^{b_0}_{end} \leq t^{Sc_j}_{end}\).
7.6.2.2 Scenario fields and bindings
To decide whether a scenario accepts a trace, the following relation is needed: The scenario and its fields have to be related to objects in the states of the given trace. For a scenario to accept a trace, there must exist bindings of object-typed fields of the scenario to objects in the states of the trace. This section defines the concept and necessary conditions for scenario field bindings in more detail.
A system state \(\pi(t)\) of a trace \(\pi\) at time \(t\) consists of a set of actor objects. An ASAM OpenSCENARIO model defines actor types for these objects that appear in the system states. In addition, an ASAM OpenSCENARIO model defines types like scenarios or scenario modifiers that do not represent actor objects, but are concepts within the ASAM OpenSCENARIO model to describe the behavior of actor objects. These types are called scenario model types.
Scenarios have fields that can be typed by actor object types and scenario model types. Moreover, scenario fields can be parameters or variables. In order for a scenario to accept a trace, there must exist bindings from scenario parameters typed by actor object types to corresponding system objects that remain unchanged during the lifetime of a scenario.
More formally, a scenario \(Sc\) with actor object type parameters \(P^{sys} = p^{sys}_1, ..., p^{sys}_n\) accepts a trace \(\pi[t_a, t_b)\) only if there exists a binding of actor object type parameters \(b^{sys}_{Sc} : P^{sys} \rightarrow O\), which is a function that is total, non-injective, non-surjective, from the actor type scenario parameters \(P^{sys}\) to actor objects \(O\) that are shared by all system states \(\pi(t)\) where \(t \in [t_a, t_b)\). That is, the binding does not change over time \([t_a, t_b)\) and also actor objects do not disappear over time \([t_a, t_b)\).
In a composite scenario (see Section 7.6.2.1, “Composition operators”), the invoking scenario can specify constraints, specific values, or ranges of specific values for the parameters of the invoked scenarios. In addition to the conditions given in composition operators, an invoked scenario accepts a (sub-)trace only if there exists an instance of the invoked scenario that respects the constraints imposed by the invoking (parent) scenario for that trace.
Figure 9 shows the concept of scenario instances and parameter bindings.
The parameter bindings of a scenario to actor objects and values of a trace that it accepts is called a scenario instance of that scenario.
The behavior invocation relationships (compare Section 7.6.1.4, “Behavior invocation tree”) at a certain time of a given trace can imply a tree of scenario instances.
These scenario instances comprise a scenario state (middle of the figure) that corresponds to a system state (bottom of the figure).
The top of the figure shows parts of an ASAM OpenSCENARIO model that describes an overtaking scenario involving two cars.
Indeed, two cars exist in the system state shown at the bottom.
The extension of the main scenario specifies two parameters of the actor type Car
and invokes the scenario Car.overtake
with these cars: Car c1
is specified as the overtaking car and the main actor of the Car.overtake
scenario and car c2
is specified as the overtaken car.
This leads to a configuration of scenario instances with bindings from actor type parameters to actor objects: First, there is an instance of the main scenario top.main
, where the parameters c1
and c2
bind to carA
and carB
.
The main scenario constrains the invocation Car.overtake
in a way that the implicit main parameter it
must be equal to the value bound to top.main.c1
, namely carA
, and the parameter overtaken_car
must be equal to the value bound to top.main.c2
, namely carB
.
The invocation of Car.overtake
by the extension of top.main
does not constrain the value of the overtaken_lane
parameter.
Thus, an arbitrary binding for this parameter to a lane instance can be chosen.
The scenario car.overtake
probably has an additional constraint to ensure a meaningful binding for the parameter.
But this constraint is not shown in the figure.
The invocation of Car.overtake
by the extension of top.main
causes the parameter overtake1
to be bound to the instance of the scenario Car.overtake
here labeled ot1:Car.overtake
.
7.6.2.3 Scenario constraints
The structure and functionality of constraints are already described in Section 7.3.11, "Constraints".
In those sections also time aspects and strengths of constraints are specified. This chapter defines how constraints influence trace acceptance within the declarative semantic of ASAM OpenSCENARIO.
The core part of constraints are Boolean expressions which state limitations for the values of parameter fields inside instances of structured types (struct, scenario, actor, or modifier). By default, those limitations are applied as long as the instance in which they are declared exists. (A scenario can exist for a certain time, see also scenario instance in Section 7.6.2.2, “Scenario fields and bindings”). During the lifetime of an instance of a structured type, all constrained parameter fields must be bound to values satisfying the constraints at each point in time. Furthermore, there are special constraints that can be specified to hold at certain points in time, using the keyword at.
If a (parent) scenario (type) \(Sc_P\) defines a scenario invocation \(sc:Sc\) (of type \(Sc\)), there are three different kinds of constraints to consider:
-
The constraints specified by the type of the invoked scenario \(Sc\), denoted as \(C_{Sc}\)
-
The constraints specified by the parent scenario \(Sc_P\) in the scenario invocation using modifiers, denoted as \(C_{sc:Sc}\)
-
Other constraints specified by the parent scenario \(Sc_P\), denoted as \(C_{ScP}\)
If a (parent) scenario \(Sc_P\) invokes another scenario \(sc:Sc\), all three sets of constraints \(C_{Sc}\), \(C_{sc:Sc}\), and \(C_{ScP}\) must hold for the lifetime of \(sc:Sc\), which is the time that the invocation \(sc:Sc\) is active. Figure 5 compares the three sets of constraints.
A scenario invocation \(sc:Sc\) accepts a trace only if it satisfies the constraints \(C_{Sc}\) and \(C_{sc:Sc}\), this means that there exists a binding for scenario fields to values and actor objects in the actor system, such that these constraints are satisfied. In addition, the trace is only accepted if all constraints of all objects in the traffic system are satisfied in all states of the trace.
A trace can be rejected in the following cases:
-
Contradictions between constraints:
There can be contradicting constraints for example ifkeep(speed>10kph)
andkeep(speed<10kph)
are defined within the same vehicle actor. Such constraints can also conflict if they are placed on the same actor instance from within different scenarios that can be active in parallel. Such cases may be less obvious. Moreover, there can be a complex interplay between constraints. For example, imagine a vehicle is constrained to a certain minimum distance to a preceding vehicle, while the preceding vehicle has some constraints forcing it to accelerate. Then the following vehicle may be forced to violate constraints on the maximum speed. -
Impossible constraints because of other behavior restrictions:
For example, there can be constraint conflicts between scenario constraints and constraints implied by atomic actions that are invoked directly or indirectly from that scenario. Trace acceptance conditions defined for atomic actions may contradict constraints in scenarios invoking these actions. Refer to the definition of the semantics of action, for example, Section 8.8, "Movement actions".) There can also be conflicts with specific behavior models, such as driver models.
7.6.2.4 Time constraints
Time constraints may occur in the context of the following language constructs:
-
Composition Operators
When composing different behaviors by using composition operators like serial or parallel the duration of the composed behaviors can be restricted by using the "duration" parameter. For semantic details, refer to Section 7.6.2.1, “Composition operators”. -
Action Invocations
When invoking actions from the domain model specification (like drive or changeLane) the duration of that action may be restricted by using the parameter "duration". -
Wait directives
Thewait
directive may be used to introduce phases with a certain time duration into a scenario where it is not further constrained what happens during that duration. Note that this directive may also be invoked using the specification of an event to wait for. The semantics of that directive is described in Section 7.6.2.5, “Events”.
7.6.2.4.1 Action invocation using duration parameter
The duration parameter may be constrained when invoking an action. It adds a restriction to the set of accepted traces regarding the time duration of the respective action.
Formally, \(\pi(t, t')\) is accepted by the action \(drive (duration: [dur^-..dur^+\))] if
-
\(t' - t \geq dur^-\), and
-
\(t' - t \leq dur^+\)
This is an example where the action drive
is constrained via the duration
parameter to take between 30 and 60 seconds.
+
...
do:
car1.drive(duration: [30s..60s])
7.6.2.4.2 Wait directive
The wait directive when used with an elapsed()
expression adds a phase of the given duration to the scenario and it is not further specified what is allowed or intended to happen during this time.
Hence, formally in this 'intended specification gap' anything is allowed to happen.
It only needs to be assured that the (sub-)trace corresponds to the specified waiting time, meaning that the (sub-)trace has the correct length.
Formally, \(\pi(t, t')\) is accepted by the wait directive \(wait elapsed([dur^-..dur^+\))] if
-
\(t' - t \geq dur^-\), and
-
\(t' - t \leq dur^+\)
scenario wait_time:
my_vehicle: vehicle
do serial:
phase1: my_vehicle.drive() with:
speed(speed: 0kph, at: start)
speed(speed: 10kph, at: end)
phase2: wait elapsed([10s..20s])
phase3: my_vehicle.drive() with:
speed(speed: [10kph..15kph])
This example is very similar to the one from the composition section for serial. But here, another phase in between (phase2) was added, which invokes a wait directive with a duration of 10 to 20 seconds. This means that during a time interval of 10 to 20 seconds anything is allowed to happen. Afterward, the action of phase3 is invoked.
7.6.2.5 Events
This chapter defines how events and directives involving events, such as emit
, wait
, or until
influence whether a trace accepts a given behavior trace.
To do so, this subsection defines:
-
How traces are extended with events formally.
-
What it means for a scenario to accept a trace extended with events.
-
How the individual directives, like
emit
andwait
, work using events.
There are four sources of events in ASAM OpenSCENARIO:
-
A scenario fires start and end events when it starts and ends.
-
A scenario can fire events explicitly using the
emit
directive. -
A structured type (such as a scenario or an actor) can have event declarations with an event specification that defines when this event occurs. The event specification can consist of a condition, such as a rise, fall, or elapse condition or another Boolean expression. An event with such an event specification occurs every time the specified condition evaluates to true. The event specification can also consist of a reference to another event plus an optional condition. In this case, the event occurs every time the referenced event occurs and the condition evaluates to true.
-
External functions can fire events. For example, an external function that connects to an external simulation application can cause an event to occur under certain conditions in that external simulation application.
Events are abstract objects: An event is an instance of an event definition identified by the name of the event given in the definition and parameter values for the parameters defined in the event definition (if any). An event carries no information about its source.
Events are purely abstract objects, which means that they are used only as a control mechanism within the language to specify:
-
Constraints on values at certain points in time
-
Constraints on the relative timing of scenarios
-
Points in time in which external functions are invoked
Events do not necessarily have a direct resemblance in the modeled traffic system, nor are certain conditions that occur within the modeled traffic system necessarily events in terms of a given ASAM OpenSCENARIO model.
For example, the starts and ends of scenarios do typically correspond to certain conditions. It can be the case that a scenario ends when a vehicle reaches a certain speed. However, there could also be sequences of scenarios where there is no uniquely identifiable point in time at which one scenario ends and the other begins, for example, when there are overlapping ranges of possible speeds of a vehicle required by two subsequent scenarios.
As another example, the honk of a horn can be considered. A given traffic system behavior where a vehicle’s horn sounds could be accepted by an ASAM OpenSCENARIO model that does not require or model the honk event at all. Likewise, defining and emitting an event called "honk" does not necessarily mean that a vehicle’s horn sounds in the modeled traffic system. Such an event must first translate to a change in a field value of a vehicle object in the traffic system. More technically and less semantically speaking, a honk event could also be a trigger for an external function call that then leads to a honk happening in an external simulation tool.
Events occur at certain points in time. This is formally represented by an event occurrence function. This function defines for every point in time the set of events occurring at that time. Formally, an event occurrence function has the type \(\epsilon: \mathbb{R}_{\geq 0} \to \mathbb{P}(E)\), where \(E\) is a set of events identified by a name and parameter values. (\(\mathbb{P}(E)\) denotes the powerset of \(E\), that is, the set of all sets of events.)
Based on the event occurrence function, we define an event trace as a tuple \((\epsilon, \pi)\) that combines an event occurrence function \(\epsilon\) with a trace \(\pi\). Both share a time axis, so \(\epsilon\) defines when events occur within the trace \(\pi\).
Note that the above definition implies that for every point in time there cannot be two occurrences of identical events. If, for example, the same event (referring to the same event definition by their name and with identical parameter values) is emitted by two scenarios at the same time, this will lead to the occurrence of only one instance of this event. If it is important to separate two occurrences of events, then they must be equipped with parameters that make this separation possible. For example, honk events could be equipped with a parameter that specifies the vehicle which is the source of the honk signal. Also, note that there is no order among the events occurring at the same time.
7.6.2.5.1 Trace acceptance and event trace consistency
A scenario \(Sc\) accepts a trace \(\pi\) only if there exists an event trace \((\epsilon, \pi)\) where the event occurrence defined by \(\epsilon\) satisfy the following conditions:
-
\((\epsilon, \pi)\) must be event trace consistent with scenario \(Sc\), which means that \(\epsilon\) places events on the trace timeline in such a way that this corresponds to
-
the time stamps of the start and end of scenarios that are invoked directly and indirectly by the scenario \(Sc\): At these points in time, the predefined
start
andend
events for the scenario invocations must occur. -
the time stamps of
emit
directives directly or indirectly invoked by \(Sc\). -
the time stamps of value changes that trigger qualified events.
-
-
wait
directive invocations are terminated if and not before a waited for event occurs while the wait directive invocation is active. -
Invocations of behaviors with an
until
directive are terminated exactly when a specified event occurs.
All other trace acceptance conditions defined above remain unaffected and must hold in addition to the conditions given here.
In the following, the semantics of the emit
, wait
, until
, and on
directives are defined in more detail.
7.6.2.5.2 Emit (event)
The emit
directive is a zero-time directive that emits an event (which may be waited for in another scenario).
Within an emit
directive invocation, values must be specified for all parameters defined in the event declaration.
At the time of invocation, any expressions specifying the event parameters are immediately evaluated, so that a concrete event instance is emitted.
An emit
directive typically appears within a serial composition, either directly or indirectly, because its invoking scenario is in turn invoked within a serial composition higher up in the behavior invocation tree.
In this case, the emit
directive emits an event at the same point in time as the previous behavior invocation terminates with respect to the next level of serial composition in the behavior invocation tree.
That means that the end
event of the previous behavior invocation and the event emitted by the emit
directive occur at the same time.
If an emit
invocation is not preceded by another behavior in a serial composition, and therefore happens at the beginning of the direct or indirect parent scenario, this means that the emitted event must occur at the beginning of the trace that shall be accepted by that scenario.
An emit
directive is zero-time, which means that the start and end of an emit
invocation happen at the same point in time.
Because an emit
directive is zero-time, there is no notion of trace acceptance defined for emit
directives:
emit
directives, as well as all other zero-time directives, are excluded from the trace acceptance semantics definition of the scenario composition operators (see Section 7.6.2.1, “Composition operators”).
emit
directives only influence trace acceptance of the parent scenarios indirectly by influencing the event trace consistency condition defined above (see Section 7.6.2.5.1, “Trace acceptance and event trace consistency”):
It is required that the event trace \((\epsilon, \pi)\) contains the emitted events at the time stamps where the emit
directive invocation occurs.
emit
eventevent vehicle_reached_speed(vehicle : vehicle, vehicle_speed : speed) # event definition
...
scenario vehicle.two_phases:
do serial:
phase1: drive() with:
speed(speed: 0kph, at: start)
speed(speed: [25kph..35kph], at: end)
emit vehicle_reached_speed(actor, actor.speed)
phase2: drive() with:
speed(speed: [30kph..50kph])
This is an example of how an event can be emitted within a serial composition.
The event definition is also shown on top: The event requires as parameter values a reference to a vehicle (vehicle
) and a speed value (vehicle_speed
).
The scenario describes two driving phases.
The first phase requires the vehicle to reach a speed between 25 and 35 kph.
The event is emitted after the first phase, more specifically at the same point in time in which the first scenario terminates.
The event emitted carries as parameter values a reference to the vehicle object which is subject to the scenario (which can be accessed via the actor field inherent to all scenarios that are invoked on actors), as well as the speed value of that vehicle at the point in time in which the event is emitted.
Such an event can be caught by another scenario using the wait
directive.
7.6.2.5.3 Wait (event)
The wait
directive for events serves as a synchronization point, delaying subsequent behavior invocations until the waited for event has occurred.
Except for delaying the next behavior, the wait
statement imposes no constraints.
If certain constraints shall hold while waiting, such constraints can be specified in a surrounding parallel composition.
Regarding trace acceptance, it is required that a trace satisfies any constraints imposed by modifiers.
Other than that, wait
directives only influence trace acceptance of the parent scenarios indirectly by influencing the event trace consistency condition defined above (see Section 7.6.2.5.1, “Trace acceptance and event trace consistency”):
It is required that the event trace \((\epsilon, \pi)\) contains waited for events only at the time stamps where the wait
directive invocation terminates or is inactive.
Note that this semantics definition entails that traces can be accepted that never lead to progressing a wait
directive invocation, and hence, never lead to the occurrence of any subsequent behavior.
In use cases where this is not acceptable, for example, upper time bounds can be specified for the invoking scenario.
wait
eventscenario vehicle.sync_with_other_vehicle:
other_vehicle: vehicle
do parallel:
other_vehicle.two_phases
serial:
wait @vehicle_reached_speed as vrs_event \
if vrs_event.vehicle == other_vehicle \
and vrs_event.vehicle_speed in [30kph..32kph]
drive() with:
speed(speed: other_vehicle.speed + 20 kph, at: start)
In this example, we have a scenario sync_with_other_vehicle
that can be invoked on vehicles.
It holds a field to another vehicle (other_vehicle
) and defines a parallel composition of an invocation of the two_phases
scenario from Section 7.6.2.5.2, “Emit (event)” on the vehicle other_vehicle
and a serial composition of a wait
action followed by an invocation of drive()
.
The drive()
action is invoked on whichever vehicle sync_with_other_vehicle
will be invoked.
The wait
directive waits for the event vehicle_reached_speed
that is emitted in the two_phases
scenario (see Section 7.6.2.5.2, “Emit (event)”).
Moreover, the wait
directive specifies two conditions:
-
The first condition is that the
vehicle
parameter of the event must be equal toother_vehicle
They must both bind to the same vehicle actor object. -
The second condition is that the parameter
vehicle_speed
must be within the range of 30 to 32 kph.
If a vehicle_reached_speed
event occurs that satisfies these two conditions, the wait
invocation terminates and the subsequent drive()
action starts, specifying that the vehicle on which sync_with_other_vehicle
is invoked must drive with a speed 20 kph higher than the speed of `other_vehicle´ immediately after the occurrence of the event.
7.6.2.5.4 Until (event)
The until
directive specifies that a behavior invocation shall terminate exactly on the occurrence of a specific event, and not before or after.
The until
directive influences trace acceptance indirectly by influencing the event trace consistency condition (see Section 7.6.2.5.1, “Trace acceptance and event trace consistency”):
For event trace consistency, events must occur in such a way that invocations of behaviors with an until
directive are terminated exactly when a specified event occurs.
When multiple until
directives apply to a behavior invocation, they are treated as if a single until
directive was given that matches any of the specified events:
The invocation terminates exactly when the first of these specified events occurs.
until
directivescenario vehicle.accelerate_to_speed_with_other_vehicle:
target_speed : speed
other_vehicle : vehicle
do drive() with:
speed(speed: target_speed, at: end)
until @vehicle_reached_speed as vrs_event \
if vrs_event.vehicle == other_vehicle \
and vrs_event.vehicle_speed == target_speed
This example shows a scenario for vehicles that invokes a drive action and specifies a target speed that shall be reached at the end of the scenario.
In addition, the scenario defines a field called other_vehicle
and it specifies that the scenario must end exactly at the occurrence of the event vehicle_reached_speed
under the condition that the event carries as the vehicle
parameter value a reference to the same vehicle as bound to other_vehicle
, and a vehicle_speed
parameter value the same value as set for target_speed
.
7.6.2.5.5 On (event)
Scenarios can have on
directives, which define that on the occurrence of an event, another zero-time behavior shall take place, such as a method call or emitting another event.
on
directives only influence trace acceptance if they trigger other events via emit
directives (see Section 7.6.2.5.2, “Emit (event)”).
7.6.3 Actions
Actions are atomic behaviors that can be performed by actors, and they can be invoked from scenarios.
The domain model of ASAM OpenSCENARIO specifies a set of domain actions, such as the drive()
action, including their semantics (see Section 8.8, "Movement actions").
In this release of the standard, the action semantics are not specified formally, and the precise semantics are left to the implementation of the respective actions.