Home | History | Annotate | Download | only in gnssmetrics
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.internal.location.gnssmetrics;
     18 
     19 import android.os.SystemClock;
     20 
     21 import android.util.Base64;
     22 import android.util.TimeUtils;
     23 
     24 import java.util.Arrays;
     25 
     26 import com.android.internal.location.nano.GnssLogsProto.GnssLog;
     27 
     28 /**
     29  * GnssMetrics: Is used for logging GNSS metrics
     30  * @hide
     31  */
     32 public class GnssMetrics {
     33 
     34   /** Default time between location fixes (in millisecs) */
     35   private static final int DEFAULT_TIME_BETWEEN_FIXES_MILLISECS = 1000;
     36 
     37   /* The time since boot when logging started */
     38   private String logStartInElapsedRealTime;
     39 
     40   /** Constructor */
     41   public GnssMetrics() {
     42     locationFailureStatistics = new Statistics();
     43     timeToFirstFixSecStatistics = new Statistics();
     44     positionAccuracyMeterStatistics = new Statistics();
     45     topFourAverageCn0Statistics = new Statistics();
     46     reset();
     47   }
     48 
     49   /**
     50    * Logs the status of a location report received from the HAL
     51    *
     52    * @param isSuccessful
     53    */
     54   public void logReceivedLocationStatus(boolean isSuccessful) {
     55     if (!isSuccessful) {
     56       locationFailureStatistics.addItem(1.0);
     57       return;
     58     }
     59     locationFailureStatistics.addItem(0.0);
     60     return;
     61   }
     62 
     63   /**
     64    * Logs missed reports
     65    *
     66    * @param desiredTimeBetweenFixesMilliSeconds
     67    * @param actualTimeBetweenFixesMilliSeconds
     68    */
     69   public void logMissedReports(int desiredTimeBetweenFixesMilliSeconds,
     70       int actualTimeBetweenFixesMilliSeconds) {
     71     int numReportMissed = (actualTimeBetweenFixesMilliSeconds /
     72         Math.max(DEFAULT_TIME_BETWEEN_FIXES_MILLISECS, desiredTimeBetweenFixesMilliSeconds)) - 1;
     73     if (numReportMissed > 0) {
     74       for (int i = 0; i < numReportMissed; i++) {
     75         locationFailureStatistics.addItem(1.0);
     76       }
     77     }
     78     return;
     79   }
     80 
     81   /**
     82    * Logs time to first fix
     83    *
     84    * @param timeToFirstFixMilliSeconds
     85    */
     86   public void logTimeToFirstFixMilliSecs(int timeToFirstFixMilliSeconds) {
     87     timeToFirstFixSecStatistics.addItem((double) (timeToFirstFixMilliSeconds/1000));
     88     return;
     89   }
     90 
     91   /**
     92    * Logs position accuracy
     93    *
     94    * @param positionAccuracyMeters
     95    */
     96   public void logPositionAccuracyMeters(float positionAccuracyMeters) {
     97     positionAccuracyMeterStatistics.addItem((double) positionAccuracyMeters);
     98     return;
     99   }
    100 
    101   /*
    102   * Logs CN0 when at least 4 SVs are available
    103   *
    104   */
    105   public void logCn0(float[] cn0s, int numSv) {
    106     if (numSv < 4) {
    107       return;
    108     }
    109     float[] cn0Array = Arrays.copyOf(cn0s, numSv);
    110     Arrays.sort(cn0Array);
    111     if (cn0Array[numSv - 4] > 0.0) {
    112       double top4AvgCn0 = 0.0;
    113       for (int i = numSv - 4; i < numSv; i++) {
    114         top4AvgCn0 += (double) cn0Array[i];
    115       }
    116       top4AvgCn0 /= 4;
    117       topFourAverageCn0Statistics.addItem(top4AvgCn0);
    118     }
    119     return;
    120   }
    121 
    122   /**
    123    * Dumps GNSS metrics as a proto string
    124    * @return
    125    */
    126   public String dumpGnssMetricsAsProtoString() {
    127     GnssLog msg = new GnssLog();
    128     if (locationFailureStatistics.getCount() > 0) {
    129       msg.numLocationReportProcessed = locationFailureStatistics.getCount();
    130       msg.percentageLocationFailure = (int) (100.0 * locationFailureStatistics.getMean());
    131     }
    132     if (timeToFirstFixSecStatistics.getCount() > 0) {
    133       msg.numTimeToFirstFixProcessed = timeToFirstFixSecStatistics.getCount();
    134       msg.meanTimeToFirstFixSecs = (int) timeToFirstFixSecStatistics.getMean();
    135       msg.standardDeviationTimeToFirstFixSecs
    136           = (int) timeToFirstFixSecStatistics.getStandardDeviation();
    137     }
    138     if (positionAccuracyMeterStatistics.getCount() > 0) {
    139       msg.numPositionAccuracyProcessed = positionAccuracyMeterStatistics.getCount();
    140       msg.meanPositionAccuracyMeters = (int) positionAccuracyMeterStatistics.getMean();
    141       msg.standardDeviationPositionAccuracyMeters
    142           = (int) positionAccuracyMeterStatistics.getStandardDeviation();
    143     }
    144     if (topFourAverageCn0Statistics.getCount() > 0) {
    145       msg.numTopFourAverageCn0Processed = topFourAverageCn0Statistics.getCount();
    146       msg.meanTopFourAverageCn0DbHz = topFourAverageCn0Statistics.getMean();
    147       msg.standardDeviationTopFourAverageCn0DbHz
    148           = topFourAverageCn0Statistics.getStandardDeviation();
    149     }
    150     String s = Base64.encodeToString(GnssLog.toByteArray(msg), Base64.DEFAULT);
    151     reset();
    152     return s;
    153   }
    154 
    155   /**
    156    * Dumps GNSS Metrics as text
    157    *
    158    * @return GNSS Metrics
    159    */
    160   public String dumpGnssMetricsAsText() {
    161     StringBuilder s = new StringBuilder();
    162     s.append("GNSS_KPI_START").append('\n');
    163     s.append("  KPI logging start time: ").append(logStartInElapsedRealTime).append("\n");
    164     s.append("  KPI logging end time: ");
    165     TimeUtils.formatDuration(SystemClock.elapsedRealtimeNanos() / 1000000L, s);
    166     s.append("\n");
    167     s.append("  Number of location reports: ").append(
    168         locationFailureStatistics.getCount()).append("\n");
    169     if (locationFailureStatistics.getCount() > 0) {
    170       s.append("  Percentage location failure: ").append(
    171           100.0 * locationFailureStatistics.getMean()).append("\n");
    172     }
    173     s.append("  Number of TTFF reports: ").append(
    174         timeToFirstFixSecStatistics.getCount()).append("\n");
    175     if (timeToFirstFixSecStatistics.getCount() > 0) {
    176       s.append("  TTFF mean (sec): ").append(timeToFirstFixSecStatistics.getMean()).append("\n");
    177       s.append("  TTFF standard deviation (sec): ").append(
    178           timeToFirstFixSecStatistics.getStandardDeviation()).append("\n");
    179     }
    180     s.append("  Number of position accuracy reports: ").append(
    181         positionAccuracyMeterStatistics.getCount()).append("\n");
    182     if (positionAccuracyMeterStatistics.getCount() > 0) {
    183       s.append("  Position accuracy mean (m): ").append(
    184           positionAccuracyMeterStatistics.getMean()).append("\n");
    185       s.append("  Position accuracy standard deviation (m): ").append(
    186           positionAccuracyMeterStatistics.getStandardDeviation()).append("\n");
    187     }
    188     s.append("  Number of CN0 reports: ").append(
    189         topFourAverageCn0Statistics.getCount()).append("\n");
    190     if (topFourAverageCn0Statistics.getCount() > 0) {
    191       s.append("  Top 4 Avg CN0 mean (dB-Hz): ").append(
    192           topFourAverageCn0Statistics.getMean()).append("\n");
    193       s.append("  Top 4 Avg CN0 standard deviation (dB-Hz): ").append(
    194           topFourAverageCn0Statistics.getStandardDeviation()).append("\n");
    195     }
    196     s.append("GNSS_KPI_END").append("\n");
    197     return s.toString();
    198   }
    199 
    200    /** Class for storing statistics */
    201   private class Statistics {
    202 
    203     /** Resets statistics */
    204     public void reset() {
    205       count = 0;
    206       sum = 0.0;
    207       sumSquare = 0.0;
    208     }
    209 
    210     /** Adds an item */
    211     public void addItem(double item) {
    212       count++;
    213       sum += item;
    214       sumSquare += item * item;
    215     }
    216 
    217     /** Returns number of items added */
    218     public int getCount() {
    219       return count;
    220     }
    221 
    222     /** Returns mean */
    223     public double getMean() {
    224       return sum/count;
    225     }
    226 
    227     /** Returns standard deviation */
    228     public double getStandardDeviation() {
    229       double m = sum/count;
    230       m = m * m;
    231       double v = sumSquare/count;
    232       if (v > m) {
    233         return Math.sqrt(v - m);
    234       }
    235       return 0;
    236     }
    237 
    238     private int count;
    239     private double sum;
    240     private double sumSquare;
    241   }
    242 
    243   /** Location failure statistics */
    244   private Statistics locationFailureStatistics;
    245 
    246   /** Time to first fix statistics */
    247   private Statistics timeToFirstFixSecStatistics;
    248 
    249   /** Position accuracy statistics */
    250   private Statistics positionAccuracyMeterStatistics;
    251 
    252   /** Top 4 average CN0 statistics */
    253   private Statistics topFourAverageCn0Statistics;
    254 
    255   /**
    256    * Resets GNSS metrics
    257    */
    258   private void reset() {
    259     StringBuilder s = new StringBuilder();
    260     TimeUtils.formatDuration(SystemClock.elapsedRealtimeNanos() / 1000000L, s);
    261     logStartInElapsedRealTime = s.toString();
    262     locationFailureStatistics.reset();
    263     timeToFirstFixSecStatistics.reset();
    264     positionAccuracyMeterStatistics.reset();
    265     topFourAverageCn0Statistics.reset();
    266     return;
    267   }
    268 }