Подтвердить что ты не робот

Обнаружение, когда кто-то начинает ходить с использованием данных Core Motion и CMAccelerometer

Я пытаюсь обнаружить три действия: когда пользователь начинает ходить, бегать или бегать. Затем я хочу знать, когда остановка. Мне удалось обнаружить, когда кто-то ходит, бегает или бежит со следующим кодом:

- (void)update:(CMAccelerometerData *)accelData {

    [(id) self setAcceleration:accelData.acceleration];

    NSTimeInterval secondsSinceLastUpdate = -([self.lastUpdateTime timeIntervalSinceNow]);

    if (labs(_acceleration.x) >= 0.10000) {
        NSLog(@"walking: %f",_acceleration.x);
    }
    else if (labs(_acceleration.x) > 2.0) {
        NSLog(@"jogging: %f",_acceleration.x);
    }
    else if (labs(_acceleration.x) > 4.0) {
        NSLog(@"sprinting: %f",_acceleration.x);
    }

Проблема, с которой я сталкиваюсь, двукратна:

1) обновление вызывается несколько раз при каждом движении, вероятно, потому, что оно так часто проверяет, что когда пользователь начинает ходить (т.е. _acceleration.x > =.1000), он еще > =.1000, когда он снова вызывает обновление.

Пример журнала:

    2014-02-22 12:14:20.728 myApp[5039:60b] walking: 1.029846
    2014-02-22 12:14:20.748 myApp[5039:60b] walking: 1.071777
    2014-02-22 12:14:20.768 myApp[5039:60b] walking: 1.067749

2) Мне трудно понять, как определить, когда пользователь остановился. Кто-нибудь имеет рекомендации о том, как реализовать "Остановить обнаружение"

4b9b3361

Ответ 1

В соответствии с вашими журналами accelerometerUpdateInterval примерно 0.02. Обновления могут быть менее частыми, если вы измените указанное свойство CMMotionManager.

Проверка только x-ускорения не очень точная. Я могу разместить устройство на столе таким образом (пусть, по левому краю), что x-ускорение будет равно 1 или немного наклонит его. Это приведет к тому, что программа будет находиться в режиме ходьбы (x > 0,1), а не в режиме ожидания.

Здесь ссылка на ДОПОЛНИТЕЛЬНЫЙ ПЕДОМЕТР ДЛЯ ОТСЛЕЖИВАНИЯ НА ОСНОВЕ СМАРТФОНОВОЙ ДЕЯТЕЛЬНОСТИ. Они отслеживают изменения в направлении вектора ускорения. Это косинус угла между двумя последовательными показаниями вектора ускорения.

cos(angle) formula

Очевидно, что без движения угол между двумя векторами близок к нулю и cos(0) = 1. Во время других видов деятельности d < 1. Чтобы отфильтровать шум, они используют взвешенное скользящее среднее из последних 10 значений d.

WMA10 formula

После реализации этого значения ваши значения будут выглядеть следующим образом (красный - ходьба, синяя - работа):

WMA(d)

Теперь вы можете установить пороговое значение для каждого действия для их разделения. Обратите внимание, что средняя ступенчатая частота составляет 2-4 Гц. Вы должны ожидать, что текущее значение будет превышать порог, по крайней мере, несколько раз в секунду, чтобы идентифицировать действие.

Другие полезные публикации:

ОБНОВЛЕНИЕ

_acceleration.x, _accelaration.y, _acceleration.z являются координатами одного и того же вектора ускорения. Вы используете каждую из этих координат в формуле d. Для вычисления d вам также необходимо сохранить вектор ускорения предыдущего обновления (с индексом i-1 в формуле).

WMA просто учитывает 10 последних значений d с разными весами. Поэтому последние значения d имеют больший вес, поэтому большее влияние на результирующее значение. Вам нужно сохранить 9 предыдущих значений d, чтобы рассчитать текущий. Вы должны сравнить значение WMA с соответствующим порогом.

Ответ 2

Если вы используете iOS7 и iPhone5S, я предлагаю вам взглянуть на CMMotionActivityManager, который доступен в iPhone5S из-за чипа M7. Он также доступен в нескольких других устройствах:

чип M7

Вот фрагмент кода, который я собрал, чтобы проверить, когда я узнал об этом.

#import <CoreMotion/CoreMotion.h>

@property (nonatomic,strong) CMMotionActivityManager *motionActivityManager;

-(void) inSomeMethod
{
  self.motionActivityManager=[[CMMotionActivityManager alloc]init];

  //register for Coremotion notifications
  [self.motionActivityManager startActivityUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMMotionActivity *activity) 
  {
    NSLog(@"Got a core motion update");
    NSLog(@"Current activity date is %f",activity.timestamp);
    NSLog(@"Current activity confidence from a scale of 0 to 2 - 2 being best- is: %ld",activity.confidence);
    NSLog(@"Current activity type is unknown: %i",activity.unknown);
    NSLog(@"Current activity type is stationary: %i",activity.stationary);
    NSLog(@"Current activity type is walking: %i",activity.walking);
    NSLog(@"Current activity type is running: %i",activity.running);
    NSLog(@"Current activity type is automotive: %i",activity.automotive);
  }];
}

Я тестировал его, и он кажется довольно точным. Единственный недостаток заключается в том, что он не даст вам подтверждения, как только вы начнете действие (например, пешком). Некоторые алгоритмы черного ящика ждут, чтобы вы действительно ходили или бегали. Но тогда вы знаете, что у вас есть подтвержденное действие.

Это бьется с акселерометром. Apple позаботилась об этой детали!

Ответ 3

Вы можете использовать эту простую библиотеку для обнаружения, если пользователь идет, работает, на транспортном средстве или не двигается. Работает на всех устройствах iOS и не нуждается в чипе M7.

https://github.com/SocialObjects-Software/SOMotionDetector

В репо вы можете найти демонстрационный проект

Ответ 4

Я следую этой статье (PDF через RG) в моем проекте внутренней навигации, чтобы определить динамику пользователя (статическую, медленную ходьбу, быструю ходьбу) через данные только акселерометра, чтобы помочь определить местоположение.

Вот алгоритм, предложенный в проекте:

введите описание изображения здесь

И вот моя реализация в Swift 2.0:

import CoreMotion
let motionManager = CMMotionManager()
motionManager.accelerometerUpdateInterval = 0.1
motionManager.startAccelerometerUpdatesToQueue(NSOperationQueue.mainQueue()) { (accelerometerData: CMAccelerometerData?, error: NSError?) -> Void in
        if((error) != nil) {
            print(error)
        } else {
            self.estimatePedestrianStatus((accelerometerData?.acceleration)!)
        }
}

После всего классического кода Swifty iOS, чтобы инициировать CoreMotion, вот метод, хрустящий числа и определяющие состояние:

func estimatePedestrianStatus(acceleration: CMAcceleration) {
    // Obtain the Euclidian Norm of the accelerometer data
    accelerometerDataInEuclidianNorm = sqrt((acceleration.x.roundTo(roundingPrecision) * acceleration.x.roundTo(roundingPrecision)) + (acceleration.y.roundTo(roundingPrecision) * acceleration.y.roundTo(roundingPrecision)) + (acceleration.z.roundTo(roundingPrecision) * acceleration.z.roundTo(roundingPrecision)))

    // Significant figure setting
    accelerometerDataInEuclidianNorm = accelerometerDataInEuclidianNorm.roundTo(roundingPrecision)

    // record 10 values
    // meaning values in a second
    // accUpdateInterval(0.1s) * 10 = 1s
    while accelerometerDataCount < 1 {
        accelerometerDataCount += 0.1

        accelerometerDataInASecond.append(accelerometerDataInEuclidianNorm)
        totalAcceleration += accelerometerDataInEuclidianNorm

        break   // required since we want to obtain data every acc cycle
    }

    // when acc values recorded
    // interpret them
    if accelerometerDataCount >= 1 {
        accelerometerDataCount = 0  // reset for the next round

        // Calculating the variance of the Euclidian Norm of the accelerometer data
        let accelerationMean = (totalAcceleration / 10).roundTo(roundingPrecision)
        var total: Double = 0.0

        for data in accelerometerDataInASecond {
            total += ((data-accelerationMean) * (data-accelerationMean)).roundTo(roundingPrecision)
        }

        total = total.roundTo(roundingPrecision)

        let result = (total / 10).roundTo(roundingPrecision)
        print("Result: \(result)")

        if (result < staticThreshold) {
            pedestrianStatus = "Static"
        } else if ((staticThreshold < result) && (result <= slowWalkingThreshold)) {
            pedestrianStatus = "Slow Walking"
        } else if (slowWalkingThreshold < result) {
            pedestrianStatus = "Fast Walking"
        }

        print("Pedestrian Status: \(pedestrianStatus)\n---\n\n")

        // reset for the next round
        accelerometerDataInASecond = []
        totalAcceleration = 0.0
    }
}

Кроме того, я использовал следующее расширение для упрощения установки значимых фигур:

extension Double {
    func roundTo(precision: Int) -> Double {
        let divisor = pow(10.0, Double(precision))
        return round(self * divisor) / divisor
    }
}

С исходными значениями из CoreMotion алгоритм был haywire.

Надеюсь, это поможет кому-то.

РЕДАКТИРОВАТЬ (4/3/16)

Я забыл предоставить мое значение roundingPrecision. Я определил его как 3. Это просто математика, что эта значительная ценность достаточно приличная. Если вам нравится, что вы предоставляете больше.

Также еще одна вещь, которая стоит упомянуть, заключается в том, что на данный момент этот алгоритм требует, чтобы iPhone был в ваших руках во время ходьбы. См. Рисунок ниже. Извините, это был единственный, который я смог найти.

Статус iPhone во время ходьбы

My GitHub Repo, поддерживающий статус пешехода