2017年4月30日日曜日

2次元の外積と内積

 2次元でも外積とか言うのか知らないけど。


 2次元で3個の頂点を決めて三角形を作った場合の外積と内積のサンプル。乱数で頂点を生成してるので見苦しいのはご容赦を。

 おおよその考え方として、内積(ドット積)は2本の線がどれくらい開いているか(閉じているか)を示している。原点を基準として、2本の線が同じ方向に伸びていれば+1となり、逆方向に伸びていれば-1となる(ただし正規化(2本のベクトルの長さの積で割る)をしない場合はややこしい数字になる)。同じ方向で+1、逆方向で-1なので、acosに入れれば同じ方向で0、逆方向で180となり、どれくらい線が開いているかという値になる。

 外積(クロス積)は、基本的に3次元で使われて、頂点で示される面の向きを計算するのに使うのだが、2次元に当てはめると面がどっちを向いているかが得られる。他に、面の面積も得られるのだが。
 今回の計算方法では、頂点が時計回りなら外積は正の値、頂点が左回りなら外積は負の値、という風になっている。


 最近になって、いろいろ数字をいじくり回す必要に迫られて、いろいろ苦労してるので、ちゃんと勉強しておけばよかったなぁとか思ったり。いや、お前の場合はそれ以前だろ、というツッコミはさておき。


2017年4月28日金曜日

JSOrbitのbug fix

 またまた、JS Orbitを更新しました。内容はいくつかのバグフィックスその他です。

 まず、先日追加したautopaddの問題で地図をクリックしても正常に衛星が選択されない問題。
 内部的な話になりますが、以前はpaddingに対して値を書いていました。しかしその影響でうまく動作しなくなっていました。正しくはmarginに対して値を書くべきだったようです。ということで、オプションはautopaddだけど実際はautomargin、みたいなややこしいことになっています。

 次に、自分でも忘れていたようなマイナーな?機能に関連した修正です。
 これは、地図上でマウスをクリックしたままドラッグすると、その範囲の矩形に含まれる衛星が非表示になる、という機能です。
 これについては地図の大きさを変えると計算が不正になるので、相当昔からあったバグだと思います。自分でも忘れていた機能なので、当然動作チェックも行われていませんでした。

 後は影響がない範囲での修正(正しく言えば重複した処理の削除)を行いました。といっても目についた1箇所だけですが。

 あと、全然更新していない更新履歴を削除しました。
 自分でいつ何を変更したのかを知りたくて更新履歴を書いていましたが、去年末あたりからgitで管理するようになったので、更新履歴が更新されていませんでした。いちいち更新するのも面倒というかなんというか。


 とりあえず、こんなところです。

2017年4月27日木曜日

JSOrbit 画面の中央に地図を表示する

 JS Orbit、怒涛の更新ラッシュですね。計画性の無さがなせる技です。


 地図を画面の上下中央に表示するモードを追加しました。wmw=windowと同様、GUIで設定することはできないので、URLにautopaddオプションを追加して読み込んでください。いちおーURLバーでJavaScriptコードを叩けば設定できますが、当然非推奨です。

 JS Orbit: http://www13.plala.or.jp/rian/jsOrbit/?wmw=window&autopadd

 正距円筒図法で展開された世界地図は横2対縦1の大きさになるわけですが、FullHDの解像度では横16対縦9、であり、期待される横16対縦8よりも僅かに縦が大きいです。ということでブラウザのフルスクリーン表示とかにした場合、地図が若干上に寄って表示されてしまいます。
 「ウチで作った衛星はこのあたりにいるんだよ!」みたいな展示とか、衛星軌道を表示して悦に入りたい場合とか、地図が寄ったり、細々とした文字表示があると邪魔な場合は、autopaddで地図のみを表示することができます。日照状態も表示できるようになりましたから、衛星運用チームででっかいスクリーンに表示したりとかして使ったりもどうぞ?


 そういえば、JS Orbitで使用している計算方法で本当に正しい位置を表示できてるのか不明でしたが、ジンバルで衛星をトラッキングするヤツもほとんど同様のソースコードを使用していますから、方位仰角でせいぜい数度の誤差に収まっているのかな、という感じです。

 切った張ったでだいぶラーメンコード化してますから、いろいろ整理したいなぁ(って言うの、何回目だろう)。

 ここ最近のブログエントリ、真面目に書きすぎてると思うので、そろそろネタに走ったエントリも書かないとなぁ。

JSOrbitで地上の日照も気にするモード


 すでに衛星の日照に応じて表示するモードはありますが、地上の日照も考慮に入れたモードを追加しました。SunLight TLで表示できます。
 このモードでは、観測点から見た太陽の中心が仰角0度以下、かつ衛星から見た太陽の中心が仰角0度以上、くらいのところでオレンジ色、それ以外(地上から太陽が0度以上or衛星から太陽が0度以下)では茶色に表示されます。
 僕の脳内モデルがかなり怪しいので、本当に正しい表示になっているかはわかりません。いちおう、JAXAの計算ページで衛星の日照が始まる時間と、JS Orbitで日照が始まる時間が、だいたい一致しているので、まぁ大丈夫かなーという気がします。

 一般的に、「星が見える暗さ」というのは、日没からかなり後です。おおよそ6等星が見えるのは太陽の俯角が12度以降かららしいです。
 ただ、ISSはかなり明るいのと、プログラムを作り込むのが面倒なので、太陽中心の仰角が0度以下ということにしています。ISSよりも暗い衛星の場合は、JS Orbit上では見えていても、実際には見えない場合もあります。といっても、肉眼で充分に見える衛星ってそもそもがそんなに多くないし、ロケットの残骸とか見ても面白くないと思うので、とりあえず現状のままで良いかなと思っています。

 太陽の位置を計算する際、時刻のタイムゾーンを使用して観測値の補正を行っているわけですが、現在のところ、時間設定で"now"ボタンを押すと、UTCでの時刻が設定されます。Manual modeで時間を設定する場合は、明確にUTC+9:0を設定してください。
 なお、Real timeではコンピューターに設定されたタイムゾーンを使用しています。
 「俺はグローバルな人間だ!だから日本にいようとグリニッジ時間を使っているぜ!」みたいな人は、残念ですがManual modeでお願いします。
 もしかしたら夏時間や冬時間も何らかの影響があるかもしれませんが、日本ではそのような時間運用はされていないので、確認はしていません。



 以降どうでもいい話です。
 ぐろーばるすたんだーどでは、可読性の低いソースコードはスパゲティコードと呼ばれています。これは「プログラムがスパゲティのように複雑に絡み合っている」という状態なわけですが、我々からすれば、絡み合っている食べ物といえば、ラーメンの縮れ麺のほうがごちゃごちゃしていると思います。それに濁点や半濁点を含むスパゲティより、それらを含まないラーメンのほうが発音しやすく、字数や音数も少なくて済みます。ということで、ラーメンコードを推していこうと思います。あ、でも発音しやすいとスルッと流れるきれいなコードっぽさが出ちゃうからダメか。。

2017年4月26日水曜日

C#のListViewの継承

 ListViewを右クリックした時の挙動をちょっと改造してみた。

 右クリックされた時はまずMouseDownRightButtonイベントを呼ぶ。
 次に、CheckFocusedItemの状態に応じ、falseならContextMenuStripを表示、falseならマウスカーソルが選択中のアイテムの上にあるときだけContextMenuStripを表示する。
 また右クリックはMouseDownRightButtonの呼び出しと、ConextMenuStripを表示することのみに使われ、それ以外の処理は行われない。つまり、右クリックで選択が解除されたりということは行われない。
 かなり端折った実装なので、まぁ、こういうこともできますよー程度に。

 ContextMenuStripのOpenedハンドラのsenderにはContextMenuStripが渡されるが、その中のSourceControlに右クリックされたListViewが渡される。ListViewのFocusedItemに選択中のListViewItemが入っている。

 ListViewItemに応じて使用するContextMenuStripを変更したい場合は、MouseDownRightButtonハンドラの中で各自実装したりという感じになると思う。

 もうちょっと色々作り込みたいところだけど、やる気が続かない。

public class ListViewRightButton : ListView
{
    public bool CheckFocusedItem { get; set; }

    protected override void WndProc(ref Message m)
    {
        const int WM_RBUTTONUP = 0x0205;
        const int WM_RBUTTONDOWN = 0x0204;

        if (m.Msg == WM_RBUTTONUP || m.Msg == WM_RBUTTONDOWN)
        {
            Point Client = PointToClient(Cursor.Position);

            MouseDownRightButton?.Invoke(this, new MouseEventArgs(MouseButtons.Right, 0, Client.X, Client.Y, 0));

            if (!CheckFocusedItem)
            {
                ContextMenuStrip?.Show(this, Client.X, Client.Y);
            }
            else if (FocusedItem != null && FocusedItem.Bounds.Contains(Client))
            {
                ContextMenuStrip?.Show(this, Client.X, Client.Y);
            }
        }
        else
        {
            base.WndProc(ref m);
        }
    }

    public event MouseEventHandler MouseDownRightButton;
}

2017年4月25日火曜日

ジンバル

 ここ何週間か、ステッピングモータでジンバルを組んでいます。確かWebカメラとかと同じ頃にモーター類も届いてるので、ブログエントリの日付を信用するなら3週間目くらいでしょうか。
 やっと、ちゃんと目標を追尾したりとかできるようになってきました。


 上の動画ではロケットボディ(宇宙ゴミ)をトラッキングしています。高度はおよそ450kmくらいですから、国際宇宙ステーションと同じくらいの速度です。ロケットよりISSのほうが遥かに大きいでしょうから、ロケットが見えるならISSも見えるはずです(今はタイミングが悪くてISSが日没後に飛んでこないのですが)。


 今のところ、方位仰角を手動設定、緯度経度高度を手動設定、恒星の追尾、飛行機の追尾、衛星の追尾、ができるようになっています。
 恒星はほとんど静止目標なので、まぁ捕捉できて当然と言うか。
 衛星と飛行機は大体同じような角速度ですが、衛星は計算で位置がわかるのでかなり高精度に追尾できます。相互の位置のズレや、軸のズレによって誤差が発生しますが、直上でもない限りはちゃんと追尾できます。
 飛行機はADS-Bを使用しているのですが、受信状態が悪いのか、位置情報が間欠でしか降りてきません。でも一応目標を捉えることはできています。夜中とか、真っ暗な画面の中で衝突防止灯がピカピカしていて、しかも翼端灯等は常時点灯ですから、まるっきりUFO映像です。
 追尾の難易度としては、一番簡単なのが恒星、ちょっとむずかしくなって衛星、かなり難しくなって飛行機、という感じです。飛行機を高精度に追尾したければ、位置予測を行った上で画像認識で追尾、という感じになると思います。

 見ての通りかなり小規模なので、せいぜいがWebカメラやウェアラブルカメラ程度まででしょうが、位置情報を追尾できるので、XBee等で自分の位置をGPSで転送すれば、自撮りカメラみたいにも使えます。この分野だと市販品ではSOLOSHOT2あたりでしょうか。
 ハードウェアは結構簡単ですし、制御回路もマイコン1個とモータードライバ基板2個で作れます。オープンソースプロジェクトみたいにしたら、だれかフレームとか設計してくれないかなーとか思ったり。でもドローンが流行ってる昨今、こういう追尾カメラとかのプロジェクトも有るんだろうなぁ。

 当初の目標は、35mm換算2mくらいの望遠鏡を自動で振ってISSを撮りたいと思ってたんですが、換算260mmくらいで点みたいなロケットボディを撮っただけでも結構満足してしまいました。次の目標をしっかりと探しておかないと、いつものようにあっという間に失速しそうです。

2017年4月24日月曜日

JS Orbitで日照を表示


 日照といっても、地上の話ではなく。衛星が太陽に照らされているはずの部分はオレンジで、地球の影に入っているはずの時は茶色で表示するようになっています。configのorbit lineからSunLightを設定すれば表示できます。

 この表示はかなり端折った計算です。
 まず太陽は無限遠にある無限小とし、地球は完全な球体と想定、衛星は無限小です。また、計算間隔は1分毎で、移動速度に対してかなり離散的です。
 おそらく大きく外しているわけではないと思いますが、ほんとに正しいかはわかりません。あくまで、目安程度にお願いします。

2017年4月23日日曜日

SAO星カタログ


なんとなく星を扱いたい気分だったので、SAOカタログを読み込んで表示するやつをC#で作ってみた。
 画面上が北、下が南、右が西、という星座盤みたいな感じで、中央下半分あたり、真南仰角45度くらいのところにオリオン座が有る。僕は全く星を見ない人間なので、オリオン座しか見つけられなかった。肉眼ならもっと見えるのに。

 さすがに生のSAOカタログはデカくて、ロードに2.4秒くらいかかる。不要なデータは解析しなければ良いのだろうけど、それもなんだか。
 今回は単純に赤緯赤経から計算しているだけなので、固有運動とかは計算していない。

 SAOカタログは正式にはスミソニアン天文台星表と言うらしいのだが、「ネット上で入手できる」とアチコチに書いてある割に、どこから入手できるかはどこにも書いてない。結局、SAOカタログのwikipediaの英語ページから外部リンクに有るNASAの圧縮データを引っ張ってきた。

 星の位置を計算したりするならSAOカタログで充分なのだけど、星座盤みたいなのを作ろうとすると星と星をつなぐリストが必要になる。そういうのってどこに有るんだろうか。あと天球を分割する継ぎ目とか。 

 スタートラッカーとか作ってみたいけど、あれってどういう計算をやってるんだろう。

2017年4月20日木曜日

C#: 文字列を数字とそれ以外で区切る


 ということをやりたかったので、つくってみた。
 こういうのは正規表現とかで使うと柔軟にできるんだろうけど、面倒くさいそこまで高機能なの必用じゃなかったので。
 数字(0-9)の連続を1グループとして、それ以外の部分も1グループとして、分割して返してくれる。数字しか識別しないので、空白で区切りとかはされない。もちろん数字と数字の間に空白があれば区切られるけど。

 いつもの通り、使うときは自己責任で。

2017年4月19日水曜日

レーザープロジェクター(みたいな名状しがたいナニカ)


 最近、こういうモノを作っています↑

 見ての通り、ステッピングモータでジンバル作ってWebカメラを乗っけてるだけですが。

 で、せっかく方位仰角を制御できるので、撮影だけじゃなくてもっと遊びたいということで、レーザーポインターを載せてみました。


 上は8秒で1周、下は2秒で1周です。
 レーザープロジェクターとして使うには致命的に遅いですが、カメラとかいろいろ重量物が乗っててモーメントが大きいのであんまり早くできません。
 ステッピングモータの軸に鏡を付けてガルバノミラーみたいなふうにすればかなり高速化できるんでしょうが。

 モーターの制御はPIDで行っています。現在でもかなりPを大きくしてIは小さいはずなんですが、それでもそれなりにオーバーシュートしてしまいます。と思っていたんですが、この写真を見る感じ、もうちょっと素早く立ち上げても良いかもしれませんね。

 レーザーポインターを載せたのはただ面白そうだというだけではなく、オーバーシュートとかアンダーシュートを見れるように、という狙いがあります。

 ということで、ブログに書くほどでもない細々した作業ばっかりの今日このごろでしたが、とりあえずネタになりそうな気がしたので久しぶりにブログを書いた次第。
 カメラジンバルを作っていろいろ制御するネタをブログに書いておけば、あと数年くらいしてキリト君がこのブログを見つけて明日奈の肩に乗れると思うと、俄然やる気が出ますね(って思っておかないと続かないくらいにはモチベーションが低いです)。


 追記
 ちょっとパラメータをいじってみました。
1周2秒です。若干発振していますが、上の画像と比べて四角形に近づいています。



 矩形を表示した時の様子です。1枚目は下から立ち上げて左右のパルス、2枚目は左から動いて上下のパルスです。
 上下方向はほとんど発振も見られず、かなり綺麗です。対して、左右方向はかなり発振しており、汚い線になっています。
 これは、上下方向はカメラ(+レーザーポインタ)の重さしか無く、回転軸と重心がかなり近いところにあるのと、左右方向はさらにステッピングモータの重さが加わり、さらに重心と回転軸が離れているために慣性モーメントが大きくなっているためだと思われます。
 PIDパラメータやモーターの加速度を最適化すればもっと良くなるのかもしれませんが、そもそもここまでの高速域で使う予定はないので、とりあえず今回はこの程度で許してやります。//次は覚えてろよッ!

 おそらく、肩の上に載せて使うような状況では、シェイクリダクションはモーターで全体を振っては間に合わないはずで、必要に応じて画素自体を動かしたり、少し広角気味に撮影してトリミングでSRを行ったり、といった感じになるんだと思います。これからますます高解像度機材が充実していくでしょうから、広角で撮影しておいてトリミングでSRというのはアリだと思います。それにVRの追従性はハードウェア(モーターの強化)ではなく、ソフトウェア(広めで撮ってトリミング)で対応するのが楽なはずです。
 でも実際に肩に載せるならRICOH Thetaあたりになるんだろうなぁ。

 あと何週間かすれば暖かくなってくるでしょうから、そうなれば屋外で色々撮影できます。ADS-Bから飛行機をトラッキングしたり、TLEから人工衛星をトラッキングしたり。ISSならWebカメラでも充分に撮影できるはずですし、イリジウムフレアとかも面白いかもしれません。

2017年4月7日金曜日

Webカメラ的なモノを買ってみた


 ガワの無い、その割に普通のWebカメラと比べても特別安いわけでもない、どっかの横流しみたいなWebカメラを買ってみました。それと、焦点距離35mmのCマウントレンズと、Cマウント-12mm変換アダプタも買いました。
 ちゃんと計算したわけじゃないですが、およそ35mm換算で250mmとかそれくらいじゃないかなーという気がします。かなり狭角ですね。


 画面から90cmほどのところからキャプチャした画像です。90cmでこの範囲しか撮れないんですから、相当に狭角です。3mほど離れた壁を撮っても、数センチ角程度しか撮影できません。

 フレームレートはQQVGAで33fpsくらい、VGAで33fpsくらい、SVGAで18fpsくらい、FHDで22fpsくらいでした。本来はフレームサイズに反比例してフレームレートが変わるはずですが、SVGAはFHDよりもフレームレートが低いという結果でした。何か重い変換処理が行われているのかもしれません。およそVGAが最高fpsで、QVGAやQQVGAにするメリットはありません。もっとも、PCに入ってからの処理はデータ量が少ないに越したことはないので、QQVGAで足りるならQQVGAに設定するべきですが。
 一般的なWebカメラと違い、低照度でもフレームレートが低下しないのが便利かもしれません。とはいえ、もちろん照度を上げればシャッタースピードが遅くなり、照度を最大にすればフレームレートも5fps程度まで低下します。とはいえ明るい環境なら20fps程度は出ますし、解像度によってはさらに高FPSも得られるので、遊びで画像解析程度なら使えると思います。


 UVCでOpenCVから叩けるカメラって、かなり少なくて、実質的にはWebカメラ程度しかありません。他にはファクトリーオートメーション向けのカメラがありますが、Webカメラより1-2桁高価です。
 今回買ったメーカーでは同じように基板剥き出しのWebカメラを、画素やレンズの組み合わせで色々な種類で売っていますが、自前で光学系を用意するなら、分解する手間もかからず、ネジ穴等もちゃんとついてるので、画像認識とかに向いている気がします。意外と基板も綺麗なので、基板剥き出しから感じる粗悪な感じはありません。本当に良いものかはわかりませんが。
 むしろ、一緒に買ったレンズの方がパッケージが汚れていたりして、あぁ、安物ってこういうのだよなぁ、という感じです。


2017年4月3日月曜日

軌道のグラフ化

 このネタも久しぶりですね。ISS放出物体のグラフ化を行いました。


 およそ2016年10月頃から2017年3月末頃までの、軌道長半径のプロットです。
 個人的にアーカイブしているデータは、17年1月中頃までは1日に1回、それ以降は1日に2回のデータを保存していますが、実際にはTLEの更新は数日置きに行われたりするので、そんなにデータ量は多くはありません。
 とはいえ、6ヶ月間でおよそ70物体、データ数にして1万以上のTLEデータがあります。
 さすがにこの量になると、TLEの解析からグラフ化までをExcelで自動的に行うのは無理があるようです。解析等はそんなに大変ではなく、待ち時間さえ許容すれば今の数倍程度までは問題ないはずです。しかし、データの出力方法が悪いので、グラフ化の処理に失敗しています。折れ線グラフにするにあたり、衛星数xデータ数のマトリクスを生成し、そこからグラフ化しているのですが、現状で70万くらいのマトリクスになっています。もうちょっとスマートな方法があると楽なんですが、別アプリでグラフ化する必要があるのかなぁ。


 さて、愚痴っててもしょうがないので、ちょっとだけデータのおさらいをしましょう。縦軸は地心からの距離、横軸は時間で、それぞれ単位はkmと日です。縦軸の下端はおおよそ地表の位置、上端は上空500kmあたりです。横軸は20日/div 4日/divの目盛りになっています。日数は固定ですが、カレンダーの仕様上わかりずらいですね。このあたりの文句は歴代権力者に言ってもらうとして。

 グラフの一番上に常にいる濃い青の線はISS本体です。たまにリブーストしたりして高度を維持しています。
 その他の物体はすべてキューブサットなどです。
 濃い赤の、比較的なだらかな線を描き、17年3月上旬に再突入したのは、SPINSATという、かなり重くて球体な衛星です。重量がある、プラス、球体で空気抵抗が少ない、という物体のため、ISS放出衛星のなかではかなり長生きしていました。
 その他の衛星でも、キューブサットの大きさによって落下速度は変わりますが、1月末あたりにものすごい速度で落下している物体があります。これがFREEDOMで、膜展開により素早くDeOrbit(軌道離脱)しているのがよくわかります。

 おおよそ、300kmを下回ると加速度的に落下しているのがわかります。飛行機が飛べるのはおおよそ10kmまでで、それ以上は空気が薄くて大変ですが、小型衛星から見ると300km未満は空気が濃すぎて長生きできません。
 また、傾向として200kmを下回ると軌道追尾が終了しているようですね。


 こう言っては何ですが、キューブサットは結構あっさりと落ちてくるので、高度のプロットを見るのは面白いと思います。軌道を維持できる衛星はずーっと直線ですからね。