如何将十六进制解释为无符号长整数(20位整数,12位分数,20位模)

时间:2019-07-18 14:13:27

标签: python timestamp udp unsigned-long-long-int

我正在以UDP数据包的形式从传感器获取数据。手册提供了这些数据包的表格,但是我在理解如何解释时间戳方面遇到困难。它被描述为长度为4个字节的无符号长(例如“ a07245ba”),应被解释为20位整数和12位小数。我也对其中包含的信息“模20位”感到困惑。

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

我尝试使用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])

1 个答案:

答案 0 :(得分:0)

这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。 这似乎相当有限,所以我不确定这是解释“模20位”的正确方法。

另一方面,如果时间戳记表示自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亿,但这完全是人为设计的...