2012年1月1日日曜日

位置情報取得について調べてみた(その1)

Androidに関する位置情報についての下回りをちょっと調べてみようかと思っています。GPSやその他の位置情報取得に関する記事なんてそれこそ山のようにあるため、あえてエントリにする必要もないのですが、自分用メモということで。

位置情報取得というと、すぐに思い浮かぶのはGPSや基地局情報だったりするのですが、現在はそれらの組み合わせや、Wi-Fiの位置データベースを使った方法など、多くの方法が存在するようです。Androidと直接関係が無いものもあるでしょうが、まずは基礎知識を知らなければ駄目でしょうということで調べてみました。まぁ、仕様書を読んだわけではなく、いろいろなサイトを眺めて歩いただけなので、間違いもあるかもしれませんけど。

位置情報取得方法


・GPS測位
複数のGPS衛星から送信されている電波を受信することで、位置を特定する技術です。
GPS衛星からは、2種類のデータが30秒周期で送信されています。
  - アルマナックデータ (すべての衛星の軌道データ)
  - エフェメリスデータ (自身の正確な位置データとこのデータ発送時の正確な時刻データ)
GPS受信機は、初期状態ではアルマナックデータを使い、位置測定に利用できる衛星を確認し、最初のエフェメリスデータの時刻情報で時刻を設定後、次のデータでデータ受信の遅延を計測することで、衛星までの距離を計算します。
これを最低3つの衛星で繰り返すと、三角交差法を使い、経度と緯度を導きだす事ができます。4つの衛星で行えば高度も出せるという仕組みです。。
アルマナックデータはだいたい1週間程度、エフェメリスデータは1時間半程度は有効なため、2つのデータの有効時間中は、時刻情報から距離を割り出すだけで、位置情報を取得できますが、データの存在しない初期処理からの測位では数分、その後の位置情報収集は最低でも30秒程度はかかるようですね。

・DGPS(Differential GPS)
もともとGPSは軍事目的の衛星で、軍用に使う正確な位置を割り出せる暗号データとあえてノイズを含めた若干不正確なGPSデータを送信していたそうです。
このため、一般の利用では、100m程度の誤差がでていたものを補正するために考案された手法で、位置のわかっている地上の基地局との比較で誤差補正を行い制度を高める技術です。

・A-GPS(Assisted GPS)
GPSは、情報の取得を開始してから最低でも30秒程度、最悪数分間は位置を特定できません。また、起動データや位置データの受信は建物内にいるとノイズによりデータ受信は難しく、位置の特定が困難になります。
携帯電話は、例えば基地局情報などで、携帯端末のおおざっぱな位置が特定できています。そこで3G回線等別の経路で全衛星軌道データと、衛星位置情報を取得し、GPSからは比較的ノイズに強い時刻情報だけを取得することで、位置情報をGPSより高速に、建物内でもわりと正確に特定できるようにする技術がA-GPSです。


・セルベース測位
現行の携帯電話は、セル方式というものをとり、無線基地局を多数設置し、ある一定の範囲に留めることで、同じ周波数帯域をできるだけ再利用するように設計されているそうです。セルというのは、無線基地局の電波が届く範囲の事になります。携帯電話に通知を行うために、携帯電話が最後に確認できたセルIDが記録されており、定期的に更新されています。このセルIDを元にどの位置に居るのかを特定するという技術です。
携帯でGPSサービスと言われるものが出始めた初期の頃は、実際にGPS受信をしておらず、このおおよその位置情報を使った機種も多かったようですよね。
位置に関する誤差については、セルの広さによりますので、狭い範囲に設置されている都市部は小さく、田園部とか湾岸部等の場合は誤差が大きくなるようです。

・基地局測位
この辺りからキャリアによっていろいろ変わってたりするようで、いまいちつかめていません。
KDDIでは、3つ以上の基地局との同期信号を使って、位置を計算するようです。GPSの衛星からの時刻データの代わりに、基地局との同期信号を使うことで測定するようですね。
DoCoMoさんでは、基地局に同期された時間情報を持っていないため、何か別の方法で測位しているようですが。
ウィルコムは、アンテナの受信強度等から特定しているような記載をみかけましたし、
ソフトバンクはどうなんだろう。もうちょっと調べてみたいなと思っていますが、とりあえずおいておきましょう。

・Wi-Fiアクセスポイントによる測位
Wi-FiのアクセスポイントのMACアドレスと位置情報のデータベースを使って、現在の位置を特定する方法
ローリングで都市を回り、Wi-Fiのアンテナ情報を一気に収集したものと位置情報をあわせて保持している企業のデータを使って特定するようなので。そういえば、僕のHTC AriaのWi-Fiの位置が、自宅に登録されていそうなんですよね。外出先でAria経由で接続すると自宅に居る事になるし・・・・。


とまぁ、こんなあたりが、ざっと主要な位置情報取得技術となるでしょうか。


Android Frameworkでの実装
さて、ようやく本題のAndroidについてです。
いきなり下回りのコードを読むにもあたりがつかないとならないので、クライアント側でおこなうサンプルをみながら、キーになる所を抜粋してみてみました。

(1) LocationManagerの取得
LocationManager locMgr  = (LocationManager)getSystemService(LOCATION_SERVICE);

(2) 最適なLocationProviderを選択
Criteria criteria = new Criteria();
String provider = locMgr.getBestProvider(criteria, true);

(3) 最後にわかっている位置情報を取得
Location location = locMgr.getLastKnownLocation(provider);

(4) 定期的に位置の変化を取得するためのListner登録

LocationListener listener = new LocationListener() {
    @Override
    public void onLocationChanged(Location location) {
    }

    @Override
    public void onProviderDisabled(String provider) {
    }

    @Override
    public void onProviderEnabled(String provider) {
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
    }
};

long minTime = 15000;
float minDistance = 1.0;
locMge.requestLocationUpdates(provider, minTime, minDistance, listener);

とすると、minTime[msec]以上の間隔で、minDistance[m]以上の変化があれば情報が取得される事になります。


(5) 経度、緯度、高度等の情報から住所情報への変換
Geocoder geocoder = new Geocoder(context, Locale.JAPAN);
List<Address> addressList = geocoder.getFromLocation(latitude, longitude, 5);

(6) GPSの状態取得/衛星情報の取得
GpsStatus gpsStat = locMgr.getGpsStatus(null);
Iterable<GpsSatellite> satellites = gpsStat.getSatellites();

(7) GPSの状態変化イベント取得方法

GpsStatus.Listener statListner = new GpsStatus.Listener() {
    @Override
    public void onGpsStatusChanged(int event) {
        switch(event){
        case GpsStatus.GPS_EVENT_STARTED:
            break;
        case GpsStatus.GPS_EVENT_STOPPED:
            break;
        case GpsStatus.GPS_EVENT_FIRST_FIX:
            break;
        case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
            break;
        }
    }
}
locMgr.addGpsStatusListener(statListner);


とまぁ、位置情報周りの主要なクラスの使い方というのはこんな所でしょうか。

アプリ側は、管理クラス LocationManagerから位置情報を提供するLocationProviderを選択し、Locationを取得するという流れとなっています。ここまで見た感じだと、Frameworkの実装としては、位置情報はGPSに限らずProviderから取得できるように設計されており、アプリケーションは、Criteriaを使ってProviderの条件を取得して、適切なProviderを選択させる事が可能です。もちろん、getBestProvider()を使わずに、providerにLocationManager.GPS_PROVIDERを指定することで、GPSの情報だけを使うようにも実装できるわけですが。

どんなProviderが実装されているのかについては、List<String> getProviders(boolean enabledOnly); を呼び出せば、取得できるようですね。あとで、自分の端末で試してみようかな。

各クラスの詳細やその先の実装はまた次回ということで。

0 件のコメント:

コメントを投稿