为了解决这个问题,我花了太多时间研究 Apple 文档。
获取磁力计数据的三种方式
1/ Core Motion框架
CMMotionManagers的CMMagnetometer
类
2/核心运动框架
CMDeviceMotion CMCalibratedMagneticField
属性
3/核心位置框架
CLLocationManager的CLHeading
1/ 提供来自磁力计的“原始”数据。
2/ 和 3/ 返回“派生”数据。两种情况下的数字相似(尽管不完全相同)。
Core Motion 的 CMMagnetometer 和 CMCalibratedMagneticField 的区别
1/ 和 2/ - 都来自 Core Motion 框架 - 不同之处如下:
CMDeviceMotion 类参考
@property(readonly, nonatomic) CMCalibratedMagneticField magneticField
讨论
此属性返回的 CMCalibratedMagneticField 为您提供了设备附近的总磁场,没有设备偏差。与 CMMagnetometer 类的磁场属性不同,这些值反映了地球磁场加上周围磁场,减去设备偏置。
CMMagnetometer 给我们原始数据,CMCalibratedMagneticField 是调整后的数据。
Core Motion 的 CMCalibratedMagneticField 和 Core Location 的 CLHeading 的区别
文档并不清楚 2/ 和 3/ 之间的区别,但它们确实生成了不同的数字,所以让我们进行一些挖掘……。
核心位置框架
CLHeading
来自位置感知编程指南
获取与标题相关的事件
在包含磁力计的设备上运行的应用程序可以使用航向事件。磁力计测量从地球发出的附近磁场,并使用它们来确定设备的精确方向。尽管磁力计可能会受到局部磁场的影响,例如来自音频扬声器、电机和许多其他类型电子设备中的固定磁铁的磁场,但 Core Location 足够智能,可以过滤掉随设备移动的磁场。
以下是相关CLHeading
的“原始”属性
@property(readonly, nonatomic) CLHeadingComponentValue x
@property(readonly, nonatomic) CLHeadingComponentValue y
@property(readonly, nonatomic) CLHeadingComponentValue z
[x|y|z] 轴的地磁数据(以微特斯拉计)。(只读)
此值表示 [x|y|z] 轴与设备正在跟踪的磁力线的偏差。(旧版本的文档添加:)此属性报告的值被标准化为 -128 到 +128 的范围。
我不清楚如何将微特斯拉测量值“标准化”(压缩?剪裁?)到 +/-128 的范围内,并且仍然代表它声称要测量的单位。也许这就是从文档中删除该句子的原因。iPad mini 上的单位似乎确实符合这种范围,但 iPhone4S 提供更高范围的CMMagnetometer读数,例如 200-500。
API 显然希望您使用派生属性:
@property(readonly, nonatomic) CLLocationDirection magneticHeading
@property(readonly, nonatomic) CLLocationDirection trueHeading
它以度为单位提供稳定的 N/SE/W 罗盘读数(0 = 北,180 = 南等)。对于真航向,需要其他核心定位服务(地理定位)来获得磁与真北的偏差。
这是CLHeading
头文件的一个片段
/*
* CLHeading
*
* Discussion:
* Represents a vector pointing to magnetic North constructed from
* axis component values x, y, and z. An accuracy of the heading
* calculation is also provided along with timestamp information.
*
* x|y|z
* Discussion:
* Returns a raw value for the geomagnetism measured in the [x|y|z]-axis.
核心运动框架
CMDeviceMotion CMCalibratedMagneticField
/*
* magneticField
*
* Discussion:
* Returns the magnetic field vector with respect to the device for devices with a magnetometer.
* Note that this is the total magnetic field in the device's vicinity without device
* bias (Earth's magnetic field plus surrounding fields, without device bias),
* unlike CMMagnetometerData magneticField.
*/
@property(readonly, nonatomic) CMCalibratedMagneticField magneticField NS_AVAILABLE(NA,5_0);
CM磁力计
* magneticField
*
* Discussion:
* Returns the magnetic field measured by the magnetometer. Note
* that this is the total magnetic field observed by the device which
* is equal to the Earth's geomagnetic field plus bias introduced
* from the device itself and its surroundings.
*/
@property(readonly, nonatomic) CMMagneticField magneticField;
CMMagneticField
这是保存向量的结构。
的CMDeviceMotion
校准磁场和CMMagnetometer
未校准的版本相同:
/* CMMagneticField - used in
* CMDeviceMotion.magneticField.field
* CMMagnetometerData.magneticField
*
* Discussion:
* A structure containing 3-axis magnetometer data.
*
* Fields:
* x:
* X-axis magnetic field in microteslas.
* y:
* Y-axis magnetic field in microteslas.
* z:
* Z-axis magnetic field in microteslas.
这里暗示了 2/ 和 3/ 之间的区别:
核心位置CLHeading
表示由轴分量值 x、y 和 z 构成的指向磁北的向量
核心位置足够智能,可以过滤掉随设备移动的字段
Core Motion CM校准磁场
[表示] 地球磁场加上周围磁场,没有设备偏差
所以 - 根据文档 - 我们有:
1/ CMMagnetometer
来自磁力计的原始读数
2/ CMDeviceMotion (CMCalibratedMagneticField*) 磁场
磁力计读数针对设备偏差进行了校正(板载磁场)
3/ CLHeading [x|y|z]
磁力计读数针对设备偏差进行了校正,并经过过滤以消除局部外部磁场(通过设备移动检测到 - 如果磁场随设备移动,则忽略它;否则测量它)
测试理论
我在 gitHub 上放了一个 Magnet-O-Meter 演示应用程序,它显示了其中一些差异。当应用程序运行并观察各种 API 的反应时,在您的设备周围挥动磁铁非常有启发性:
CMMagnetometer对任何东西都没有太大反应,除非你拉近稀土磁铁。机载磁场似乎比局部外部磁场或地球磁场重要得多。在我的 iPhone 4S 上,它始终指向设备的左下角;在 iPad mini 上,它通常指向右上角。
CLHeading.[x|y|z] 对本地外部场最脆弱(响应),无论是相对于设备移动还是静态。
(CMDevice)CMCalibratedMagneticField在面对变化的外部场时是最稳定的,但在其他方面它的核心位置对应物CLHeading.[x|y|z]非常接近。
CLHeading.magneticHeading - Apple 推荐的磁罗盘读数 - 比任何这些都稳定。它使用来自其他传感器的数据来稳定磁力计数据。但是你没有得到 x,y,z 的原始分解
influenced by
onboard fields local external fields earth's field
yellow X X X
green _ X X
blue _ _ X
red _ _ X
黄色CMMagnetometer
绿色CLHeading .[x|y|z]
蓝色CMCalibratedMagneticField
红色CLHeading.magneticHeading
这似乎与文档相矛盾,这表明CLHeading.[x|y|z]应该比CMCalibratedMagneticField受本地外部场的影响更小。
你应该采取什么方法?根据我有限的测试,我建议……<br>
如果您想要一个罗盘读数
CLHeading 的magneticHeading
,trueHeading
它将为您提供最准确和最稳定的罗盘读数。
如果您需要避免核心位置,
CMDeviceMotionCMCalibratedMagneticField
似乎是下一个最理想的位置,尽管它的稳定性和准确性远不如magneticHeading
.
如果您对局部磁场感兴趣,
CLHeading 的“原始”xy 和 z 属性似乎对局部磁场更敏感。
如果您想要包括板载磁场在内的所有数据
来自 CMMagnetometer 的原始磁力计数据。除非您准备进行大量过滤,否则使用它实际上没有多大意义,因为它受到设备本身产生的磁场的巨大影响。