個人で重力異常を測れます、きゃー。
なんて誰が思うんだ、てか。
Android の TYPE_GRAVITY、どうやら重力加速度そのものを測ってるらしい。おぉ、おもしろい。
デバイスの X, Y, Z 軸ごとに測るってことはたぶん:
g = \sqrt{X^2 + Y^2 + Z^2}
\)
でよさげかね? ので:
1 # -*- coding: utf-8 -*-
2 import math
3 from copy import deepcopy
4 from jnius import PythonJavaClass, java_method, autoclass, cast
5 from plyer.platforms.android import activity
6 from kivy.logger import Logger
7
8 Context = autoclass('android.content.Context')
9 Sensor = autoclass('android.hardware.Sensor')
10 SensorManager = autoclass('android.hardware.SensorManager')
11
12 class _SensorListener(PythonJavaClass):
13 __javainterfaces__ = ['android/hardware/SensorEventListener']
14
15 def __init__(self, sensor_manager, sensor_type):
16 super(_SensorListener, self).__init__()
17 self.SensorManager = sensor_manager
18 self.sensor = self.SensorManager.getDefaultSensor(sensor_type)
19 self.values = None
20
21 def enable(self):
22 self.SensorManager.registerListener(self, self.sensor,
23 SensorManager.SENSOR_DELAY_NORMAL)
24
25 def disable(self):
26 self.SensorManager.unregisterListener(self, self.sensor)
27
28 @java_method('(Landroid/hardware/SensorEvent;)V')
29 def onSensorChanged(self, event):
30 self.values = deepcopy(event.values)
31
32 @java_method('(Landroid/hardware/Sensor;I)V')
33 def onAccuracyChanged(self, sensor, accuracy):
34 # Maybe, do something in future?
35 pass
36
37
38 class GravitySensor(object):
39 def __init__(self):
40 self.SensorManager = cast('android.hardware.SensorManager',
41 activity.getSystemService(Context.SENSOR_SERVICE))
42 self._bState = False
43
44 def enable(self):
45 if not self._bState:
46 self._listener = _SensorListener(
47 self.SensorManager, Sensor.TYPE_GRAVITY)
48 self._listener.enable()
49 #
50 self._bState = True
51
52 def disable(self):
53 if self._bState:
54 self._bState = False
55 #
56 self._listener.disable()
57 del self._listener
58
59 @property
60 def values(self):
61 if self._bState and self._listener.values:
62 return self._listener.values[:3]
63
64 @property
65 def abs_value(self):
66 _v = self.values
67 if _v:
68 return math.sqrt(_v[0]**2 + _v[1]**2 + _v[2]**2)
69
70 def __del__(self):
71 if self._bState:
72 self._disable()
73 super(self.__class__, self).__del__()
さて。緯度がわかればいわゆる「正規重力」がわかるわけである。パラメータや近似方法の違いで多少変種はあるけれど、wikipediaでのこれ:
g(\phi)= 9.780327 \left(1+0.0053024\sin^2(\phi) – 0.0000058\sin^2(2 \phi) \right)\;[m/s^2]
\)
でひとまず遊んでみる。(φは緯度ね。) 正規重力と実測値との差が重力異常(Gravity anomaly)。
1 title=Gravity Sensor Demo
2 author=hhsprings
3 orientation=all
1 # -*- coding: utf-8 -*-
2 import math
3 from kivy.lang import Builder
4 from kivy.app import App
5 from kivy.clock import Clock, mainthread
6 from kivy.properties import StringProperty
7 from plyer import gps
8 from gravity_sensor import GravitySensor
9 grav_sensor = GravitySensor()
10
11 kv = '''
12 BoxLayout:
13 RstDocument:
14 id: result
15 text: app.result
16 '''
17 class VariousAltitudeDemo(App):
18 result = StringProperty()
19 lon = None
20 lat = None
21 alt = None
22
23 def build(self):
24 grav_sensor.enable()
25 gps.configure(on_location=self.on_location,
26 on_status=self.on_status)
27 gps.start()
28 Clock.schedule_interval(self.do_interval, 1.)
29 return Builder.load_string(kv)
30
31 @mainthread
32 def on_location(self, **kwargs):
33 #self.lon = float(kwargs['lon'])
34 self.lat = float(kwargs['lat'])
35 #self.alt = float(kwargs['altitude'])
36
37 @mainthread
38 def on_status(self, stype, status):
39 pass
40
41 def do_interval(self, *args, **kwargs):
42 if self.lat is None:
43 return
44
45 g = grav_sensor.abs_value
46
47 # Theoretical gravity (using GRS80)
48 # g(\phi)= 9.780327 \left(1+0.0053024\sin^2(\phi) - 0.0000058\sin^2(2 \phi) \right)\;[\frac{m}{s^2}]
49 gth = 9.780327 * (
50 1.0 + 0.0053024 * math.sin(math.radians(self.lat))**2 - \
51 0.0000058 * math.sin(math.radians(2 * self.lat))**2)
52
53 self.result = """
54 * latitude: {}
55 * observed gravity: {:.6f}
56 * theoretical gravity (using GRS80): {:.6f}
57 * gravity anomaly: {:.6f}
58 """.format(self.lat, g, gth, g - gth)
59
60
61 if __name__ == '__main__':
62 VariousAltitudeDemo().run()
ふーむ、こんなもんか。標準がどのくらいかがあんましわからんしなぁ。
なお、本来は高度も考慮する。Free Air Correction という。地球から離れるほど重力は小さくなることは知ってるよね? この項を加える。Web サービスもあるのでみてみて。
16:30追記:
GGMplus 200m-resolution maps
of Earth’s gravity field. データダウンロードしても使えるみたいだ。ちょっと切れ目が中途半端で使いにくいが東京はこの辺。
ところでこの GGMplus 200m-resolution maps of Earth’s gravity field を紹介している WIRED の説明…。一般人向けなのだから仕方ないのだが、かなり誤解を招くぞ。「しかし、この重力加速度は場所により、以前考えられていた値よりも大きく変化することが、オーストラリアとドイツの共同研究により明らかになった。」と言ってるがこれはあんまりな説明だ。「測った、世界的なグリッドを作った」ことは大きな成果だけれども、重力加速度が場所によって違うことなんぞ、地球科学系を専攻してればはっきりいって常識。当然国土地理院とかも計測して公開しとるぞ。(つーか高校地理で習うでしょ? アイソスタシー…。)
2017-08-07追記:
なんだか読む人が多いようなので、結構前から追記しようと思ってたことを追記しとく。
ちゃんと理解しきれているわけではないが、このセンサー、ひょっとしたら「成分分解してるだけ」の可能性がある。つまり、「重力加速度は定数」としてリポートしてくるのじゃないのか、ということ。だとしたら重力異常を求める目的には全然使えない。まぁ元々「傾き検知」が主たる目的のセンサーだからね、そうだとしても文句は言えまい。