Matlab
Script for parsing CSI
parseFeitCSI.m
%{
Function which parse FeitCSI data.
usage: parseFeitCSI("path/to/FeitCSI/file")
returned data structure sample:
[
{
header: {
"csi_size":416,
"ftm_clock":144084200,
"timestamp":1701251234567890,
"num_rx":2,
"num_tx":1,
"num_subcarriers":52,
"rssi1":67,
"rssi2":68,
"source_mac":(0, 7, 14, 124, 232, 48),
"source_mac_string":"00:07:0e:7c:e8:30",
"rate_flags":49415,
"rate_format":"LEGACY_OFDM",
"channel_width":"20",
"mcs":7,
"antenna_a":true,
"antenna_b":true,
"ldpc":false,
"ss":1,
"beamforming":false
},
data: complex matrix[num_subcarriers, num_rx, num_tx]
},
{
header: ...,
data: ...
},
...
]
%}
function output = parseFeitCSI(fileName)
RATE_MCS_MOD_TYPE_POS = uint32(8);
RATE_MCS_MOD_TYPE_MSK = bitshift(uint32(0x7), RATE_MCS_MOD_TYPE_POS);
RATE_MCS_CCK_MSK = bitshift(uint32(0), RATE_MCS_MOD_TYPE_POS);
RATE_MCS_LEGACY_OFDM_MSK = bitshift(uint32(1), RATE_MCS_MOD_TYPE_POS);
RATE_MCS_HT_MSK = bitshift(uint32(2), RATE_MCS_MOD_TYPE_POS);
RATE_MCS_VHT_MSK = bitshift(uint32(3), RATE_MCS_MOD_TYPE_POS);
RATE_MCS_HE_MSK = bitshift(uint32(4), RATE_MCS_MOD_TYPE_POS);
RATE_MCS_EHT_MSK = bitshift(uint32(5), RATE_MCS_MOD_TYPE_POS);
RATE_MCS_CHAN_WIDTH_POS = uint32(11);
RATE_MCS_CHAN_WIDTH_MSK = bitshift(uint32(0x7), RATE_MCS_CHAN_WIDTH_POS);
RATE_MCS_CHAN_WIDTH_20_VAL = uint32(0);
RATE_MCS_CHAN_WIDTH_20 = bitshift(RATE_MCS_CHAN_WIDTH_20_VAL, RATE_MCS_CHAN_WIDTH_POS);
RATE_MCS_CHAN_WIDTH_40_VAL = uint32(1);
RATE_MCS_CHAN_WIDTH_40 = bitshift(RATE_MCS_CHAN_WIDTH_40_VAL, RATE_MCS_CHAN_WIDTH_POS);
RATE_MCS_CHAN_WIDTH_80_VAL = uint32(2);
RATE_MCS_CHAN_WIDTH_80 = bitshift(RATE_MCS_CHAN_WIDTH_80_VAL, RATE_MCS_CHAN_WIDTH_POS);
RATE_MCS_CHAN_WIDTH_160_VAL = uint32(3);
RATE_MCS_CHAN_WIDTH_160 = bitshift(RATE_MCS_CHAN_WIDTH_160_VAL, RATE_MCS_CHAN_WIDTH_POS);
RATE_MCS_CHAN_WIDTH_320_VAL = uint32(4);
RATE_MCS_CHAN_WIDTH_320 = bitshift(RATE_MCS_CHAN_WIDTH_320_VAL, RATE_MCS_CHAN_WIDTH_POS);
RATE_HT_MCS_CODE_MSK = uint32(7);
RATE_MCS_ANT_A_POS = uint32(14);
RATE_MCS_ANT_A_MSK = bitshift(uint32(1), RATE_MCS_ANT_A_POS);
RATE_MCS_ANT_B_POS = uint32(15);
RATE_MCS_ANT_B_MSK = bitshift(uint32(1), RATE_MCS_ANT_B_POS);
RATE_MCS_LDPC_POS = uint32(16);
RATE_MCS_LDPC_MSK = bitshift(uint32(1), RATE_MCS_LDPC_POS);
RATE_MCS_SS_POS = uint32(16);
RATE_MCS_SS_MSK = bitshift(uint32(1), RATE_MCS_SS_POS);
RATE_MCS_BEAMF_POS = uint32(16);
RATE_MCS_BEAMF_MSK = bitshift(uint32(1), RATE_MCS_BEAMF_POS);
function header = parseHeader(data)
header = {};
header.csi_size = typecast(data(1:4), 'uint32');
header.ftm_clock = typecast(data(9:12), 'uint32');
header.timestamp = typecast(data(13:20), 'uint64');
header.num_rx = data(47);
header.num_tx = data(48);
header.num_subcarriers = typecast(data(53:56), 'uint32');
header.rssi1 = typecast(data(61:64), 'uint32');
header.rssi2 = typecast(data(65:68), 'uint32');
header.source_mac = data(69:74);
header.source_mac_string = sprintf('%02x:%02x:%02x:%02x:%02x:%02x', header.source_mac);
header.rate_flags = typecast(data(93:96), 'uint32');
rate_format = bitand(header.rate_flags, RATE_MCS_MOD_TYPE_MSK);
if rate_format == RATE_MCS_CCK_MSK
rate_format = 'CCK';
elseif rate_format == RATE_MCS_LEGACY_OFDM_MSK
rate_format = 'LEGACY_OFDM';
elseif rate_format == RATE_MCS_VHT_MSK
rate_format = 'VHT';
elseif rate_format == RATE_MCS_HT_MSK
rate_format = 'HT';
elseif rate_format == RATE_MCS_HE_MSK
rate_format = 'HE';
elseif rate_format == RATE_MCS_EHT_MSK
rate_format = 'EHT';
else
rate_format = 'unknown';
end
header.rate_format = rate_format;
channel_width = bitand(header.rate_flags, RATE_MCS_CHAN_WIDTH_MSK);
if channel_width == RATE_MCS_CHAN_WIDTH_20
channel_width = '20';
elseif channel_width == RATE_MCS_CHAN_WIDTH_40
channel_width = '40';
elseif channel_width == RATE_MCS_CHAN_WIDTH_80
channel_width = '80';
elseif channel_width == RATE_MCS_CHAN_WIDTH_160
channel_width = '160';
elseif channel_width == RATE_MCS_CHAN_WIDTH_320
channel_width = '320';
else
channel_width = 'unknown';
end
header.channel_width = channel_width;
header.mcs = bitand(header.rate_flags, RATE_HT_MCS_CODE_MSK);
if bitand(header.rate_flags, RATE_MCS_ANT_A_MSK)
header.antenna_a = true;
else
header.antenna_a = false;
end
if bitand(header.rate_flags, RATE_MCS_ANT_B_MSK)
header.antenna_b = true;
else
header.antenna_b = false;
end
if bitand(header.rate_flags, RATE_MCS_LDPC_MSK)
header.ldpc = true;
else
header.ldpc = false;
end
if bitand(header.rate_flags, RATE_MCS_SS_MSK)
header.ss = 2;
else
header.ss = 1;
end
if bitand(header.rate_flags, RATE_MCS_BEAMF_MSK)
header.beamforming = true;
else
header.beamforming = false;
end
end
function csi_matrix = parseCsiData(data, header)
csi_matrix = zeros(header.num_subcarriers, header.num_rx, header.num_tx);
csi_matrix = complex(csi_matrix ,0);
pos = 1;
for j = 1:header.num_rx
for k = 1:header.num_tx
for n = 1:header.num_subcarriers
real = typecast(data(pos:pos + 1), 'int16');
imag = typecast(data(pos + 2:pos + 3), 'int16');
pos = pos + 4;
csi_matrix(n, j, k) = complex(real, imag);
end
end
end
end
f = fopen(fileName);
fileContent = uint8(fread(f));
step = 1;
index = 1;
while length(fileContent) > step
data = {};
data.header = parseHeader(fileContent(step:step + 271));
step = step + 272;
data.csi_matrix = parseCsiData(fileContent(step:step+data.header.csi_size - 1), data.header);
step = step + data.header.csi_size;
output(index ) = data;
index = index + 1;
end
end
Script for parsing FTM
parseFeitCSIftm.m
%{
Function which parse FeitCSI FTM data.
usage: parseFeitCSIftm("path/to/FeitCSI/ftm/file")
returned data structure sample:
[
{
"burstIndex": 123,
"numFtmrAttempts": 123,
"numFtmrSuccesses": 123,
"numBurstsExp": 123,
"burstDuration": 123,
"ftmsPerBurst": 123,
"rssiAvg": 123,
"rssiSpread": 123,
"rttAvg": 123,
"rttVariance": 123,
"rttSpread": 123,
"distAvg": 123,
"distVariance": 123,
"distSpread": 123,
"timestamp": 123,
},
{
FTM data...
},
...
]
%}
function output = parseFeitCSIftm(fileName)
function ftmData = parseFtmData(data)
ftmData = {};
ftmData.burstIndex = typecast(data(1:4), 'uint32');
ftmData.numFtmrAttempts = typecast(data(5:8), 'uint32');
ftmData.numFtmrSuccesses = typecast(data(9:12), 'uint32');
ftmData.numBurstsExp = typecast(data(13:16), 'uint32');
ftmData.burstDuration = typecast(data(17), 'uint8');
ftmData.ftmsPerBurst = typecast(data(18), 'uint8');
ftmData.rssiAvg = typecast(data(19), 'uint8');
ftmData.rssiSpread = typecast(data(20:23), 'uint32');
ftmData.rttAvg = typecast(data(24:31), 'uint64');
ftmData.rttVariance = typecast(data(32:39), 'uint64');
ftmData.rttSpread = typecast(data(40:47), 'uint64');
ftmData.distAvg = typecast(data(48:55), 'uint64');
ftmData.distVariance = typecast(data(56:63), 'uint64');
ftmData.distSpread = typecast(data(64:71), 'uint64');
ftmData.timestamp = typecast(data(72:79), 'uint64');
end
f = fopen(fileName);
fileContent = uint8(fread(f));
step = 1;
index = 1;
while length(fileContent) > step
ftmData = parseFtmData(fileContent(step:step + 78));
step = step + 79;
output(index) = ftmData;
index = index + 1;
end
end