CSI 数据二进制文件探究

考研一年多没有看相关的东西,现在又要重新拾起之前的知识,作为开始,从CSI数据角度切入,探寻之前一直忽略的内容。也是为了用Python来慢慢替代MATLAB。

分批读取

在仔细阅读了 csitools 中的 read_bfee.cread_bf_file.m 文件,慢慢理解数据是如何储存的。

read_bf_file.m 可知,读取数据是分批次进行的,每个批次又去调用 read_bfee 这个函数将二进制数据转化为需要的数据。首先在每个批次的开始是有一个验证码,来检查数据是否可靠,然后再判断数据的长度是否对齐,之后才会进行数据解码。

数据解码

原始数据是二进制的数据块,需要通过解码来得到相应的数据。这个数据块里首先是个 unsigned long 的时间戳,接着是 bfee_countNrxNtxrssi_arssi_brssi_cnoiseagcantenna_selpermlengthfake_rate_n_flags 和最关键的 CSI 原始数据。 关于这些变量,在我之前的文章里有详细介绍。取数据比较麻烦的是要知道不同变量的类型以及其字节位数。其中CSI是有实部和虚部构成,它们都是 unsigned char 类型,这一步的转换用 Python 来转型让我思考了好久。csi 其实是 beamforming matrix(通过查阅802.11n的相关文档可以详细了解其构成)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
def read_bfee(buffer):
# print buffer
timestamp_low = buffer.read('uintne:32')
# print timestamp_low
bfee_count = buffer.read('uintne:32')
# print bfee_count
Nrx = buffer.read('intbe:8')
# print Nrx
Ntx = buffer.read('intbe:8')
# print Ntx
rssi_a = buffer.read('intbe:8')
# print rssi_a
rssi_b = buffer.read('intbe:8')
# print rssi_b
rssi_c = buffer.read('intbe:8')
# print rssi_c
noise = buffer.read('intbe:8')
# print noise
agc = buffer.read('intbe:8')
# print agc
antenna_sel = buffer.read('intbe:8')
# print antenna_sel
perm = [((antenna_sel) & 0x3) + 1,((antenna_sel >> 2) & 0x3) + 1,((antenna_sel >> 4) & 0x3) + 1]
# print perm
length = buffer.read('intle:16')
# print length
fake_rate_n_flags = buffer.read('intle:16')
# print fake_rate_n_flags
index = 0

csiR = []
csiI = []
payload = ''.join(map(str,map(int,buffer[160:])))
payload = map(lambda x:int(x,base=2),[payload[i:i+8] for i in range(0, len(payload), 8)])

for i in xrange(30):
index += 3
remainder = index % 8
for j in xrange(Nrx*Ntx):
t = int(bin(payload[index / 8] >> remainder), 2) | int(bin(payload[index / 8 + 1] << (8 - remainder))[2:].zfill(8)[-8:], 2)
tmp = t - 256 if t > 127 else t
csiR.append(tmp)
t = (payload[index / 8 + 1] >> remainder) | int(bin(payload[index / 8 + 2] << (8 - remainder))[2:].zfill(8)[-8:], 2)
tmp = t - 256 if t > 127 else t
csiI.append(tmp)
index += 16

以上是 read_bfee 的简单demo,函数的返回值可以自定。在一般的研究中,只需要获取 csi 的原始值即可。当然,查询天线的排列可以通过检查 perm 变量来做的。

后续工作

  • 数据转储
  • 性能调优
  • 封装成函数