Skip to content

Commit 6d3c8b3

Browse files
authored
[uss_qualifier/display_data_evaluator] factor out _evaluate_flight_presence for future additional evaluators (#879)
1 parent abf62e8 commit 6d3c8b3

File tree

1 file changed

+102
-99
lines changed

1 file changed

+102
-99
lines changed

monitoring/uss_qualifier/scenarios/astm/netrid/display_data_evaluator.py

Lines changed: 102 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import datetime
2-
32
import math
43
from dataclasses import dataclass
54
from typing import List, Optional, Dict, Union, Set, Tuple
@@ -8,7 +7,6 @@
87
import s2sphere
98
from loguru import logger
109
from s2sphere import LatLng, LatLngRect
11-
1210
from uas_standards.interuss.automated_testing.rid.v1.observation import (
1311
Flight,
1412
GetDisplayDataResponse,
@@ -371,12 +369,16 @@ def _evaluate_normal_observation(
371369
self._injected_flights, observation.flights
372370
)
373371

374-
self._evaluate_flight_presence(
372+
_evaluate_flight_presence(
375373
observer.participant_id,
376374
[query],
377375
True,
378376
mapping_by_injection_id,
379377
verified_sps,
378+
self._test_scenario,
379+
self._injected_flights,
380+
self._rid_version,
381+
self._config,
380382
)
381383

382384
# Check that altitudes match for any observed flights matching injected flights
@@ -492,101 +494,6 @@ def _evaluate_normal_observation(
492494
],
493495
)
494496

495-
def _evaluate_flight_presence(
496-
self,
497-
observer_participant_id: str,
498-
observation_queries: List[Query],
499-
observer_participant_is_relevant: bool,
500-
mapping_by_injection_id: Dict[str, TelemetryMapping],
501-
verified_sps: Set[str],
502-
):
503-
"""Implements fragment documented in `display_data_evaluator_flight_presence.md`."""
504-
505-
query_timestamps = [q.request.timestamp for q in observation_queries]
506-
observer_participants = (
507-
[observer_participant_id] if observer_participant_is_relevant else []
508-
)
509-
for expected_flight in self._injected_flights:
510-
t_initiated = min(q.request.timestamp for q in observation_queries)
511-
t_response = max(q.response.reported.datetime for q in observation_queries)
512-
timestamps = [
513-
arrow.get(t.timestamp) for t in expected_flight.flight.telemetry
514-
]
515-
t_min = min(timestamps).datetime
516-
t_max = max(timestamps).datetime
517-
518-
if t_response < t_min:
519-
# This flight should definitely not have been observed (it starts in the future)
520-
with self._test_scenario.check(
521-
"Premature flight", [expected_flight.uss_participant_id]
522-
) as check:
523-
if expected_flight.flight.injection_id in mapping_by_injection_id:
524-
check.record_failed(
525-
summary="Flight observed before it started",
526-
details=f"Flight {expected_flight.flight.injection_id} injected into {expected_flight.uss_participant_id} was observed by {observer_participant_id} at {t_response.isoformat()} before that flight should have started at {t_min.isoformat()}",
527-
severity=Severity.Medium,
528-
query_timestamps=query_timestamps
529-
+ [expected_flight.query_timestamp],
530-
)
531-
# TODO: attempt to observe flight details
532-
continue
533-
elif (
534-
t_response
535-
> t_max
536-
+ self._rid_version.realtime_period
537-
+ self._config.max_propagation_latency.timedelta
538-
):
539-
# This flight should not have been observed (it was too far in the past)
540-
participants = observer_participants
541-
if (
542-
expected_flight.uss_participant_id not in verified_sps
543-
or not participants
544-
):
545-
participants.append(expected_flight.uss_participant_id)
546-
with self._test_scenario.check(
547-
"Lingering flight", participants
548-
) as check:
549-
if expected_flight.flight.injection_id in mapping_by_injection_id:
550-
check.record_failed(
551-
summary="Flight still observed long after it ended",
552-
details=f"Flight {expected_flight.flight.injection_id} injected into {expected_flight.uss_participant_id} was observed by {observer_participant_id} at {t_response.isoformat()} after it ended at {t_max.isoformat()}",
553-
severity=Severity.Medium,
554-
query_timestamps=query_timestamps
555-
+ [expected_flight.query_timestamp],
556-
)
557-
continue
558-
elif (
559-
t_min + self._config.max_propagation_latency.timedelta
560-
< t_initiated
561-
< t_max
562-
+ self._rid_version.realtime_period
563-
- self._config.max_propagation_latency.timedelta
564-
):
565-
# This flight should definitely have been observed
566-
participants = observer_participants
567-
if (
568-
expected_flight.uss_participant_id not in verified_sps
569-
or not participants
570-
):
571-
participants.append(expected_flight.uss_participant_id)
572-
with self._test_scenario.check("Missing flight", participants) as check:
573-
if (
574-
expected_flight.flight.injection_id
575-
not in mapping_by_injection_id
576-
):
577-
check.record_failed(
578-
summary="Expected flight not observed",
579-
details=f"Flight {expected_flight.flight.injection_id} injected into {expected_flight.uss_participant_id} was not found in the observation by {observer_participant_id} at {t_response.isoformat()} even though it should have been active from {t_min.isoformat()} to {t_max.isoformat()}",
580-
severity=Severity.Medium,
581-
query_timestamps=query_timestamps
582-
+ [expected_flight.query_timestamp],
583-
)
584-
continue
585-
# TODO: observe flight details
586-
elif t_initiated > t_min:
587-
# If this flight was not observed, there may be propagation latency
588-
pass # TODO: findings propagation latency
589-
590497
def _evaluate_area_too_large_observation(
591498
self,
592499
observer: RIDSystemObserver,
@@ -882,12 +789,16 @@ def _evaluate_normal_sp_observation(
882789
mappings: Dict[str, TelemetryMapping],
883790
) -> None:
884791

885-
self._evaluate_flight_presence(
792+
_evaluate_flight_presence(
886793
"uss_qualifier, acting as Display Provider",
887794
sp_observation.queries,
888795
False,
889796
mappings,
890797
set(),
798+
self._test_scenario,
799+
self._injected_flights,
800+
self._rid_version,
801+
self._config,
891802
)
892803

893804
for mapping in mappings.values():
@@ -1312,3 +1223,95 @@ def _sliding_triples(points: List[s2sphere.LatLng]) -> List[List[s2sphere.LatLng
13121223
Returns a list of triples of consecutive positions in passed the list.
13131224
"""
13141225
return [[points[i], points[i + 1], points[i + 2]] for i in range(len(points) - 2)]
1226+
1227+
1228+
def _evaluate_flight_presence(
1229+
observer_participant_id: str,
1230+
observation_queries: List[Query],
1231+
observer_participant_is_relevant: bool,
1232+
mapping_by_injection_id: Dict[str, TelemetryMapping],
1233+
verified_sps: Set[str],
1234+
test_scenario: TestScenario,
1235+
injected_flights: List[InjectedFlight],
1236+
rid_version: RIDVersion,
1237+
evaluation_config: EvaluationConfiguration,
1238+
):
1239+
"""Implements fragment documented in `display_data_evaluator_flight_presence.md`."""
1240+
1241+
query_timestamps = [q.request.timestamp for q in observation_queries]
1242+
observer_participants = (
1243+
[observer_participant_id] if observer_participant_is_relevant else []
1244+
)
1245+
for expected_flight in injected_flights:
1246+
t_initiated = min(q.request.timestamp for q in observation_queries)
1247+
t_response = max(q.response.reported.datetime for q in observation_queries)
1248+
timestamps = [arrow.get(t.timestamp) for t in expected_flight.flight.telemetry]
1249+
t_min = min(timestamps).datetime
1250+
t_max = max(timestamps).datetime
1251+
1252+
if t_response < t_min:
1253+
# This flight should definitely not have been observed (it starts in the future)
1254+
with test_scenario.check(
1255+
"Premature flight", [expected_flight.uss_participant_id]
1256+
) as check:
1257+
if expected_flight.flight.injection_id in mapping_by_injection_id:
1258+
check.record_failed(
1259+
summary="Flight observed before it started",
1260+
details=f"Flight {expected_flight.flight.injection_id} injected into {expected_flight.uss_participant_id} was observed by {observer_participant_id} at {t_response.isoformat()} before that flight should have started at {t_min.isoformat()}",
1261+
severity=Severity.Medium,
1262+
query_timestamps=query_timestamps
1263+
+ [expected_flight.query_timestamp],
1264+
)
1265+
# TODO: attempt to observe flight details
1266+
continue
1267+
elif (
1268+
t_response
1269+
> t_max
1270+
+ rid_version.realtime_period
1271+
+ evaluation_config.max_propagation_latency.timedelta
1272+
):
1273+
# This flight should not have been observed (it was too far in the past)
1274+
participants = observer_participants
1275+
if (
1276+
expected_flight.uss_participant_id not in verified_sps
1277+
or not participants
1278+
):
1279+
participants.append(expected_flight.uss_participant_id)
1280+
with test_scenario.check("Lingering flight", participants) as check:
1281+
if expected_flight.flight.injection_id in mapping_by_injection_id:
1282+
check.record_failed(
1283+
summary="Flight still observed long after it ended",
1284+
details=f"Flight {expected_flight.flight.injection_id} injected into {expected_flight.uss_participant_id} was observed by {observer_participant_id} at {t_response.isoformat()} after it ended at {t_max.isoformat()}",
1285+
severity=Severity.Medium,
1286+
query_timestamps=query_timestamps
1287+
+ [expected_flight.query_timestamp],
1288+
)
1289+
continue
1290+
elif (
1291+
t_min + evaluation_config.max_propagation_latency.timedelta
1292+
< t_initiated
1293+
< t_max
1294+
+ rid_version.realtime_period
1295+
- evaluation_config.max_propagation_latency.timedelta
1296+
):
1297+
# This flight should definitely have been observed
1298+
participants = observer_participants
1299+
if (
1300+
expected_flight.uss_participant_id not in verified_sps
1301+
or not participants
1302+
):
1303+
participants.append(expected_flight.uss_participant_id)
1304+
with test_scenario.check("Missing flight", participants) as check:
1305+
if expected_flight.flight.injection_id not in mapping_by_injection_id:
1306+
check.record_failed(
1307+
summary="Expected flight not observed",
1308+
details=f"Flight {expected_flight.flight.injection_id} injected into {expected_flight.uss_participant_id} was not found in the observation by {observer_participant_id} at {t_response.isoformat()} even though it should have been active from {t_min.isoformat()} to {t_max.isoformat()}",
1309+
severity=Severity.Medium,
1310+
query_timestamps=query_timestamps
1311+
+ [expected_flight.query_timestamp],
1312+
)
1313+
continue
1314+
# TODO: observe flight details
1315+
elif t_initiated > t_min:
1316+
# If this flight was not observed, there may be propagation latency
1317+
pass # TODO: findings propagation latency

0 commit comments

Comments
 (0)