如何将 hex 解释为 unsigned long int(20 位整数,12 位小数,模 20 位)

How to interpret hex to unsigned long int (20-bits integer, 12-bits fraction, modulo 20-bits)

我正在以 UDP 数据包的形式从传感器获取数据。手册提供了这些数据包的形式,但我无法理解如何解释时间戳。它被描述为长度为 4 个字节的无符号长整数(例如 'a07245ba'),应该被解释为 20 位整数和 12 位小数。我也对包含的信息 "modulo 20 bits" 感到困惑。

如何正确解释这些时间戳?

我尝试使用 Python 的 "int('str', 16)" 函数(例如 int('a0724',16) 和 int('5ba',16 ) ) 然后将两部分与小数点组合(例如 '657188​​.1466 seconds' )。 这似乎为我提供了正确的时间戳单位(秒),因为我已经记录了大约 10 秒的数据并且第一个和最后一个时间戳相隔 10 秒。但是,数字的小数部分似乎不正确。当我绘制数据时,时间戳会意外地前后跳跃,这让我相信我对时间戳的解释不正确。

此外,我解释的时间戳与任何预期值无关。手册说它应该返回自开机以来的秒数,或者自 2010 年 1 月 1 日以来的秒数。检查时,这两种情况似乎都不是。

所以时间戳意外地跳到 726162.71 秒,然后回落到 726126.125 秒。前四个字节是时间戳:

datasample = np.array(['b1491fda 00001017 00040a88 00000000 0a 02 00c24d18 0076dd10 fd13fe3c 0032d8ce 0222c71a 01f0f0fa',
       'b1492010 00001018 00040a88 00000000 0a 02 00c249aa 0076dbee fd148e86 0032dc34 02235336 01f0f3c8',
       'b1492047 00001019 00040a88 00000000 0a 02 00c2463c 0076dacc fd151ed0 0032df9a 0223df52 01f0f696',
       'b149207d 0000101a 00040a88 00000000 0a 02 00c248d0 0076da0a fd13fff4 003265b8 02239a24 01f0f3e0',
       'b14920b4 0000101b 00040a88 00000000 0a 02 00c248d0 0076da0a fd13fff4 003265b8 02239a24 01f0f3e0',
       'b14920eb 0000101c 00040a88 00000000 0a 02 00c1eed0 0076a812 fd148d00 0032b896 022396fe 01f0b4ac'],
      dtype='|S98')

timesample = np.array([726161.4058, 726162.16, 726162.71, 726162.125, 726162.18, 726162.235 ])

这是两个数据包的示例,间隔约 10 秒:

datasample10 = np.array(['b1a2f9ea 000012ea 00040a88 00000000 0a 02 00c230d4 007671a6 fd1c2538 002b512e 021b9f7c 01f14944',
           'b1a39a8e 000015db 00040a88 00000000 0a 02 00c1d26c 0076b032 fd1c3554 002d51b2 021bd5a0 01f0cd92'],
          dtype='|S98')

timesample10 = np.array([727599.2538, 727609.2702])

12位可以表示2**12个不同的数字。它可以表示从 02**12 - 1 的整数(即 4095)。 如果我们采用该整数的十进制字符串表示形式并将其直接转换为秒的小数部分, 那么我们只能表示从 00.4096 的小数秒。好像不太对。

要在 01 之间均匀分布小数部分,我们需要除以 4096:

import numpy as np
datasample = np.array(['b1491fda 00001017 00040a88 00000000 0a 02 00c24d18 0076dd10 fd13fe3c 0032d8ce 0222c71a 01f0f0fa',
                       'b1492010 00001018 00040a88 00000000 0a 02 00c249aa 0076dbee fd148e86 0032dc34 02235336 01f0f3c8',
                       'b1492047 00001019 00040a88 00000000 0a 02 00c2463c 0076dacc fd151ed0 0032df9a 0223df52 01f0f696',
                       'b149207d 0000101a 00040a88 00000000 0a 02 00c248d0 0076da0a fd13fff4 003265b8 02239a24 01f0f3e0',
                       'b14920b4 0000101b 00040a88 00000000 0a 02 00c248d0 0076da0a fd13fff4 003265b8 02239a24 01f0f3e0',
                       'b14920eb 0000101c 00040a88 00000000 0a 02 00c1eed0 0076a812 fd148d00 0032b896 022396fe 01f0b4ac'],
                      dtype='|S98')
print(np.array([int(row[:8],16)  for row in datasample]) / 2**12)

产量

[726161.99072266 726162.00390625 726162.01733398 726162.03051758 726162.04394531 726162.05737305]

这很好 属性 时间戳都在增加:

result = (np.array([int(row[:8],16)  for row in datasample]) / 2**12)
print(np.diff(result))
# [0.01318359 0.01342773 0.01318359 0.01342773 0.01342773]

并且 datasample10 映射到时间戳,时间戳大约相隔 10 秒:

datasample10 = np.array(['b1a2f9ea 000012ea 00040a88 00000000 0a 02 00c230d4 007671a6 fd1c2538 002b512e 021b9f7c 01f14944',
           'b1a39a8e 000015db 00040a88 00000000 0a 02 00c1d26c 0076b032 fd1c3554 002d51b2 021bd5a0 01f0cd92'],
          dtype='|S98')

result = (np.array([int(row[:8],16)  for row in datasample10]) / 2**12)
print(np.diff(result))
# [10.04003906]

我不确定这些十六进制字符串应该如何解释为秒 自电源打开或自 2010-1-1 以来。 如果它们是为了表示自电源打开以来的秒数,并且可能您发布的数据很快就出现了, 那么使数字大小合理的一种方法是取整数模 2**20 —— 即模 20 位:

result = (np.array([int(row[:8],16)  for row in datasample]) % 2**20 / 2**12) 
print(result)
# [145.99072266 146.00390625 146.01733398 146.03051758 146.04394531 146.05737305]

但如果这是正确的,那么在原来的32位中,只有最右边的20位 正在使用,12 位的小数部分和 8 位的整体 秒。这意味着在值循环回 0 之前,最大时间戳仅为 256。 这似乎相当有限,所以我不确定这是解释 "modulo 20-bits".

的正确方法

另一方面,如果时间戳表示自 2010-1-1 以来的秒数,那么我们应该期望整数 301000000:

import datetime as DT
print((DT.datetime.now() - DT.datetime(2010,1,1)).total_seconds())
# 301151491.085063

我还没猜到从 3.01 亿范围内的日期样本到时间戳的映射 它保留了单调性和已知的 10 秒间隔。

好吧,我们可以在当前公式中添加 3.01 亿,但这完全是人为的...