#!perl -w
#
# GPSy拡張形式のトラックログから速度加速度計算
# Nowral
# 00/12/23
#
# ファイル毎処理?
use Time::Local;
$tint = 0 + eval( MacPerl::Ask(
"何秒おきに書出しますか? (「0」で、元データと同じ時刻で書出し。)"
, "0") );
die if($tint<0);
# 定数 < グローバル
$pi = 4 * atan2(1, 1); # 円周率
$rd = $pi / 180; # [ラジアン/度]
$g = 9.80665; # 重力加速度 [m/s^2]
# データム諸元 (Tokyo)
$a = 6377397.155; # 赤道半径 [m]
$f = 1 / 299.152813; # 扁平率
$e2 = 2*$f - $f*$f; # 第一離心率
# 出力ファイル準備
$0 =~ /(.+:)/;
$newargv = "$1result.dat";
open(OUT, ">$newargv");
MacPerl::SetFileInfo('ttxt', 'TEXT', $newargv);
# ヘッダ出力
print OUT "経過時間[秒]\t積算距離[km]\t速度[km/h]\t加速度[G]\t方位角[度]\n";
# データ読み込み
$n = 0;
$oldargv = "";
$trn = "";
while (<>) {
next unless(/^T\t/);
@ed = split("\t");
if ($ARGV ne $oldargv || $ed[1] ne $trn) {
&prc_trk(\@t, \@b, \@l, \@h, $n-1) if $n>=2;
$oldargv = $ARGV;
$trn = $ed[1];
$n = 0;
undef @t;
undef @b;
undef @l;
undef @h;
}
# 時刻
$ed[4] =~ /(\d+)\/(\d+)\/(\d+)\s+(\d+):(\d+):(\d+)/;
$t2 = timelocal($6,$5,$4,$2,$1-1,$3-1900);
push(@t, $t2);
# 緯度
$ed[5] =~ /(-?)(\d+)。(\d+)'(\d+\.?\d*)"/;
$b2 = ($1 ? -1 : 1) * ($2+$3/60+$4/3600);
push(@b, $b2);
# 経度
$ed[6] =~ /(-?)(\d+)。(\d+)'(\d+\.?\d*)"/;
$l2 = ($1 ? -1 : 1) * ($2+$3/60+$4/3600);
push(@l, $l2);
# 高さ <>楕円体高?
$h2 = $ed[8];
push(@h, $h2);
++$n;
}
&prc_trk(\@t, \@b, \@l, \@h, $n-1) if $n>=2;
close(OUT);
#MacPerl::Quit(2);
die "The Unhappy End";
sub prc_trk { # 一つながりのトラックを処理
my($tref, $bref, $lref, $href, $n) = @_;
my(@x, @y, @z, @h);
my(@ax, @ay, @az);
my(@sr, $sr, $dr);
my($t0, $t1, $t3, $u, $i);
my($vx1, $vy1, $vz1, $v1);
my($ax1, $ay1, $az1, $a1);
my(@tp, $vmax, $amax, $amin);
my(@t) = @{$tref};
($t0, $t3) = ($t[0], $t[$n]);
$t00 = $t0 unless defined $t00;
$st = $t3 - $t0;
foreach $i (0 .. $n) {
($x[$i], $y[$i], $z[$i])
= &llh2xyz(${$bref}[$i], ${$lref}[$i], ${$href}[$i], $a, $e2);
}
foreach $i (0 .. $n-1) { $h[$i] = $t[$i+1] - $t[$i]; }
@ax = &sp_gen(\@x, \@h, $n);
@ay = &sp_gen(\@y, \@h, $n);
@az = &sp_gen(\@z, \@h, $n);
# 積算距離計算
$sr = 0;
undef @sr;
push(@sr, $sr);
foreach $i (0 .. $n-1) {
$dr = &part_amt(1, $h[$i],
$x[$i], $x[$i+1], $ax[$i], $ax[$i+1],
$y[$i], $y[$i+1], $ay[$i], $ay[$i+1],
$z[$i], $z[$i+1], $az[$i], $az[$i+1]);
$sr += $dr;
push(@sr, $sr);
}
# 書き出し時刻
undef @tp;
if($tint) {
for($t1=$t0; $t1<$t3; $t1+=$tint) { push(@tp, $t1); }
push(@tp, $t3);
}
else { @tp = @t; }
# printf OUT "# 開始時刻 : %s\n", &formd($t0);
#集計
print "\n";
printf "# 元データ数: %d\n", $n+1;
printf "# 出力行数 : %d\n", $#tp+1;
printf "# 開始時刻 : %s\n", &formd($t0);
printf "# 終了時刻 : %s\n", &formd($t3);
printf "# 所要時間 : %d:%02d:%02d\n", int($st/3600), ($st/60)%60, $st%60;
printf "# 総距離 : %.1f [km]\n", $sr/1000;
printf "# 平均速度 : %.1f [km/h]\n", $sr/$st*3.6;
# 書き出しループ
$i = 0;
($vmax, $amax, $amin) = (0, 0, 0);
foreach $t1 (@tp) {
while($t[$i+1]<$t1) { ++$i; }
$u = ($t1-$t[$i]) / $h[$i];
# 積算距離
$dr = &part_amt($u, $h[$i],
$x[$i], $x[$i+1], $ax[$i], $ax[$i+1],
$y[$i], $y[$i+1], $ay[$i], $ay[$i+1],
$z[$i], $z[$i+1], $az[$i], $az[$i+1]);
$sr = $sr[$i] + $dr;
# 速度
$vx1 = &sp_v($u, $h[$i], $x[$i], $x[$i+1], $ax[$i], $ax[$i+1]);
$vy1 = &sp_v($u, $h[$i], $y[$i], $y[$i+1], $ay[$i], $ay[$i+1]);
$vz1 = &sp_v($u, $h[$i], $z[$i], $z[$i+1], $az[$i], $az[$i+1]);
$v1 = &absvec($vx1, $vy1, $vz1);
$vmax = $v1 if $vmax<$v1;
# 加速度
$ax1 = &sp_a($u, $ax[$i], $ax[$i+1]);
$ay1 = &sp_a($u, $ay[$i], $ay[$i+1]);
$az1 = &sp_a($u, $az[$i], $az[$i+1]);
$a1 = &absvec($ax1, $ay1, $az1);
$a1 *= (&inprod($ax1, $ay1, $az1, $vx1, $vy1, $vz1)>0 ? 1 : -1);
$amax = $a1 if $amax<$a1;
$amin = $a1 if $amin>$a1;
# 方位角
$azm = &azimuth($x[$i], $y[$i], $z[$i], $vx1, $vy1, $vz1);
# 書き出し
printf OUT "%d\t%.3f\t%.1f\t%.3f\t%.0f\n",
$t1-$t00, $sr/1000, $v1*3.6, $a1/$g, $azm;
}
print OUT "\n";
#集計
printf "# 最高速度 : %.1f [km/h]\n", $vmax*3.6;
printf "# 最大加速 : %.2f [G]\n", $amax/$g;
printf "# 最大減速 : %.2f [G]\n", -$amin/$g;
print "\n";
return 1;
}
sub formd { # 日付、時刻の表示形式
my($t) = @_;
my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($t);
return sprintf("%d:%02d", $hour, $min);
# return sprintf("%04d/%d/%d %d:%02d:%02d", $year+1900,$mon+1,$mday,$hour,$min,$sec);
}
sub llh2xyz { # 楕円体座標 -> 直交座標
my($b, $l, $h, $a, $e2) = @_;
my($sb, $cb, $rn, $x, $y, $z);
$b *= $rd;
$l *= $rd;
$sb = sin($b);
$cb = cos($b);
$rn = $a / sqrt(1-$e2*$sb*$sb);
$x = ($rn+$h) * $cb * cos($l);
$y = ($rn+$h) * $cb * sin($l);
$z = ($rn*(1-$e2)+$h) * $sb;
($x, $y, $z);
}
sub xyz2llh { # 直交座標 -> 楕円体座標
my($x, $y, $z, $a, $e2) = @_;
my($bda, $p, $t, $st, $ct, $b, $l, $sb, $rn, $h);
$bda = sqrt(1-$e2); # b/a
$p = sqrt($x*$x+$y*$y);
$t = atan2($z, $p*$bda);
$st = sin($t);
$ct = cos($t);
$b = atan2($z+$e2*$a/$bda*$st*$st*$st, $p-$e2*$a*$ct*$ct*$ct);
$l = atan2($y, $x);
$sb = sin($b);
$rn = $a / sqrt(1-$e2*$sb*$sb);
$h = $p/cos($b) - $rn;
($b/$rd, $l/$rd, $h);
}
sub sp_gen { # 3次の自然スプライン決定
my($xref, $href, $n) = @_;
my(@x) = @{$xref};
my(@h) = @{$href};
my(@rho, @tau);
$rho[1] = 0;
$tau[1] = 0;
foreach $i (1 .. $n-1) {
my($di) = 6 * (($x[$i+1]-$x[$i])/$h[$i] - ($x[$i]-$x[$i-1])/$h[$i-1]);
my($fi) = $h[$i-1]*$rho[$i] + 2*$h[$i] + 2*$h[$i-1];
$rho[$i+1] = - $h[$i] / $fi;
$tau[$i+1] = ($di - $h[$i-1]*$tau[$i]) / $fi;
}
undef @x;
undef @h;
my(@a);
$a[$n] = 0;
for($i=$n; $i>0; --$i) { $a[$i-1] = $rho[$i]*$a[$i] + $tau[$i]; }
return @a;
}
sub sp_x { # スプライン関数値の計算
my($u, $hi, $xi, $xip, $ai, $aip) = @_;
my($uu) = 1 - $u;
my($hh6) = $hi * $hi / 6;
return $hh6*$ai*$uu*$uu*$uu + $hh6*$aip*$u*$u*$u
+ ($xi-$hh6*$ai)*$uu + ($xip-$hh6*$aip)*$u;
}
sub sp_v { # スプライン関数一階微分値の計算
my($u, $hi, $xi, $xip, $ai, $aip) = @_;
my($uu) = 1 - $u;
return - $ai*$hi/2*$uu*$uu + $aip*$hi/2*$u*$u
+ ($xip-$xi)/$hi - $hi/6*($aip-$ai);
}
sub sp_a { # スプライン関数二階微分値の計算
my($u, $ai, $aip) = @_;
return $ai*(1-$u) + $aip*$u;
}
sub dldt { # 速度の絶対値 <> 単位時間あたりに進む距離
my($u, $hi,
$xi, $xip, $axi, $axip,
$yi, $yip, $ayi, $ayip,
$zi, $zip, $azi, $azip) = @_;
my($vx, $vy, $vz);
$vx = &sp_v($u, $hi, $xi, $xip, $axi, $axip);
$vy = &sp_v($u, $hi, $yi, $yip, $ayi, $ayip);
$vz = &sp_v($u, $hi, $zi, $zip, $azi, $azip);
return sqrt($vx*$vx + $vy*$vy + $vz*$vz);
}
sub part_amt { # i区間におけるパラメタuまでの積算
my($u, $hi,
$xi, $xip, $axi, $axip,
$yi, $yip, $ayi, $ayip,
$zi, $zip, $azi, $azip) = @_;
my($sr, $m, $k);
$m = $u * $hi;
$sr = &dldt(0, $hi, $xi, $xip, $axi, $axip, $yi, $yip, $ayi, $ayip, $zi, $zip, $azi, $azip);
for($k=1; $k<$m; ++$k) {
$sr += 2 * &dldt($k/$hi, $hi, $xi, $xip, $axi, $axip, $yi, $yip, $ayi, $ayip, $zi, $zip, $azi, $azip);
$sr += 4 * &dldt($k/$hi-0.5, $hi, $xi, $xip, $axi, $axip, $yi, $yip, $ayi, $ayip, $zi, $zip, $azi, $azip);
}
$k--;
$m -= $k;
$sr += ($m-1) * &dldt($k/$hi, $hi, $xi, $xip, $axi, $axip, $yi, $yip, $ayi, $ayip, $zi, $zip, $azi, $azip);
$sr += 4 * $m * &dldt(($k+$m/2)/$hi, $hi, $xi, $xip, $axi, $axip, $yi, $yip, $ayi, $ayip, $zi, $zip, $azi, $azip);
$sr += $m * &dldt($u, $hi, $xi, $xip, $axi, $axip, $yi, $yip, $ayi, $ayip, $zi, $zip, $azi, $azip);
return $sr/6;
}
sub azimuth { # 方位角計算
my($x, $y, $z, $vx, $vy, $vz) = @_;
# 法線ベクトル
my($b, $l, $h) = &xyz2llh($x, $y, $z, $a, $e2);
$b *= $rd;
$l *= $rd;
my($nx, $ny, $nz) = (cos($b)*cos($l), cos($b)*sin($l), sin($b));
# 速度ベクトルの地平面射影
my($vpx, $vpy, $vpz) = &outprod($nx, $ny, $nz, $vx, $vy, $vz);
# 北極ベクトルの地平面射影
my($ppx, $ppy, $ppz) = &outprod($nx, $ny, $nz, 0, 0, 1);
# 方位角
my($ax, $ay, $az) = &outprod($ppx, $ppy, $ppz, $vpx, $vpy, $vpz);
my($a1) = (&inprod($ax, $ay, $az, $nx, $ny, $nz)>0 ? -1 : 1) * # 北から時計回り
atan2(&absvec($ax, $ay, $az), &inprod($ppx, $ppy, $ppz, $vpx, $vpy, $vpz));
$a1 += 2*$pi if $a1<0;
return $a1/$rd;
}
sub absvec { # ベクトルの絶対値
my($ax, $ay, $az) = @_;
return sqrt($ax*$ax + $ay*$ay + $az*$az);
}
sub inprod { # ベクトルの内積
my($ax, $ay, $az, $bx, $by, $bz) = @_;
return $ax*$bx + $ay*$by + $az*$bz;
}
sub outprod { # ベクトルの外積
my($ax, $ay, $az, $bx, $by, $bz) = @_;
return ($ay*$bz-$az*$by, $az*$bx-$ax*$bz, $ax*$by-$ay*$bx);
}