@@ -17,6 +17,14 @@ def base64(fig):
17
17
buf .seek (0 )
18
18
return base64 .b64encode (buf .getvalue ()).decode ('utf-8' )
19
19
20
+ def getGroundTruths (data ):
21
+ # Preferred ground truth type first.
22
+ groundTruths = []
23
+ for field in ["globalGroundTruth" , "gnss" ]:
24
+ if len (data [field ]["t" ]) > 0 :
25
+ groundTruths .append (data [field ])
26
+ return groundTruths
27
+
20
28
def plotFrame (
21
29
x ,
22
30
ys ,
@@ -579,18 +587,18 @@ def computeVelocity(data, intervalSeconds=None):
579
587
580
588
plt .subplot (3 , 1 , 1 )
581
589
plt .plot (timestamps , velocity [:, 0 ], label = "VIO" )
582
- plt .plot (gtTime , gtVelocity [:, 0 ], label = "GNSS" )
590
+ plt .plot (gtTime , gtVelocity [:, 0 ], label = groundTruth [ "name" ], color = groundTruth [ "color" ] )
583
591
plt .ylabel ("East (m/s)" )
584
592
plt .legend ()
585
593
586
594
plt .subplot (3 , 1 , 2 )
587
595
plt .plot (timestamps , velocity [:, 1 ], label = "VIO" )
588
- plt .plot (gtTime , gtVelocity [:, 1 ], label = "GNSS" )
596
+ plt .plot (gtTime , gtVelocity [:, 1 ], label = groundTruth [ "name" ], color = groundTruth [ "color" ] )
589
597
plt .ylabel ("North (m/s)" )
590
598
591
599
plt .subplot (3 , 1 , 3 )
592
600
plt .plot (timestamps , velocity [:, 2 ], label = "VIO (z)" )
593
- plt .plot (gtTime , gtVelocity [:, 2 ], label = "GNSS" )
601
+ plt .plot (gtTime , gtVelocity [:, 2 ], label = groundTruth [ "name" ], color = groundTruth [ "color" ] )
594
602
plt .ylabel ("Up (m/s)" )
595
603
596
604
fig .suptitle (f"VIO velocity in ENU coordinates" )
@@ -603,8 +611,8 @@ def analyzeVIOPosition(
603
611
altitudeWGS84 ,
604
612
timestamps ,
605
613
trackingStatus ,
606
- groundTruth ):
607
- if groundTruth is None :
614
+ groundTruths ):
615
+ if len ( groundTruths ) == 0 :
608
616
self .images .append (plotFrame (
609
617
positionENU [:, 0 ],
610
618
positionENU [:, 1 ],
@@ -630,16 +638,16 @@ def analyzeVIOPosition(
630
638
631
639
fig , _ = plt .subplots (2 , 1 , figsize = (8 , 6 ))
632
640
633
- gtPosition = np .array (groundTruth ["position" ])
634
- gtAltitudeWGS84 = np .array (groundTruth ["altitude" ])
635
- gtTime = np .array (groundTruth ["t" ])
636
-
637
641
# Get lost tracking indices
638
642
lostIndices = [i for i , status in enumerate (trackingStatus ) if status == "LOST_TRACKING" ]
639
643
640
644
ax1 = plt .subplot (2 , 1 , 1 )
641
645
ax1 .plot (positionENU [:, 0 ], positionENU [:, 1 ], label = "VIO" )
642
- ax1 .plot (gtPosition [:, 0 ], gtPosition [:, 1 ], label = "GNSS" )
646
+
647
+ for groundTruth in groundTruths :
648
+ gtTime = np .array (groundTruth ["t" ])
649
+ gtPosition = np .array (groundTruth ["position" ])
650
+ ax1 .plot (gtPosition [:, 0 ], gtPosition [:, 1 ], label = groundTruth ["name" ], color = groundTruth ["color" ])
643
651
644
652
# Plot lost tracking points
645
653
if lostIndices :
@@ -656,7 +664,12 @@ def analyzeVIOPosition(
656
664
657
665
ax2 = plt .subplot (2 , 1 , 2 )
658
666
ax2 .plot (timestamps , altitudeWGS84 , label = "VIO" )
659
- ax2 .plot (gtTime , gtAltitudeWGS84 , label = "GNSS" )
667
+
668
+ for groundTruth in groundTruths :
669
+ gtTime = np .array (groundTruth ["t" ])
670
+ gtAltitudeWGS84 = np .array (groundTruth ["altitude" ])
671
+ ax2 .plot (gtTime , gtAltitudeWGS84 , label = groundTruth ["name" ], color = groundTruth ["color" ])
672
+
660
673
ax2 .set_title ("VIO altitude in WGS-84 coordinates" )
661
674
ax2 .set_xlabel ("Time (s)" )
662
675
ax2 .set_ylabel ("Altitude (m)" )
@@ -994,8 +1007,6 @@ def diagnoseGNSS(data, output):
994
1007
sensor = data ["gnss" ]
995
1008
timestamps = np .array (sensor ["t" ])
996
1009
deltaTimes = np .array (sensor ["td" ])
997
- positionEnu = np .array (sensor ["position" ])
998
- altitude = np .array (sensor ["altitude" ])
999
1010
1000
1011
if len (timestamps ) == 0 : return
1001
1012
@@ -1011,32 +1022,43 @@ def diagnoseGNSS(data, output):
1011
1022
},
1012
1023
allowDataGaps = True ,
1013
1024
isOptionalSensor = True )
1014
- status .analyzeSignalDuplicateValues (positionEnu )
1025
+ status .analyzeSignalDuplicateValues (np .array (sensor ["position" ]))
1026
+
1027
+ groundTruths = getGroundTruths (data )
1028
+
1029
+ import matplotlib .pyplot as plt
1030
+ fig , ax = plt .subplots (figsize = (8 , 6 ))
1031
+ for groundTruth in groundTruths :
1032
+ p = np .array (groundTruth ["position" ])
1033
+ linestyle = "-" if len (groundTruth ["t" ]) > 0 else "."
1034
+ ax .plot (p [:, 0 ], p [:, 1 ], label = groundTruth ["name" ], color = groundTruth ["color" ], linestyle = linestyle )
1035
+ ax .set_title ("GNSS position" )
1036
+ ax .set_xlabel ("East (m)" )
1037
+ ax .set_ylabel ("North (m)" )
1038
+ ax .legend ()
1039
+ ax .set_xscale ("linear" )
1040
+ ax .set_yscale ("linear" )
1041
+ ax .set_aspect ("equal" , adjustable = "datalim" )
1042
+ fig .tight_layout ()
1043
+ positionImage = base64 (fig )
1044
+
1045
+ fig , ax = plt .subplots (figsize = (8 , 6 ))
1046
+ for groundTruth in groundTruths :
1047
+ linestyle = "-" if len (groundTruth ["t" ]) > 0 else "."
1048
+ ax .plot (groundTruth ["t" ], groundTruth ["altitude" ], label = groundTruth ["name" ], color = groundTruth ["color" ], linestyle = linestyle )
1049
+ ax .set_title ("GNSS altitude (WGS-84)" )
1050
+ ax .set_xlabel ("Time (s)" )
1051
+ ax .set_ylabel ("Altitude (m)" )
1052
+ ax .legend ()
1053
+ fig .tight_layout ()
1054
+ altitudeImage = base64 (fig )
1015
1055
1016
1056
output ["GNSS" ] = {
1017
1057
"diagnosis" : status .diagnosis .toString (),
1018
1058
"issues" : status .serializeIssues (),
1019
1059
"frequency" : computeSamplingRate (deltaTimes ),
1020
1060
"count" : len (timestamps ),
1021
- "images" : [
1022
- plotFrame (
1023
- positionEnu [:, 0 ],
1024
- positionEnu [:, 1 ],
1025
- "GNSS position" ,
1026
- xLabel = "ENU x (m)" ,
1027
- yLabel = "ENU y (m)" ,
1028
- style = '-' if len (timestamps ) > 1 else '.' ,
1029
- yScale = "linear" ,
1030
- xScale = "linear" ,
1031
- equalAxis = True ),
1032
- plotFrame (
1033
- timestamps ,
1034
- altitude ,
1035
- "GNSS altitude (WGS-84)" ,
1036
- xLabel = "Time (s)" ,
1037
- yLabel = "Altitude (m)" ,
1038
- style = '-' if len (timestamps ) > 1 else '.' )
1039
- ] + status .images
1061
+ "images" : [positionImage , altitudeImage ] + status .images ,
1040
1062
}
1041
1063
if status .diagnosis == DiagnosisLevel .ERROR :
1042
1064
output ["passed" ] = False
@@ -1094,9 +1116,10 @@ def diagnoseVIO(data, output):
1094
1116
1095
1117
images = []
1096
1118
if hasGlobalOutput :
1097
- groundTruth = data ["gnss" ] # TODO: use groundTruth instead of gnss (if available)
1098
- if len (groundTruth ["t" ]) == 0 : groundTruth = None
1099
- status .analyzeVIOPosition (positionENU , altitudeWGS84 , timestamps , trackingStatus , groundTruth )
1119
+ groundTruths = getGroundTruths (data )
1120
+ status .analyzeVIOPosition (positionENU , altitudeWGS84 , timestamps , trackingStatus , groundTruths )
1121
+
1122
+ groundTruth = groundTruths [0 ] if len (groundTruths ) > 0 else None
1100
1123
status .analyzeVIOVelocity (velocityENU , timestamps , groundTruth )
1101
1124
else :
1102
1125
# TODO: improve relative positioning analysis
0 commit comments