22from enum import Enum
33
44SECONDS_TO_MILLISECONDS = 1e3
5+ CELCIUS_TO_KELVIN = 273.15
6+ KELVIN_TO_CELCIUS = - CELCIUS_TO_KELVIN
57TO_PERCENT = 100.0
68
79SIGNAL_PLOT_KWARGS = {
@@ -468,6 +470,96 @@ def analyzeAccelerometerSignalHasGravity(self, signal):
468470 "This suggests the signal may be missing gravitational acceleration."
469471 )
470472
473+ def analyzeBarometerSignal (self , pressure , temperature , timestamps , data ):
474+ self .images .append (plotFrame (
475+ timestamps ,
476+ pressure ,
477+ "Barometer signal" ,
478+ yLabel = "Pressure (hPa)" ,
479+ ** SIGNAL_PLOT_KWARGS ))
480+
481+ if temperature is not None :
482+ self .images .append (plotFrame (
483+ timestamps ,
484+ temperature + KELVIN_TO_CELCIUS , # Plot in °C
485+ "Air temperature" ,
486+ yLabel = "Temperature (°C)" ,
487+ ** SIGNAL_PLOT_KWARGS ))
488+
489+ groundTruths = getGroundTruths (data )
490+ if len (groundTruths ) > 0 :
491+ import matplotlib .pyplot as plt
492+ fig , ax1 = plt .subplots (figsize = (8 , 6 ))
493+ ax2 = ax1 .twinx ()
494+
495+ # https://en.wikipedia.org/wiki/Pressure_altitude
496+ # p = 1013.25 * (1 - h / 44330.694) ** 5.255 (hPa)
497+ altitude = 44330.694 * (1 - (pressure / 1013.25 ) ** (1 / 5.255 ))
498+ ax1 .plot (timestamps , altitude , label = "Barometer altitude" )
499+
500+ for groundTruth in groundTruths :
501+ marker = "." if len (groundTruth ["t" ]) == 1 else ""
502+ ax2 .plot (
503+ groundTruth ["t" ],
504+ groundTruth ["altitude" ],
505+ label = groundTruth ["name" ],
506+ color = groundTruth ["color" ],
507+ linestyle = "-" ,
508+ marker = marker )
509+
510+ ax1 .set_xlabel ("Time" )
511+ ax1 .set_ylabel ("Standard pressure altitude (m)" )
512+ ax1 .set_title ("Standard pressure altitude and GNSS altitude" )
513+ ax1 .legend ()
514+ ax2 .set_ylabel ("GNSS altitude (m)" )
515+ ax2 .legend ()
516+ fig .tight_layout ()
517+ self .images .append (base64 (fig ))
518+
519+ if temperature is None : return
520+
521+ minTemp = np .nanmin (temperature )
522+ maxTemp = np .nanmax (temperature )
523+
524+ def temperatureUnitCheck (thresholdKelvins , severityLevel ):
525+ thresholdCelcius = thresholdKelvins + KELVIN_TO_CELCIUS
526+ self .__addIssue (severityLevel ,
527+ "Barometer temperature measurements have values below threshold "
528+ f"{ thresholdKelvins :.1f} K ({ thresholdCelcius } °C). "
529+ f"Please verify measurement unit is Kelvins."
530+ )
531+
532+ BARO_UNIT_CHECK_ERROR_THRESHOLD_KELVINS = - 60 + CELCIUS_TO_KELVIN
533+ BARO_UNIT_CHECK_WARNING_THRESHOLD_KELVINS = - 30 + CELCIUS_TO_KELVIN
534+ if minTemp < BARO_UNIT_CHECK_ERROR_THRESHOLD_KELVINS :
535+ temperatureUnitCheck (BARO_UNIT_CHECK_ERROR_THRESHOLD_KELVINS , DiagnosisLevel .ERROR )
536+ elif minTemp < BARO_UNIT_CHECK_WARNING_THRESHOLD_KELVINS :
537+ temperatureUnitCheck (BARO_UNIT_CHECK_WARNING_THRESHOLD_KELVINS , DiagnosisLevel .WARNING )
538+
539+ def temperatureHighCheck (thresholdKelvins , severityLevel ):
540+ thresholdCelcius = thresholdKelvins + KELVIN_TO_CELCIUS
541+ self .__addIssue (severityLevel ,
542+ "Barometer temperature measurements have high values above threshold "
543+ f"{ thresholdKelvins :.1f} K ({ thresholdCelcius } °C). "
544+ "This may indicate that the barometer temperature measurements are not measuring air temperature."
545+ )
546+
547+ AIR_TEMPERATURE_ERROR_THRESHOLD_KELVINS = 60 + CELCIUS_TO_KELVIN
548+ AIR_TEMPERATURE_WARN_THRESHOLD_KELVINS = 40 + CELCIUS_TO_KELVIN
549+ if maxTemp > AIR_TEMPERATURE_ERROR_THRESHOLD_KELVINS :
550+ temperatureHighCheck (AIR_TEMPERATURE_ERROR_THRESHOLD_KELVINS , DiagnosisLevel .ERROR )
551+ elif maxTemp > AIR_TEMPERATURE_WARN_THRESHOLD_KELVINS :
552+ temperatureHighCheck (AIR_TEMPERATURE_WARN_THRESHOLD_KELVINS , DiagnosisLevel .WARNING )
553+
554+ AIR_TEMPERATURE_DELTA_THRESHOLD = 10
555+ if maxTemp - minTemp > AIR_TEMPERATURE_DELTA_THRESHOLD :
556+ self .__addIssue (
557+ DiagnosisLevel .WARNING ,
558+ "Barometer temperature measurements changed over "
559+ f"{ AIR_TEMPERATURE_DELTA_THRESHOLD :.1f} K over the dataset. "
560+ "This may indicate that the barometer temperature measurements are not measuring air temperature."
561+ )
562+
471563 def analyzeCpuUsage (self , signal , timestamps , processes ):
472564 CPU_USAGE_THRESHOLD = 90.0
473565
@@ -953,13 +1045,15 @@ def diagnoseBarometer(data, output):
9531045 BARO_MIN_FREQUENCY_HZ = 1.0
9541046 BARO_MAX_FREQUENCY_HZ = 1e3
9551047 BARO_DUPLICATE_VALUE_THRESHOLD = 0.2
956- BARO_UNIT_CHECK_MIN_THRESHOLD = 800 # hPa
957- BARO_UNIT_CHECK_MAX_THRESHOLD = 1200 # hPa
1048+ BARO_PRESSURE_UNIT_CHECK_MIN_THRESHOLD = 800 # hPa
1049+ BARO_PRESSURE_UNIT_CHECK_MAX_THRESHOLD = 1200 # hPa
9581050
9591051 sensor = data ["barometer" ]
9601052 timestamps = np .array (sensor ["t" ])
9611053 deltaTimes = np .array (sensor ["td" ])
962- signal = np .array (sensor ['v' ])
1054+ pressure = np .array (sensor ["pressure" ])
1055+ temperature = np .array (sensor ["temperature" ])
1056+ if np .all (np .isnan (temperature )): temperature = None
9631057
9641058 if len (timestamps ) == 0 : return
9651059
@@ -974,28 +1068,23 @@ def diagnoseBarometer(data, output):
9741068 "title" : "Barometer time diff"
9751069 },
9761070 isOptionalSensor = True )
977- status .analyzeSignalDuplicateValues (signal , BARO_DUPLICATE_VALUE_THRESHOLD )
1071+ status .analyzeSignalDuplicateValues (pressure , BARO_DUPLICATE_VALUE_THRESHOLD )
9781072 status .analyzeSignalUnit (
979- signal ,
1073+ pressure ,
9801074 timestamps ,
9811075 "hPa" ,
9821076 "Barometer" ,
983- BARO_UNIT_CHECK_MIN_THRESHOLD ,
984- BARO_UNIT_CHECK_MAX_THRESHOLD )
1077+ BARO_PRESSURE_UNIT_CHECK_MIN_THRESHOLD ,
1078+ BARO_PRESSURE_UNIT_CHECK_MAX_THRESHOLD )
1079+
1080+ status .analyzeBarometerSignal (pressure , temperature , timestamps , data )
9851081
9861082 output ["barometer" ] = {
9871083 "diagnosis" : status .diagnosis .toString (),
9881084 "issues" : status .serializeIssues (),
9891085 "frequency" : computeSamplingRate (deltaTimes ),
9901086 "count" : len (timestamps ),
991- "images" : [
992- plotFrame (
993- timestamps ,
994- signal ,
995- "Barometer signal" ,
996- yLabel = "Pressure (hPa)" ,
997- ** SIGNAL_PLOT_KWARGS )
998- ] + status .images
1087+ "images" : status .images
9991088 }
10001089 if status .diagnosis == DiagnosisLevel .ERROR :
10011090 output ["passed" ] = False
0 commit comments