CSI 数据二进制文件探究

Author Avatar
Xin Qiu Jan 25, 2018
  • Read this article on other device

考研一年多没有看相关的东西,现在又要重新拾起之前的知识,作为开始,从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的相关文档可以详细了解其构成)。

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 变量来做的。

后续工作

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