Android 获取GNSS原始数据

获取安卓设备的GNSS测量数据方法

2016 年 5 月,Google 在 I/O 开发者会议上宣布,将为 Android Nougat 操作系统中的应用程序提供原始 GNSS 观测数据。
API参考(Google中文官网)DEMO参考(GNSSLogger)

1. 用到的类

注释
LocationManager 用于注册GNSSmeasurement
GnssMeasurementsEvent.Callback 用于从GNSS引擎接收GNSS卫星测量值
GnssMeasurementsEvent 一个包含测量值数据的容器
GnssClock 包含GPS时钟时间戳记的类
Gnssmeasurement 代表GNSS卫星测量的类,其中包含原始信息和计算信息

2.设置权限
必须先在Manifest文件中设置相应的权限,否则将无法获取测量的回调数据


    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
    <uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION"/>
    <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
    <uses-permission android:name="com.google.android.providers.gsf.permission.WRITE_GSERVICES"/>
    

3.注册GNSSmeasurement

private LocationManager mLocationManager;
private GnssMeasurementsEvent.Callback gnssMeasurementEventListener =
            new GnssMeasurementsEvent.Callback()
//这里先声明,重写方法将在下一步添加

public void RegisterMeasurements(){
        @SuppressLint("MissingPermission")
        boolean is_register_success=
        mLocationManager.registerGnssMeasurementsCallback(gnssMeasurementEventListener);
        //注册GNSSmeasurement回调监听,返回是否注册成功的信息
        //测量信息将在GnssMeasurementsEvent.Callback中接收
    }
//顺便把注销的方法也写了
public void unRegisterMeasurements(){
        mLocationManager.unregisterGnssMeasurementsCallback(gnssMeasurementEventListener);
    }

4.重写GnssMeasurementsEvent.Callback里的两个方法

private GnssMeasurementsEvent.Callback gnssMeasurementEventListener =
            new GnssMeasurementsEvent.Callback() {
                @Override
                public void onGnssMeasurementsReceived(GnssMeasurementsEvent eventArgs) {
                    super.onGnssMeasurementsReceived(eventArgs);
                    //这里我们获取到了回调的测量数据容器:GnssMeasurementsEvent eventArgs
                    //TODO:
                }

                @Override
                public void onStatusChanged(int status) {
                    super.onStatusChanged(status);
                }
    };

5.将测量数据转换为字符串

  1. 把GnssMeasurementsEvent拆分为GnssClock和Gnssmeasurement
//写一个接收测量信息的方法
public void onGnssMeasurementsReceived(GnssMeasurementsEvent event) {
        StringBuilder builder=new StringBuilder("GNSS测量数据:\n\n");
         //这里的toStringClock和toStringMeasurement将写在下一步里
        builder.append(toStringClock(event.getClock()));//写入gnss时钟的数据
        builder.append("\n");
        
        for (GnssMeasurement measurement : event.getMeasurements()) {
            builder.append(toStringMeasurement(measurement));//写入gnss测量数据
            builder.append("\n");
        }
		//这里可以写runOnUiThread(...),将builder打印在屏幕上
		//也可以修改返回值
    }

  1. 分别把GnssClock和Gnssmeasurement转化为字符串
private String toStringClock(GnssClock gnssClock){
        //将GPS接收器时钟的值转换为字符串
        final String format = "   %-4s = %s\n";//定义数据显示格式,“%-4”表示左对齐、不足四位补足四位
        StringBuilder builder=new StringBuilder("GNSS时钟:\n");
        DecimalFormat numberFormat = new DecimalFormat("#0.000");//定义格式化数字


        if (gnssClock.hasLeapSecond()) {
            //如果闰秒存在则显示闰秒
            builder.append(String.format(format, "闰秒(LeapSecond)", gnssClock.getLeapSecond()));
        }
        builder.append(String.format(format, "硬件时钟(TimeNanos)", gnssClock.getTimeNanos()));//获取以毫秒为单位的GNSS接收器内部硬件时钟值
        if (gnssClock.hasTimeUncertaintyNanos()) {
            //获取硬件时钟的误差估计(不确定度)
            builder.append(String.format(format, "时钟误差估计(TimeUncertaintyNanos)", gnssClock.getTimeUncertaintyNanos()));
        }

        if (gnssClock.hasFullBiasNanos()) {
            //如果存在接收机本地时钟总偏差,则显示
            builder.append(String.format(format, "总时钟偏差(FullBiasNanos)", gnssClock.getFullBiasNanos()));
        }
        if (gnssClock.hasBiasNanos()) {
            //亚纳秒偏差
            builder.append(String.format(format, "亚偏差(BiasNanos)", gnssClock.getBiasNanos()));
        }
        if (gnssClock.hasBiasUncertaintyNanos()) {
            //FullBiasNanos和BiasNanos的误差估计
            builder.append(String.format(format, "时钟偏差估计(BiasUncertaintyNanos)", numberFormat.format(gnssClock.getBiasUncertaintyNanos())));
        }
        /**
         * 注意:以上五个数据用于计算GPS时钟
         * 具体计算方法为:local estimate of GPS time = TimeNanos - (FullBiasNanos + BiasNanos)
         *     世界标准时:UtcTimeNanos = TimeNanos - (FullBiasNanos + BiasNanos) - LeapSecond * 1,000,000,000
         */
        if (gnssClock.hasDriftNanosPerSecond()) {
            //以每秒纳秒为单位获取时钟的漂移
            builder.append(String.format(format, "时钟漂移(DriftNanosPerSecond)", numberFormat.format(gnssClock.getDriftNanosPerSecond())));
        }
        if (gnssClock.hasDriftUncertaintyNanosPerSecond()) {
            //时钟偏差的估计
            builder.append(String.format(format, "时钟漂移估计(DriftUncertaintyNanosPerSecond)", numberFormat.format(gnssClock.getDriftUncertaintyNanosPerSecond())));
        }
        //获取硬件时钟不连续的计数,即:每当gnssclock中断时,该值+1
        builder.append(String.format(format, "中断计数(HardwareClockDiscontinuityCount)", gnssClock.getHardwareClockDiscontinuityCount()));
        return builder.toString();
    }
private String toStringMeasurement(GnssMeasurement measurement){
        //将GNSS测量结果转换为字符串
        //定义显示格式
        final String format = "   %-4s = %s\n";
        StringBuilder builder = new StringBuilder("GNSS测量结果:\n");
        DecimalFormat numberFormat = new DecimalFormat("#0.000");
        DecimalFormat numberFormat1 = new DecimalFormat("#0.000E00");

        //获取卫星ID
            /**
             * 取决于卫星类型
             * GPS:1-32
             * SBAS:120-151、183-192
             * GLONASS:OSN或FCN + 100之一
             * 1-24作为轨道槽号(OSN)(首选,如果知道)
             * 93-106作为频道号(FCN)(-7至+6)加100。即将-7的FCN编码为93,0编码为100,+ 6编码为106
             * QZSS:193-200
             * 伽利略:1-36
             * 北斗:1-37
             */
        builder.append(String.format(format, "卫星ID", measurement.getSvid()));

        //获取卫星类型
            /**
             *  1:CONSTELLATION_GPS 使用GPS定位
             *  2:CONSTELLATION_SBAS 使用SBAS定位
             *  3:CONSTELLATION_GLONASS 使用格洛纳斯定位
             *  4:CONSTELLATION_QZSS 使用QZSS定位
             *  5:CONSTELLATION_BEIDOU 使用北斗定位 (^-^)!
             *  6:CONSTELLATION_GALILEO 使用伽利略定位
             *  7:CONSTELLATION_IRNSS 使用印度区域卫星定位
             */
        builder.append(String.format(format, "卫星类型", measurement.getConstellationType()));

        //获取进行测量的时间偏移量(以纳秒为单位)
        builder.append(String.format(format, "测量时间偏移量", measurement.getTimeOffsetNanos()));

        //获取每个卫星的同步状态
        //具体数值含义请查表
        builder.append(String.format(format, "同步状态", measurement.getState()));

        //获取时间戳的伪距速率,以m/s为单位
        builder.append(
                String.format(
                        format,
                        "伪距速率",
                        numberFormat.format(measurement.getPseudorangeRateMetersPerSecond())));
        //获取伪距的速率不确定性(1-Sigma),以m/s为单位
        builder.append(
                String.format(
                        format,
                        "伪距速率不确定度",
                        numberFormat.format(measurement.getPseudorangeRateUncertaintyMetersPerSecond())));
        //
        if (measurement.getAccumulatedDeltaRangeState() != 0) {
            // 获取“累积增量范围”状态
            // 返回:MULTIPATH_INDICATOR_UNKNOWN(指示器不可用)=0
            // notice 即:指示器可用时,收集数据
            builder.append(
                    String.format(
                            format, "累积增量范围状态", measurement.getAccumulatedDeltaRangeState()));

            //获取自上次重置通道以来的累积增量范围,以米为单位.
            //该值仅在上面的state值为“可用”时有效
            //notice 累积增量范围= -k * 载波相位(其中k为常数)
            builder.append(
                    String.format(
                            format,
                            "累积增量范围",
                            numberFormat.format(measurement.getAccumulatedDeltaRangeMeters())));

            //获取以米为单位的累积增量范围的不确定性(1-Sigma)
            builder.append(
                    String.format(
                            format,
                            "累积增量范围不确定度",
                            numberFormat1.format(measurement.getAccumulatedDeltaRangeUncertaintyMeters())));
        }

        if (measurement.hasCarrierFrequencyHz()) {
            //获取被跟踪信号的载波频率
            builder.append(
                    String.format(format, "信号载波频率", measurement.getCarrierFrequencyHz()));
        }

        if (measurement.hasCarrierCycles()) {
            //卫星和接收器之间的完整载波周期数
            builder.append(String.format(format, "载波周期数", measurement.getCarrierCycles()));
        }

        if (measurement.hasCarrierPhase()) {
            //获取接收器检测到的RF相位
            builder.append(String.format(format, "RF相位", measurement.getCarrierPhase()));
        }

        if (measurement.hasCarrierPhaseUncertainty()) {
            //误差估计
            builder.append(
                    String.format(
                            format, "RF相位不确定度", measurement.getCarrierPhaseUncertainty()));
        }

        //获取一个值,该值指示事件的“多路径”状态,返回0或1或2
        //MULTIPATH_INDICATOR_DETECTED = 1 测量显示有“多路径效应”迹象
        // MULTIPATH_INDICATOR_NOT_DETECTED = 2 测量结果显示没有“多路径效应”迹象
        builder.append(String.format(format, "多路经效应指示器", measurement.getMultipathIndicator()));

        //
        if (measurement.hasSnrInDb()) {
            //获取信噪比(SNR),以dB为单位
            builder.append(String.format(format, "信噪比", measurement.getSnrInDb()));
        }

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            if (measurement.hasAutomaticGainControlLevelDb()) {
                //获取以dB为单位的自动增益控制级别
                builder.append(String.format(format, "自动增益控制级别", measurement.getAutomaticGainControlLevelDb()));
            }
            if (measurement.hasCarrierFrequencyHz()) {
                builder.append(String.format(format, "载波频率", measurement.getCarrierFrequencyHz()));
            }
        }

        return builder.toString();

    }

最后将这些方法整合起来即可,UI显示的部分就不再赘述了。

你可能感兴趣的:(Android 获取GNSS原始数据)