この記事の内容
- (前の記事で紹介)VSCodeのHexEditorを利用したバイナリデータの概要把握
- (この記事で紹介)MATLABでバイナリデータからtable形式への変換
MATLABを使ったデータの読みこみ
前記事に書いた、VSCodeのHexEditorで確認すると改行を示す「0D 0A」がいくつか並んでいる。
そこで読み込みにはMATLABのfgetl
を用いて1行ずつ読み込んでいき、ヘッダー部分の行数分で終了するプログラムを書いた。下記のように少し工夫することでtableのヘッダー風に読み込むことができた。
clear all; clc;
filename = 'DBOX_004.DBN';
%% バイナリファイルオープン
fid = fopen(filename,'r');
% ヘッダー部分読み込み
m = 1;n = 1;
for i = 1:40 a = fgetl(fid); if isempty(a) == 1 m = m+1; n = 1; else n = n+1; end A{m,n} = a;
end
Aという変数はセル配列になり、中身このようになる。
これで、ヘッダー部分を読み込むことができたようだ。
ヘッダーに書いてあるSAT(1)
という表記だが、SATは受信している衛星の数という意味で、()内は数値データのByte数を示していると想定している。衛星は1Byte,時間は3Byte,,,というように一回の記録で何Byte分あるのか確かめてみると、36Byteあるようだ。
データの形は既に想定できているので、MATLABのfread
を使って数値データの部分をいっきに読み込み、後から形を整えるようにプログラムしてみた。
fread
で読み込み、reshape
で整え、衛生が受信できていない不要なデータ行を削除後、各データのByte数分を16進数の形で取り出す。その後、10進数に戻して必要な乗数を掛けている。この辺りの処理は冗長な感じが否めないので、この道のプロならおそらくもっといい方法を知っているのではないかと想像する。
必要な乗数はどこにも書いてなかったので、WindowsPCを借りて標準解析ツールより出力したCSVデータと見比べることで確かめました。本末転倒感。笑
num_byte = 36;
% データ部分読み込み
B = uint8(fread(fid));
% ベクトルを行列に変換
nd = length(B);
num_data = length(B)/num_byte;
C = reshape(B,[num_byte,num_data])';
% 衛星を受信できてないデータ行の取得
idx_nonGPS = C(:,2) = 1 | C(:,2) >= 15;
% tableに変換
D = array2table(C);
% 衛星を受信できてないデータの削除
D(idx_nonGPS,:) = [];
% 16進数で必要なバイト数分選択
time = hex2dec([dec2hex(D.C3),dec2hex(D.C3),dec2hex(D.C3)])*10;
lat = [dec2hex(D.C6),dec2hex(D.C7),dec2hex(D.C8),dec2hex(D.C9)];
lon = [dec2hex(D.C10),dec2hex(D.C11),dec2hex(D.C12),dec2hex(D.C13)];
vel = [dec2hex(D.C14),dec2hex(D.C15),dec2hex(D.C16)];
heading = [dec2hex(D.C17),dec2hex(D.C18)];
height = [dec2hex(D.C19),dec2hex(D.C20),dec2hex(D.C21),dec2hex(D.C22)];
vert_sp = [dec2hex(D.C23),dec2hex(D.C24)];
yaw_1 = [dec2hex(D.C25),dec2hex(D.C26)];
yaw_2 = [dec2hex(D.C27),dec2hex(D.C28)];
yaw_calc = [dec2hex(D.C29),dec2hex(D.C30)];
slip = [dec2hex(D.C31),dec2hex(D.C32)];
checksum = [dec2hex(D.C33),dec2hex(D.C34)];
% 10進数への変換と、データへの単位変換
E.sat = D.C2;
E.time = duration(milliseconds(time)+hours(9),'Format','hh:mm:ss.SSS');
E.lat_10 = hex2dec(lat)/60*10^-5;
E.lon_10 = hex2dec(lon)/60*10^-5;
E.vel_kmph = hex2dec(vel)*10^-2;
E.heading_deg = hex2dec(heading)*10^-2;
E.height_m = hex2dec(height)*10^-2;
E.vert_sp_mps = hex2dec(int16(vert_sp))*10^-2;
E.vert_sp_mps(E.vert_sp_mps > 600) = E.vert_sp_mps(E.vert_sp_mps > 600,:) - 655.35;
E.vert_sp_mps = E.vert_sp_mps*3.6;
E.yaw_2_degps = hex2dec(yaw_1)*10^-2;
E.yaw_1_degps = hex2dec(yaw_2)*10^-2;
E.yaw_calc = hex2dec(yaw_calc)*10^-2;
E.slip_deg = hex2dec(slip);
E.checksum = hex2dec(checksum);
% tableへ変換
E = struct2table(E);
以上、DriftBoxのバイナリデータを読み解けた。
MATLABのgeoscatter
を使って走行軌跡を確認すると、しっかり当時走行した場所を示していた。これで自分のMacBookAirでもDriftBoxのデータを解析できるようになった。