Search code examples
iosobjective-ccore-locationcllocationmanagercore-telephony

How can I find an average of 10 signal strength recordings in Objective-C


I am attempting to find an average of 10 signal strength values (to improve accuracy whilst using CTGetSignalStrength). I am also trying to capture the users location (once). I currently have the following code, whilst I realise this will not work. How can I arrange the if statements to ensure that an average value of the 10 signal strength values is recorded whilst only recording one location when buttonPressed?

- (IBAction)buttonPressed:(id)sender {

    dispatch_async(backgroundQueue, ^{
        manager.delegate = self;
        manager.desiredAccuracy = kCLLocationAccuracyBest;
        [manager startUpdatingLocation];
    });

}

#pragma mark CLLocationManagerDelegate Methods

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
    NSLog(@"Error: %@", error);
    NSLog(@"Failed to get location!");
}

- (void)arrayBuild {
    loopCount++;
    if (loopCount >= 11) {
        [myTimer invalidate];
        myTimer = nil;
        [manager startUpdatingLocation];

    } else {

    }

}

-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {


        NSLog(@"Location: %@",newLocation);
        CLLocation *curentLocation = newLocation;

        if (curentLocation != nil) {

        float signalstrength = CTGetSignalStrength();

        NSMutableArray *resultsArray = [[NSMutableArray alloc]init];
        NSNumber *avg = [resultsArray valueForKeyPath:@"@avg.self"];
        NSString *result = [NSString stringWithFormat:@"%f", signalstrength];
        NSInteger resultInt = [result integerValue];
        [resultsArray addObject:[NSNumber numberWithFloat:resultInt]];

        self.latitude.text = [NSString stringWithFormat:@"%.8f",curentLocation.coordinate.latitude];
        self.longitude.text = [NSString stringWithFormat:@"%.8f",curentLocation.coordinate.longitude];
        self.signal.text = [NSString stringWithFormat:@"%.8f",signalstrength];


        // Code below uses a third party utility to submit data

        PFObject *Object = [PFObject objectWithClassName:@"Issue"];

        Object[@"Latitude"] = [NSString stringWithFormat:@"%.8f",curentLocation.coordinate.latitude];
        Object[@"Longitude"] = [NSString stringWithFormat:@"%.8f",curentLocation.coordinate.longitude];
        Object[@"Signal"] = [NSString stringWithFormat:@"%@",avg];

        myTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
                                                   target:self
                                                 selector:@selector(arrayBuild)
                                                 userInfo:nil
                                                  repeats:YES];
        [Object saveInBackground];
    }
}

Solution

  • What I would do:

    1)Use regions instead of a set of coordinates. Either work out passing data around or less elegantly...set a global variable for region.

    Register to receive "region updates" via

    startMonitoringForRegion:
    

    Then use the delegate calls to your "region updates" method to change the global variable every time the user moves around.

    2)The delegate method

    -(void)locationManager: didUpdateToLocation: fromLocation:
    

    ...is depreciated in iOS 6.0 You should instead set up a delegate for...

    - (void)locationManager: didUpdateLocations:
    

    ...then call

    [CLLocationManager startUpdatingLocation];
    

    You'll get your delegate method immediately called.

    The docs in Xcode say:

    Specifically, it takes into account the values in the desiredAccuracy and distanceFilter property to determine when to deliver new events. The precision of the standard location services are needed by navigation applications or any application where high-precision location data or a regular stream of updates is required.

    [RANT]

    ( Maybe your intention, but we're mixing two different schemes here-standard location delegate handler plus polling with CTGetSignalStrength...Might want to cut out one or the other)

    [/RANT]

    ...so I think you just have to wait for the location data to keep getting updated (i.e. signal strength) once you've told the superclass you'd like the finest degree of location tuning.

    3)Can't find a lot of defining info on CTGetSignalStrength but I think it returns an int, not a float. Something to keep in mind when averaging is that you're getting -decibels as a unit. Since it's logerithmic you'll have to convert to decimal scale i.e.:

    -65db, -40db, -75db 
    

    can be...

    10^(-65/10.), 10^(-40/10.), 10^(-75/10.)
    

    in powers scale. Then average those values and convert back to db's. Please double-check what units you're getting back from CTGetSignalStrength in your exact module/header. Hope that helps.