MATLABを用いた異なるサンプリング時間のデータの同期
はじめに
複数センサのログデータを解析するとき等,異なるデータの時間軸を合わせたいときがある.
その際にデータの時間軸を同期して解析しやすくなる方法について記載する.
背景と状況例
例えば,センサーAとセンサーBによりデータが取得される場合において,サンプリング時間は
ここで,
さらに,実際のログデータはサンプリング時間通りにぴったりとれているとは限らず,ブレがある.
これらを考慮して,ログデータを用いて解析や計算するプログラムを作成するのは面倒である.
そこで,あらかじめそれぞれのデータの時間軸を合わせておき,解析時間に合わせてサンプリング時間を調整する.
結論
MATLABでログデータをtimetableにし,synchronize関数を用いると簡単にできる.
使用例
移動ロボットのデータセットで使われているUTIAS Multi-Robot Cooperative Localization and Mapping Datasetを対象に処理をする.
ftpでdownloadになるので,ダウンロード先[ftp://asrl3.utias.utoronto.ca/MRCLAM/]をエクスプローラのアドレス欄に入力したらファイルにアクセスできる(windowsの場合).
なお,時間補間するスクリプトが公式で置いているけど,あまりスマートじゃない印象…
datasetのload
データの中身の詳細は公式ページの中身を参照していただきたいが,Dataset1
のRobot1
のOdometryとGround truthのデータを同期させる対象にする.
importdata
でファイル名を指定してデータをロードするとtextとdataの二種類が含まれるので,.data
でデータを読み出す.
datasetFolder="./MRCLAM_Dataset1";
robotNumber = "Robot1";
% truth data
groundtruth = importdata(strcat(datasetFolder,"/",robotNumber,"_Groundtruth.dat"))
groundtruth = groundtruth.data;
% odometry data
odometry = importdata(strcat(datasetFolder,"/",robotNumber,"_Odometry.dat"));
odometry = odometry.data;
次に,データを使いやすいようにtimetableに変換する.
時間軸はduration配列にする必要があるのでseconds()
で変換し,そのほかの変数名はVariableNames
で指定する.
なお,groundTruthはモーションキャプチャによる二次元上の位置(
groundtruthTime = seconds(groundtruth(:,1)); %duration配列にする
groundtruthTable = array2timetable(groundtruth(:,2:4),'RowTimes',groundtruthTime,'VariableNames',{'X','Y','Theta'})
odometryTime = seconds(odometry(:,1)); %duration配列にする
odometryTable = array2timetable(odometry(:,2:3),'RowTimes',odometryTime,'VariableNames',{'Vel','AngVel'})
サンプリング時間の確認
サンプリング時間を確認してみる.
各行の時間とその前の時間の差分をとり,プロットしてみる.
Ground truthデータの場合
plot(groundtruthTime(2:end)-groundtruthTime(1:end-1),'b')
xlim([30000 31000])
Odometryデータの場合
plot(odometryTime(2:end)-odometryTime(1:end-1),'r')
xlim([30000 31000])
これらより,どちらのデータにおいてもサンプリング時間の間隔が一定でないことがわかる.
データの結合とリサンプリング
二つのデータの結合をする.
1行目で結合しており,オプションを何も指定しない場合は欠損値はNaNになるため,前の値を保持するようprevious
を指定する.
また,上記の補間をした後でも最初の方はNaNが存在するため(Ground truthの方が開始時間が早く,Odometryはしばらくデータがない),rmmissing()
でNaNがある行を削除する.
この処理を2行目で行っている.
syncTable = synchronize(groundtruthTable,odometryTable,'union','previous'); %tableの結合し,欠損値は直前の値を保持.
syncTable = rmmissing(syncTable); %NaNの行を削除
syncTable.Time = syncTable.Time-syncTable.Time(1) %スタート時間を0にする
これにより下記のようなtimetableが得られる.
Timeの列を見てもわかるとおり,サンプリング時間の間隔は一定ではない.
そこで,サンプリング時間を
これにはretime()
を用いる.
dt = seconds(0.01);
syncTableRetime = retime(syncTable,'regular','previous','TimeStep',dt)
下記のようなtimetableが得られる.
特に0.05秒と0.06秒の間を見比べると,欲しい出力になっていることがわかる.
これにより,複数のデータの時間軸を同期することができ,使いやすくなった.
なお,retime関数ではサンプリング時間の指定だけではなく,サンプリング周期で指定したり,時間配列を作成してそれに合わせたサンプリングも行えるので,状況に応じてoptionを使用できる.
おわりに
実質数行でデータの時間同期できてMATLAB便利.
Discussion