204. Traffic density watcher
The vehicle.traffic_density watcher monitors the traffic conditions in the immediate vicinity of a vehicle and emits intervals when traffic density changes across different categories. This watcher provides real-time assessment of traffic conditions in the Ego lane, left lanes, and right lanes, along with an overall traffic density indicator based on established traffic engineering standards.
204.0.1 Start condition
A new interval starts when all the following conditions are met:
- No active interval exists (
data == null) - Lane information is available
- The Ego exists in the simulator
- The Ego's speed is greater than or equal to
min_activation_speed
204.0.2 End condition
An active interval ends when any of the following conditions are met:
1. Category change (with delayed restart):
- The traffic density category changes from one level to another (e.g., from light to moderate)
- The previous interval ends immediately at the current sampling time
- The watcher prevents starting a new interval within the same clock cycle
- The new interval starts at the next clock cycle in which the conditions are met. This ensures distinct start and end timestamps and prevents overlap.
2. Invalid operating conditions (end with deferred restart when activation returns):
- The Ego's speed drops below the
min_activation_speed - Lane information becomes unavailable, or lane/occupancy consistency checks fail
- The interval ends on that tick; when activation is OK again, the next interval starts on the following
w_clk(no need to wait forsampling_frequency)
204.0.3 Interval timing
- A category change ends at the sample time; the next interval opens on the next
w_clk. - An invalid activation ends on any tick. The same deferred start applies when speed and lane checks pass again.
- Interval length can be shorter than
sampling_frequency: invalid activation ends on everyw_clk, so an interval may start at one traffic-density sample and end when speed or lane fails between samples. Logs only appear on sample ticks, so a 34.5–36.1 s interval can appear as "no data" in the log even though the watcher was active.
204.0.4 Validity checks
- The check for invalid operating conditions runs on every clock tick, not just at sampling intervals.
- Lane validity allows either
lane_position.laneormsp_pos_closest_laneto match an occupied driving lane, reducing transient false invalids when those sources disagree by one tick. - Longitudinal separation for the detection window uses
map.get_road_distance_along_routeon the same driving-lanes-onlyrouteasget_lane_changes_along_route, notvehicle.road_distance.vehicle.road_distanceis measured along the Ego'splanned_pathand can disagree with the graph route, for example for oncoming or off-path traffic.
204.0.5 Rolling metrics
- Rolling density windows append one sample per traffic tick, including 0 v/km when a relative lane is empty. The average decays over
rolling_window_sizeinstead of clearing history. This avoids an instantno_trafficresult when the Ego changes lane and a side slot drops to 0 while traffic still exists in another slot. - Rolling averages determine when an interval ends on an overall category change.
- Rolling lists are cleared on each interval start (
@i_start), so rolling state is per interval only.
204.0.6 Emitted interval data
Emitted data.* values (lane and overall density and categories at @i_end) use the following calculation rules:
- Lane and overall density and categories use a true interval-mean vehicle count (float: sum of per-sample counts / number of samples).
- Integer
statistics(..., average)truncates, so*_vehicle_count_avgcan be 0 while min/max show brief traffic. - Density uses the float mean so categories match sparse occupancy.
data.total_vehicle_countuses the float mean of the per-tick total count (sum of lane sums / number of samples), rounded for the uint field.
204.1 Configuration parameters
The following parameters can be configured to customize the evaluator's behavior.
| Parameter | Type | Unit | Description | Default Value | Range |
|---|---|---|---|---|---|
detection_range_forward |
length | m | Forward detection range is the distance from the Ego's current position to the forward detection range | 100m | [0, 300]m |
detection_range_backward |
length | m | Distance behind the Ego within which vehicles are detected | 50m | [0, 300]m |
min_vehicle_speed |
speed | kph | Minimum speed at which a vehicle is considered to be in motion and included in traffic density calculations | 5kph | [0, 100]kph |
min_activation_speed |
speed | kph | Minimum Ego speed required to activate the watcher | 5kph | [0, 100]kph |
light_traffic_density_threshold |
float | Upper density threshold for the light traffic category | 8.0 | [1, 200] vehicles/km/lane | |
moderate_traffic_density_threshold |
float | Upper density threshold for the moderate traffic density category | 19.0 | [1, 200] vehicles/km/lane | |
heavy_traffic_density_threshold |
float | Upper density threshold for the heavy traffic density category | 42.0 | [1, 200] vehicles/km/lane | |
sampling_frequency |
time | s | Time interval between traffic density samples | 2s | [0, 30]s |
rolling_window_size |
uint | Number of samples in the rolling window used to calculate average traffic density | 5 | [0, 30] | |
log_level |
enum (info_level, debug_level, trace_level) |
Log level for the watcher. | info_level | ||
enabled |
bool | Enables or disables the watcher. | true |
204.2 Metrics
The following metrics are recorded and tracked by the evaluator.
| Metric | Type | Description | Range | Unit |
|---|---|---|---|---|
avg_speed |
speed | Average speed of the Ego during the interval | kph | |
ego_lane_traffic_density_category |
enum (no_traffic, light, moderate, heavy, congested, not_available) |
Traffic density category in the Ego lane | ||
left_lane_traffic_density_category |
enum (no_traffic, light, moderate, heavy, congested, not_available) |
Traffic density category in the left adjacent lane | ||
right_lane_traffic_density_category |
enum (no_traffic, light, moderate, heavy, congested, not_available) |
Traffic density category in the right adjacent lane | ||
ego_lane_vehicle_count_avg |
uint | Number of vehicles detected in the Ego lane within the detection range | ||
left_lane_vehicle_count_avg |
uint | Number of vehicles detected in the left adjacent lane (if available) | ||
right_lane_vehicle_count_avg |
uint | Number of vehicles detected in the right adjacent lane (if available) | ||
ego_lane_vehicle_count_minimum |
uint | Minimum number of vehicles detected in the Ego lane within the detection range | ||
left_lane_vehicle_count_minimum |
uint | Minimum number of vehicles detected in the left adjacent lane (if available) | ||
right_lane_vehicle_count_minimum |
uint | Minimum number of vehicles detected in the right adjacent lane (if available) | ||
ego_lane_vehicle_count_maximum |
uint | Maximum number of vehicles detected in the Ego lane within the detection range | ||
left_lane_vehicle_count_maximum |
uint | Maximum number of vehicles detected in the left adjacent lane (if available) | ||
right_lane_vehicle_count_maximum |
uint | Maximum number of vehicles detected in the right adjacent lane (if available) | ||
ego_lane_density |
float | Spatial traffic density in the Ego lane (vehicles/km/lane) | ||
left_lane_density |
float | Spatial traffic density in the left adjacent lane (vehicles/km/lane) | ||
right_lane_density |
float | Spatial traffic density in the right adjacent lane (vehicles/km/lane) | ||
traffic_avg_density |
float | Mean spatial traffic density across all lanes (vehicles/km/lane) | ||
overall_traffic_density_category |
enum (no_traffic, light, moderate, heavy, congested, not_available) |
Overall traffic density category (interval-mean overall category) | ||
total_vehicle_count |
uint | Mean total vehicles in range per sample tick over the interval (aligned with interval-mean density) | ||
ego_lane_avg_speed |
speed | Mean speed of vehicles traveling in the Ego lane | kph | |
left_lane_avg_speed |
speed | Mean speed of vehicles traveling in the left adjacent lane | kph | |
right_lane_avg_speed |
speed | Mean speed of vehicles traveling in the right adjacent lane | kph | |
traffic_avg_speed |
speed | Mean speed of vehicles across all lanes | kph |
204.3 Log and Error Messages
No error messages found.
204.4 Usage
204.4.1 How to instantiate
The traffic_density watcher can be instantiated for any vehicle actor.
watcher traffic_density_watcher is traffic_density(
vehicle: actor,
detection_range_forward: ftlx_global_eval_config.ego_traffic_density_config.detection_range_forward,
detection_range_backward: ftlx_global_eval_config.ego_traffic_density_config.detection_range_backward,
min_vehicle_speed: ftlx_global_eval_config.ego_traffic_density_config.min_vehicle_speed,
min_activation_speed: ftlx_global_eval_config.ego_traffic_density_config.min_activation_speed,
light_traffic_density_threshold: ftlx_global_eval_config.ego_traffic_density_config.light_traffic_density_threshold,
moderate_traffic_density_threshold: ftlx_global_eval_config.ego_traffic_density_config.moderate_traffic_density_threshold,
heavy_traffic_density_threshold: ftlx_global_eval_config.ego_traffic_density_config.heavy_traffic_density_threshold,
sampling_frequency: ftlx_global_eval_config.ego_traffic_density_config.sampling_frequency,
rolling_window_size: ftlx_global_eval_config.ego_traffic_density_config.rolling_window_size,
log_level: ftlx_global_eval_config.ego_traffic_density_config.log_level)
204.4.2 Set parameters at instantiation time
Pass parameters in the keep(...) binding at instantiation time, either from ftlx_global_eval_config or as explicit values.
watcher traffic_density_watcher is traffic_density(vehicle: sut.car):
keep(detection_range_forward == ftlx_global_eval_config.ego_traffic_density_config.detection_range_forward)
keep(detection_range_backward == 50m)
keep(min_vehicle_speed == 5kph)
keep(min_activation_speed == 5kph)
keep(log_level == ftlx_global_eval_config.ego_traffic_density_config.log_level)
204.4.3 Define and use a custom parameter set
A new struct can be created to customize the watcher's parameters in a more organized and modular way.
const custom_traffic_density_config: traffic_density_watcher_config = new
set custom_traffic_density_config.detection_range_forward = 100m
set custom_traffic_density_config.detection_range_backward = 50m
set custom_traffic_density_config.min_vehicle_speed = 5kph
set custom_traffic_density_config.min_activation_speed = 5kph
set custom_traffic_density_config.log_level = trace_level
watcher custom_traffic_density_watcher is traffic_density(vehicle: sut.car,
detection_range_forward: custom_traffic_density_config.detection_range_forward,
detection_range_backward: custom_traffic_density_config.detection_range_backward,
min_vehicle_speed: custom_traffic_density_config.min_vehicle_speed,
min_activation_speed: custom_traffic_density_config.min_activation_speed,
log_level: custom_traffic_density_config.log_level)
204.4.4 Disabling the watcher
To disable the watcher, set the enabled flag to false in the traffic_density_watcher_config struct.
const traffic_density_watcher_config: traffic_density_watcher_config = new
set traffic_density_watcher_config.enabled = false
204.5 Additional information
All parameters are required, but you don't need to customize all of them.
For any parameter you don't customize with set, the default value defined in traffic_density_watcher_config is used.
Custom traffic density interval watcher configuration example
extend top.main:
watcher my_traffic_density_watcher is traffic_density(
vehicle: sut.car,
detection_range_forward: 150m,
detection_range_backward: 75m,
min_vehicle_speed: 10kph,
min_activation_speed: 15kph,
light_traffic_density_threshold: 10.0,
moderate_traffic_density_threshold: 25.0,
heavy_traffic_density_threshold: 50.0,
sampling_frequency: 1s,
rolling_window_size: 3,
log_level: debug_level
)
Traffic density categories
The watcher classifies traffic density into the following five categories based on spatial density of vehicles per kilometer per lane (vehicles/km/lane).
| Category | Density Range | Description | Unit |
|---|---|---|---|
| no_traffic | 0.0 | No vehicles detected in the detection range | |
| light | < 8.0 | Sparse traffic with minimal vehicle interactions | vehicles/km/lane |
| moderate | 8.0 - 19.0 | Stable traffic flow with some vehicle interactions | vehicles/km/lane |
| heavy | 19.0 - 42.0 | Unstable traffic flow where frequent lane changes are difficult due to significant congestion | vehicles/km/lane |
| congested | > 42.0 | Very heavy traffic, near standstill conditions where breakdowns cause major delays | vehicles/km/lane |
| not_available | N/A | Lane information unavailable or invalid density calculation |