【问题标题】:Accelerometer SensorEvent timestamp加速度计 SensorEvent 时间戳
【发布时间】:2011-03-31 13:38:07
【问题描述】:

我目前正在开发一个 android 应用程序。我必须用事件时间记录加速度计传感器事件坐标。我得到了像“3497855005850”这样的传感器事件时间戳,但我无法将事件时间戳转换为用户可读的日期时间格式。提前致谢

如何将 SensorEvent 时间戳转换为 unix 时间戳?

【问题讨论】:

    标签: android


    【解决方案1】:

    https://source.android.com/devices/sensors/hal-interface.html#sensors_event_t
    “时间戳必须与 elapsedRealtimeNano 时钟同步” 所以

    val timeInMills = System.currentTimeMillis() + (event.timestamp - SystemClock.elapsedRealtimeNanos()) / 1000000
    

    【讨论】:

    • 正确答案是这个,否则时间戳会偏移
    【解决方案2】:

    官方SensorEvent#timestampdocumentation表示:

    [event.time is] 事件发生的时间(以纳秒为单位)。对于给定的传感器,每个新的传感器事件都应该单调递增使用与 SystemClock.elapsedRealtimeNanos() 相同的时基

    挑战

    • 某些制造商/设备改用SystemClock.currentTimeNanos()(例如 Nexus 4)。

    独立于设备的解决方案:

    /**
     * Calculates the static offset (ms) which needs to
     *  be added to the `event.time` (ns) to get the Unix
     *  timestamp of the event.
     *
     * @param eventTimeNanos the {@code SensorEvent.time} to be used to determine the time offset
     * @return the offset in milliseconds
     */
    private long eventTimeOffset(final long eventTimeNanos) {
        // Capture timestamps of event reporting time
        final long elapsedRealTimeMillis = SystemClock.elapsedRealtime();
        final long upTimeMillis = SystemClock.uptimeMillis();
        final long currentTimeMillis = System.currentTimeMillis();
    
        // Check which timestamp the event.time is closest to the event.time
        final long eventTimeMillis = eventTimeNanos / 1_000_000L;
        final long elapsedTimeDiff = elapsedRealTimeMillis - eventTimeMillis;
        final long upTimeDiff = upTimeMillis - eventTimeMillis;
        final long currentTimeDiff = currentTimeMillis - eventTimeMillis;
    
        // Default case (elapsedRealTime, following the documentation)
        if (Math.abs(elapsedTimeDiff) <= Math.min(Math.abs(upTimeDiff), Math.abs(currentTimeDiff))) {
            final long bootTimeMillis = currentTimeMillis - elapsedRealTimeMillis;
            return bootTimeMillis;
        }
    
        // Other seen case (currentTime, e.g. Nexus 4)
        if (Math.abs(currentTimeDiff) <= Math.abs(upTimeDiff)) {
            return 0;
        }
    
        // Possible case, but unknown if actually used by manufacturers (upTime)
        throw new IllegalStateException("The event.time seems to be upTime. In this case we cannot use a static offset to calculate the Unix timestamp of the event");
    }
    

    注册时间延迟

    • 此代码与event.time 与触发传感器事件侦听器的时间(注册时间)之间的延迟无关,因为我们仅使用SystemClock 来计算偏移量。
    • 这允许在多个设备之间同步传感器数据,前提是它们的系统时间已同步(有应用程序)。

    关于“可能的情况”(见代码):

    • 尚不清楚是否有制造商将upTime 用作event.time。因此,我们抛出一个异常来看看这是否真的发生过。

    • 如果发生这种情况,并且如果我们计算 currentTimeupTime 之间的静态偏移量,这将导致设备再次处于(深度)睡眠状态时发生时间偏移。我们需要为每个非常重的事件动态计算偏移量。

    • 如果在设备上发生这种情况,可以使用以下方法进行测试:https://developer.android.com/training/monitoring-device-state/doze-standby#testing_doze_and_app_standby

    【讨论】:

      【解决方案3】:

      每个设备都不同。它可以基于纪元、自启动以来的时间和 CPU 唤醒时间。最好的方法是读取所有三个,然后查看时间戳最接近哪一个,然后根据偏移量进行转换。

      【讨论】:

        【解决方案4】:

        我看到了三种获取millis(Kotlin)的方法

        val millis = Date().getTime() + (event.timestamp - System.nanoTime()) / 1000000L
        
        val millis = System.currentTimeMillis() + (event.timestamp - System.nanoTime()) / 1000000L
        
        val millis = System.currentTimeMillis() + (event.timestamp - SystemClock.elapsedRealtimeNanos()) / 1000000L
        

        所有三个都提供相同的结果,但是当我想查看计算值与当前时间的差异时

        val diff  = System.currentTimeMillis() - millis
        

        我看到 'diff' 的值为 -359704905

        Log.d("diff", "" + event.timestamp + " - " + System.nanoTime())
        

        差异:541695268300000 - 181990403666592

        差异:541695277240000 - 181990405818592

        差异:541695286859000 - 181990411901592

        差异:541695296139000 - 181990412584592

        差异:541695305735000 - 181990415222592

        所以所有建议的解决方案都不正确

        对我来说,这种简单的方法适合我的需要

        override fun onSensorChanged(sensorEvent: SensorEvent?) {
            val millis = System.currentTimeMillis()
        }
        

        【讨论】:

        • 如果您在注册时设置了任何延迟,此解决方案将不起作用*。当延迟>0 时,您将有多个读数同时到达,您将为所有读数分配相同的时间戳。 * 注册使用公共布尔 registerListener(SensorEventListener listener, Sensor sensor, int samplingPeriodUs, int maxReportLatencyUs)
        【解决方案5】:

        我遇到了同样的问题并使用了 ehartwell 的 solution。但是我使用了System.currentTimeMillis() 而不是new Date().getTime()

        此外,我发现sensorEvent.timeStampSystem.nanoTime() 的最大偏移量为 300 毫秒,大部分小于 200 毫秒。根据所需的精度,您可以忽略此差异。

        如果我使用 Boban S.solution,则初始化时差异是正确的。然而,正确的时间和测量的时间是不同的。估计的测量时间是未来。

        【讨论】:

        • 分歧发生在什么时间范围内,发生了多少?您是否在多个设备上看到了这种情况?
        【解决方案6】:

        您可以在 onSensorChanged(SensorEvent) 函数中设置参考时间变量。

        当前时间和事件时间的参考。当事件到达时,从事件时间中减去传感器参考时间,您将有纳秒的差异。您可以将该差除以 1,000,000 与当前时间参考相加,以获取以毫秒为单位的事件时间。
        一个事件的计算误差最大为 0.5 毫秒。您可以通过偶尔更改参考时间来最大程度地减少错误。

        private long sensorTimeReference = 0l;
        private long myTimeReference = 0l;
        
        public void onSensorChanged(SensorEvent event) {
            // set reference times
            if(sensorTimeReference == 0l && myTimeReference == 0l) {
                sensorTimeReference = event.timestamp;
                myTimeReference = System.currentTimeMillis();
            }
            // set event timestamp to current time in milliseconds
            event.timestamp = myTimeReference + 
                Math.round((event.timestamp - sensorTimeReference) / 1000000.0);
            // some code...
        }
        

        【讨论】:

        • 您如何处理在报告值时存在延迟的传感器?
        【解决方案7】:

        传感器时间戳实际上是纳秒的正常运行时间,不是以纳秒为单位的系统时间。见SensorEvent.timestamp to absolute (utc) timestamp?

        理论上,您可以使用以下方法将传感器时间戳转换为以毫秒为单位的时间:

        long timeInMillis = (new Date()).getTime() 
                            + (sensorEvent.timestamp - System.nanoTime()) / 1000000L;
        

        您甚至可以将 (new Date()).getTime() 调用与两个 System.nanoTime() 调用括起来,并对它们进行平均以更接近实际偏移量。

        然后您可以将传感器时间格式化为日期和时间。

        【讨论】:

        • 从 Android 4.2.1(API lvl 17)开始,在我的 Nexus 4 上,sensorEvent.timestamp 似乎包含准确的时间戳(以纳秒为单位)。这似乎是无证的,尽管它非常重要!
        • 我可以保证 Romain 所说的。
        • 不幸的是,时间戳的值似乎并不取决于 Android 的版本:code.google.com/p/android/issues/detail?id=56561
        • 对于 STEP_COUNTER 类型的 SensorEvent,这不适用于搭载 Android 5 的三星 S4 - 所以基本上给出的答案对于该传感器类型来说并没有那么多用途或正确。我最初认为 Boban S 的答案是有道理的,但实际上对于此设备上的这种类型的传感器也不起作用。本质上,您有时间为该类型的传感器引发事件 - 大概是因为它是事件的集合,而不是单个事件。
        • 这是一个错误的答案。传感器时间戳可能不是以纳秒为单位的正常运行时间,它因制造商而异。
        猜你喜欢
        • 2013-01-28
        • 1970-01-01
        • 2012-09-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多