garlog改造への道 6

ていうか個人的なメモです。(H13.11.17)



 前回、
>まずは現在のgarlogでどうやって三角関数計算をしているか、解析することから始めることとします。
 なんて書きましたが、gigoさんから
loggerは測地系変換を行う関係でmldnsky.cの中でsin,cos,asin,acos,atan,atan2を、
e_sqrt.cの中でsqrtを実装しています。
 というアドバイスのお陰で、アッサリ解決しました。(^^;

 と、いうことで今回は、前回garlog改造への道5(H13.11.13)で書いた内容をプログラムしてみました。変えるのはcommon.cのみです。

 まず変数の定義からはじめます。
 Cの本を読むと、あるブロック( { }で囲まれた範囲)で宣言された変数は、その中でしか値が保持されないみたいなことが書いてありました。 今回の8方向の速度データなどはそれでは困るので、common.cの冒頭に宣言することにしました。

--------------------------------------------------------------------------------

/* 風向風速計算用のグローバル変数定義 */
static int zoneSpd[8]={0,0,0,0,0,0,0,0}; /* 北、北東、東…の8方向の速度 */
static int windSpd,windDir;		 /* 風速と風向(速度データの全体的なドリフト量) */

--------------------------------------------------------------------------------

 8方向の速度データは配列にしました。
 続いて、風向風速を求めるサブルーチン...いや違った、関数を記述します。
 今まではgigoさんの書いたソースをコピー&ペーストしてちょっと変えるだけだったのですが、今回は一行書くにもCの本を見たり、あちこちのソースを見て似たような部分を探したり... なかなかスムーズに書けないです。

-------------------------------------------------------------------------------

/* 風向風速を求める関数を定義(8方向の速度の和から、全体的なドリフト量を計算) */
static void wind_carc()
{
	int wind_x;		/* 風(全体的なドリフト量)のx成分 */
	int wind_y;		/* 風(全体的なドリフト量)のy成分 */
/* 現在の進行方向に相当する変数に現在速度を代入 */
	if (cnv.iHead>=338 || cnv.iHead<23 ) zoneSpd[0]=cnv.iSpd;
	if (cnv.iHead>=23  && cnv.iHead<68 ) zoneSpd[1]=cnv.iSpd;
	if (cnv.iHead>=68  && cnv.iHead<113) zoneSpd[2]=cnv.iSpd;
	if (cnv.iHead>=113 && cnv.iHead<158) zoneSpd[3]=cnv.iSpd;
	if (cnv.iHead>=158 && cnv.iHead<203) zoneSpd[4]=cnv.iSpd;
	if (cnv.iHead>=203 && cnv.iHead<248) zoneSpd[5]=cnv.iSpd;
	if (cnv.iHead>=248 && cnv.iHead<293) zoneSpd[6]=cnv.iSpd;
	if (cnv.iHead>=293 && cnv.iHead<338) zoneSpd[7]=cnv.iSpd;
/* ドリフト量を出すためベクトル和。小数点以下にならないよう、sin,cosの値は100倍しています */
	wind_x = zoneSpd[0]*100 + zoneSpd[1]*71 + zoneSpd[2]*0 + zoneSpd[3]*-71 +
			 zoneSpd[4]*-100 + zoneSpd[5}*-71 + zoneSpd[6]*0 + zoneSpd[7]*71;
	wind_y = zoneSpd[0]*0 + zoneSpd[1]*71 + zoneSpd[2]*100 + zoneSpd[3]*71 +
			 zoneSpd[4]*0 + zoneSpd[5}*-71 + zoneSpd[6]*-100 + zoneSpd[7]*-71;
/* 風速を√(x^2 + y^2 )で求める。km/s→m/sへ変換するため3.6で割った。 */
/* ただしwindSpdは整数型なので√100^2倍=100倍から10倍相当にするため10で割る */
	windSpd = (int)(sqrt(wind_x*wind_x + wind_y*wind_y)/3.6/10 );
/* 風向を求める。0〜360°表示 */
	windDir = (int)(atan(wind_y / wind_x )/TORAD + 360)%360;
}

-------------------------------------------------------------------------------

 ズラリ並んだif文が超初心者的雰囲気を醸し出していてかなり恥ずかしいですけど、これで肝心の計算部分は書けました。 wind_xとwind_y変数が整数でもいいように、計算時にsin,cosの値を100倍したものを使ってます。
 あとで風速の計算のときに2乗の平方根をとるので風速は実際の100倍になりますので、これを10倍相当にするため10で割ってます。風向のatanの計算式ではx,yの倍数は結果に関係ないので、何もしてません。

 これで目論見では、windSpdに風速m/sが10倍の値で、windDirに風向が0〜360で入るハズです。
 (呼び出される側に戻り値を返すreturnで記述しようとしたけど、戻り値がwindSpdとwindDirの二つあるのでどうしていいかわからなかったので、関数はvoidにしてグローバル変数を使うことにしました。)

 で、軌跡表示画面でこの数字を書きます。garlog改造への道4(H13.11.09)で作ったバージョンの、左下の進行方向部分に2段書きで風向と風速を表示させます。

-------------------------------------------------------------------------------

/* 風向風速を表示 */
			void wind_carc();;	/* 風向風速計算実施 */
			sprintf(msgbuff,"風向 %3d`",windDir);
			text_put_string(0,15,msgbuff);

			sprintf(msgbuff,"風速 %2d.%dm/s",windSpd/10,windSpd%10);
			text_put_string(0,16,msgbuff);

-------------------------------------------------------------------------------

 これでオッケーです。ではコンパイルしてみましょう。
 今回はとりあえずgarlogだけ作ることとして、dmcp_gar.batをダブルクリック!

 あれま〜
 「エラーが多すぎる」と怒られちゃいました。(T_T)

 早速、どこがいけないのか調べていろいろ変えてみるも、エラーは変わらず。

 進捗がないので、とりあえずこのページを作ってみました。(^^;;

 では、また...





 追記 (11/18)

 gigoさんOzekiさん申し訳ありません。大ボケしてました。
 ベクトル和を出す式で、

	wind_x = zoneSpd[0]*100 + zoneSpd[1]*71 + zoneSpd[2]*0 + zoneSpd[3]*-71 +
		 zoneSpd[4]*-100 + zoneSpd[5}*-71 + zoneSpd[6]*0 + zoneSpd[7]*71;
と、 ] でなく } を使っていた部分があったという、単なるsyntax errorでした。(^^;;

 加えてgigoさん自らプログラムに修正(ていうか新規作成^^;?)を加えていただきました。それによると、問題の8つ並んだif文は、

	zoneSpd[((cnv.iHead+23)%360)/45]=cnv.iSpd;
 と、if文も使わずに1行になってました。
 さすがというか当たり前というか、このスマートな式に惚れ惚れしました。

 さらに

	windDir = (int)(atan(wind_y / wind_x )/TORAD + 360)%360;
 を
	windDir = (int)(atan2(wind_x,wind_y )/TORAD + 360)%360;
 にするというアドバイスを頂きました。
 両方ともmldnsky.cに実装されているアークタンジェントを求める関数なのですが、atanの( )内の引数が1個なのに対して、atan2( )は2つの引数を渡します。どこが違うかというと...
 例えば atan(1/1)は45°で、atan(-1/-1)は225°になるハズです。でも( )内はどちらも 1 です。 引数が1個しかない atan( )では、0〜180°までならいいのですが、今回の風向のように360°ぶん計算しなくてはならないとなると、第1象限と第3象限の区別がつきません。
 だから引数が2個ある atan2( ) が必要、というわけです。

 以上を直してコンパイル!
 が、エラー。
 しかしこれは楽勝。後半の風向風速表示部分でwind_carc()を呼び出すとき、

	void wind_carc();	/* 風向風速計算実施 */
 としていたのを、voidを削除したらOKでした。

 今度は見事コンパイル成功。早速Swanに転送してみます。
 が、表示が何か変。
 とりあえずのテストとして、eTrex SummitをDEMOモードにしてgarlogを走らせるのですが、風速表示が0.1m/sとかなのです。
 DEMOモードでは移動速度は20km/hで一直線に進む軌跡なので、風速は20km/h=5.5m/s程度になるハズなのに...
 これはおそらく、Ozekiさんからご指摘いただいた部分、

intを多用していますが、WSは16bitなので、intは-32768から32767の値しか扱えません。
だから掛け算などをするとすぐにオーバーフローします。
(プロでもたまにこれにハマる...)

多分、sqrt(wind_x*wind_x + wind_y*wind_y)あたりはまずいのではないかと思います。

 これが原因だと思われます。
 そこでgigoさんからも頂いたアドバイスに沿って、wind_xとwind_yをint型でなくlong型で宣言することにしました。
 早速GPSのDEMOモードでチェックしてみると.... ウム、いい感じです。

 んがしかし...
現在のプログラム言うところの「風向」は、風によって全体的に流されている方向を示しています。でも「風向」とは、当たり前ですが「風の吹いてくる方向」ですから、180°違う向きを表示させてることになります。大ボケでした。



 続く...(かも)



目次に戻る