【问题标题】:CLLocationManager responsivenessCLLocationManager 响应能力
【发布时间】:2012-04-02 13:14:10
【问题描述】:

我有一个应用程序,它围绕设备的 GPS 和来自它的信息。位置数据准确和最新是很重要的。我知道该设备受到其 GPS 和 GPS 限制的限制,但我想知道是否可以做任何事情来调整/提高 iPhone GPS 的性能,特别是在速度方面。由于位置更新比设备的实时位置滞后约 3-5 秒,因此位置管理器报告的速度也远远落后于实时值。就我而言,这太长了。我知道我可能无能为力,但是有没有人在提高 iPhone GPS 的响应能力方面取得了任何成功?每一点都会有所不同。

编辑 1:

按照 Apple 的建议,我的位置管理器位于单例类中。

SingletonDataController.m 内部:

static CLLocationManager* locationManager;
locationManager = [CLLocationManager new];
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.headingFilter = kCLHeadingFilterNone;

if(([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateCharging) || ([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateFull)) {
    locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
} else {
    locationManager.desiredAccuracy = kCLLocationAccuracyBest;
}

[sharedSingleton setLocationManager:locationManager];
[locationManager release];

在 MapView.m 内部(实际使用位置管理器的地方):

- (id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil {
    //setup
    [SingletonDataController sharedSingleton].locationManager.delegate = self;
    //more setup
}

- (void)batteryChanged {
    if(([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateCharging) || ([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateFull)) {
        [SingletonDataController sharedSingleton].locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
    } else {
        [SingletonDataController sharedSingleton].locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    }
}

- (void)viewDidLoad {
    //setup
    [[NSNotificationCenter defaultCenter]
      addObserver:self 
         selector:@selector(batteryChanged) 
             name:UIDeviceBatteryStateDidChangeNotification 
           object:nil];
    //other setup
}

数据处理发生在locationManager:didUpdateToLocation:fromLocation: 内部。我不认为这里的低效率是滞后的原因。

locationManager:didUpdateToLocation:fromLocation: 调用此方法更新 UI:

- (void)setLabels:(CLLocation*)newLocation fromOldLocation:(CLLocation*)oldLocation {
    //set speed label
    if(iterations > 0) {
        if(currentSpeed > keyStopSpeedFilter) {
            if(isFollowing) {
                [mapViewGlobal setRegion:MKCoordinateRegionMake([newLocation coordinate], mapViewGlobal.region.span)];
            }

            NSString* currentSpeedString;
            if(isCustomary) {
                currentSpeedString = [[NSString alloc] initWithFormat:@"%.1f miles per hour", (currentSpeed * 2.23693629f)];
            } else {
                currentSpeedString = [[NSString alloc] initWithFormat:@"%.1f km per hour", (currentSpeed * 3.6f)];
            }

            [speedLabel setText:currentSpeedString];
            [currentSpeedString release];
        } else {
            speedLabel.text = @"Not moving";
        }
    }

    //set average speed label
    if(iterations > 4 && movementIterations > 2) {
        NSString* averageSpeedString;
        if(isCustomary) {
            averageSpeedString = [[NSString alloc] initWithFormat:@"%.1f miles per hour", (float)((speedAverages / (long double)movementIterations) * 2.23693629f)];
        } else {
            averageSpeedString = [[NSString alloc] initWithFormat:@"%.1f km per hour", (float)((speedAverages / (long double)movementIterations) * 3.6f)];
        }
        [averageSpeedLabel setText:averageSpeedString];
        [averageSpeedString release];
    }

    //set elapsed time label
    NSInteger seconds = [[NSDate date] timeIntervalSinceDate:dataObject.locationManagerStartDate];
    NSInteger minutes = seconds / 60;
    NSInteger hours = minutes / 60;

    //get remainder
    seconds %= 60;

    NSString* timeString;
    NSString* secondsString;
    NSString* minutesString;
    NSString* hoursString;

    if((seconds % 60) < 10) {
        secondsString = [[NSString alloc] initWithFormat:@"0%i", seconds];
    } else {
        secondsString = [[NSString alloc] initWithFormat:@"%i", seconds];
    }

    if((minutes % 60) < 10) {
        minutesString = [[NSString alloc] initWithFormat:@"0%i", minutes];
    } else {
        minutesString = [[NSString alloc] initWithFormat:@"%i", minutes];
    }

    if((hours % 60) < 10) {
        hoursString = [[NSString alloc] initWithFormat:@"0%i", hours];
    } else {
        hoursString = [[NSString alloc] initWithFormat:@"%i", hours];
    }

    timeString = [[NSString alloc] initWithFormat:@"%@:%@:%@", hoursString, minutesString, secondsString];

    [elapsedTimeLabel setText:timeString];

    [timeString release], timeString = nil;
    [secondsString release], secondsString = nil;
    [minutesString release], minutesString = nil;
    [hoursString release], hoursString = nil;

    NSString* totalDistanceString;
    if(isCustomary) {
        totalDistanceString = [[NSString alloc] initWithFormat:@"Total: %.2f mi", (float)distance * 0.000621371192f];
    } else {
        totalDistanceString = [[NSString alloc] initWithFormat:@"Total: %.2f km", (float)distance / 1000.0f];
    }
    [customTopBar setTitle:totalDistanceString];
    [totalDistanceString release];
}

通过几个 NSDates 和 NSLogs,我发现在我的 iPhone 4 上执行整个locationManager:didUpdateToLocation:fromLocation:(不仅仅是标签更新方法)不会超过大约 8 毫秒;换句话说,数据处理不是问题。

【问题讨论】:

  • 向我们展示您如何获取位置数据。这种滞后是不正常的。
  • 添加了代码。如果需要,我可以发布更多内容。
  • 3-5 秒可能有点夸张;已经很晚了,范围 3-5 出于某种原因突然出现在我的脑海中。明天我将进行一些测试以获得确切的数字。
  • 没什么奇怪的。你在 locationManager:didUpdateToLocation:fromLocation: 中做什么,你是如何确定它滞后的?
  • 抱歉,我无法解决延迟问题。但我认为您可以使用 @"%02i" 简化 secondsString/minutesString/hoursString 购买的初始化,以自动格式化前导 0 的数字,而无需显式测试 "

标签: ios performance gps core-location cllocationmanager


【解决方案1】:

好的,有几件事可以改善您的延迟。首先,始终使用 kCLLocationAccuracyBestForNavigation。这与 kCLLocationAccuracyBest 之间没有真正的电池使用差异,它们都以最高速度使用 GPS。主要区别在于Apple所做的后处理。

其次,无需过滤速度 == 0。Apple 已经进行了过滤:如果您从 GPS 获得的速度下降到某个阈值(约 4 公里/小时)以下,操作系统会假定您静止不动,它为所有后续样本替换相同的位置值。它会这样做,直到它认为你再次移动。我认为他们这样做是为了避免在您静止不动时在地图上“抖动”。事实上,对于一系列“静止”值的最后一个实际值,速度已经下降到 0,因此如果您根据速度 == 0 进行过滤,那么您将丢失一个真正的 GPS 样本。

不幸的是,他们无法避免过滤并获得真正的 GPS 样本。我和苹果谈过这件事,他们的回答是他们不会改变这种行为。 kCLLocationAccuracyBestForNavigation 的过滤不如 kCLLocationAccuracyBest 激进,因此最好使用它。

第三,您可能已经在执行此操作,但请确保您从“didUpdateFromLocation:”开始在您的视图上调用“setNeedsDisplay”,以确保地图实际上已重新绘制。

如果你做了所有这些,你应该有大约 1 秒的延迟。如果您想在 1 秒内有所改进,则可以尝试使用预测技术。根据最后两个位置和给定的速度,您可以计算下一个位置可能在哪里,并且已经显示该位置。我的结果好坏参半。它适用于不会突然改变速度的快速运动,例如驾驶汽车。对于步行或骑自行车等较慢的运动,它的效果较差。

【讨论】:

  • 非常感谢kCLLocationAccuracyBestForNavigation 真的帮助了我。位置委托方法现在运行得更快了:)
  • @fishinear ActivityType 是否会影响准确性?
【解决方案2】:

在 iPhone 中我们可以通过两种方式配置定位服务 -

  1. 使用Standard Location Services,即卫星GPS,可为您提供更准确的数据。
  2. 通过使用Significant Location Changes 使用 A-GPS 或通过 wi-fi 获取位置,这提供了不太准确的数据。

我们可以通过这两种方法中的任何一种来配置位置服务,但这取决于应用程序的要求。 如果应用程序是navigation applocation tracking app,那么我们应该使用Standard Location Services,但在使用标准服务之前,我们要记住,如果您想要更准确的数据,那么您必须忍受battery consume more quickly。 如果该应用不需要更频繁地更新位置并且accuracy doesn't matter 很多,那么我们应该Significant Location Changes 因为与标准位置服务相比,它会消耗save a lot of battery

标准位置服务使用desiredAccuracydistanceFilter 值来确定是否以及何时发送事件。

desiredAccuracy 是您可以定义 GPS 硬件所需精度的参数。它使用一些预定义的常量作为 -

kCLLocationAccuracyBestForNavigation
kCLLocationAccuracyBest
kCLLocationAccuracyNearestTenMeters
kCLLocationAccuracyHundredMeters
kCLLocationAccuracyKilometer
kCLLocationAccuracyThreeKilometers

distanceFilter 是您必须定义距离的参数,表示您希望 GPS 硬件发送位置更新的距离间隔。

在您的情况下,您正在处理速度参数,所以我猜它与导航有关。所以你应该使用Standard Location Services。我认为您也在这样做,但您面临的问题是位置更新之间的滞后。在这里,我建议您将您的 desiredAccuracydistanceFilter 值修改为此 -

[locationManager setDesiredAccuracy:kCLLocationAccuracyNearestTenMeters]; [locationManager setDistanceFilter:10.0f];

通过设置此值,如果您正在开车,您将在不到 1 秒的时间内获得位置更新。

您必须记住的另一件事是,当您获取位置更新时,您应该检查其timestamp 值以忽略旧的位置更新。这是因为当您通过调用startUpdatingLocation 开始locationManager 时,您获得的第一个位置可能是您的旧位置。此外,您还必须检查 horizontalAccuracy 值,因为您获得的前几个位置更新总是不准确的,并且可能具有 1000 或更多的准确度,而您不需要。因此,您必须检查其值以忽略不准确的位置更新。

Note: If you try with different accuracy and different distance filter value then you will be more clear about it how accurate data iPhone GPS hardware return.

【讨论】:

    【解决方案3】:

    除了其他如何使用核心定位的好例子之外,还要记住从Kalman Filtering 的不太好的传感器(例如智能手机定位服务)获得良好运动学结果的一般技术。

    这需要大量的数学运算、测试和调整,但它确实可以让您获得用户认为比传感器提供的简单数据更好的结果。

    这是用于航空电子设备和雷达处理系统之类的东西。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-16
      • 2013-09-28
      • 2016-09-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多