iOS8の高度計(気圧計)
iOS8の高度計(気圧計)
iPhone6 Plus および iPhone6には、気圧計が入っています。
今どき気圧計は高精度で、気圧の値の変化から、1メートル程度の高さの変化が十分にわかります。これがあると、例えば、ユーザが今ビルの何階にいるかがわかるわけです。
サンプルコードはこんな感じ。
1秒に1回の頻度で、気圧値が更新されて通知されてきます。相対高度(relativeAltitude)は、前回の通知から今回の通知までの高度の変化分を通知しています。今の実装は、おそらく、単純に気圧値の差分に定数をかけるとか、そんな感じなのかもしれません。
更新頻度を指定する方法は、今のところないみたい。
ハードウェから見ると、iPhone6の分解 http://www.techinsights.com/teardown.com/apple-iphone-6/ から、センサは Bosch Sensortec BMP280 Barometric Sensor。
仕様を見ると、動作範囲(full accuracy) 300 ~ 1100 hPa、平均測定時間 5.5ミリ秒、分解能0.01 hPa (< 10cm)、温度 0.1度、絶対精度(950 ~ 1050 hPa) +- 1hPa、相対精度 +ー0.12 hPa (高さ+ー1m相当)。 (1hPa(ヘクトパスカル) は 100パスカル。)
センサの仕様から、今の振る舞いは、ほぼセンサの値をそのまま利用する単純な実装をしているのかな、と思いました。

Githubのサンプルアプリ。 https://github.com/reinforce-lab/ObjC_Codes/tree/master/barometer
ここの気圧と高度の計算式で、標高ゼロメートル、温度27度(絶対温度で300K)のときに、1mあたりの気圧の変化は、11パスカル。

アプリの値の変化を見ていると、たしかにそれっぽい感じで、とれている。
ソースコード
@interface ViewController () {
CMAltimeter *_altimater;
bool _isFirstSample;
double _currentValue;
double _averageValue;
double _altitudValue;
}
@property (weak, nonatomic) IBOutlet UILabel *currentValueTextLabel;
@property (weak, nonatomic) IBOutlet UILabel *averageValueTextLabel;
@property (weak, nonatomic) IBOutlet UILabel *variationValueTextLabel;
@property (weak, nonatomic) IBOutlet UILabel *warningTextLabel;
@property (weak, nonatomic) IBOutlet UILabel *altitudeValueTextLabel;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_isFirstSample = YES;
self.warningTextLabel.hidden = [CMAltimeter isRelativeAltitudeAvailable];
if([CMAltimeter isRelativeAltitudeAvailable]) {
_altimater = [[CMAltimeter alloc] init];
[_altimater startRelativeAltitudeUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMAltitudeData *data, NSError *error) {
[self altitudeDataHandlr:data error:error];
}];
}
}
-(void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[_altimater stopRelativeAltitudeUpdates];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)altitudeDataHandlr:(CMAltitudeData *)data error:(NSError *)error {
if(error != nil) return;
double altitude = [[data relativeAltitude] doubleValue];
double pressure = [[data pressure] doubleValue];
_currentValue = pressure;
_altitudValue = altitude;
if(_isFirstSample) {
_averageValue = pressure;
} else {
_averageValue = 0.1 * _currentValue + (1 - 0.1) * _averageValue;
}
_isFirstSample = NO;
self.currentValueTextLabel.text = [NSString stringWithFormat:@"%1.5e", _currentValue];
self.averageValueTextLabel.text = [NSString stringWithFormat:@"%1.5e", _averageValue];
self.altitudeValueTextLabel.text = [NSString stringWithFormat:@"%1.3e", _altitudValue];
}