Détection du moment où une personne commence à marcher à l'aide des données du mouvement du cœur et du Cmaccéléromètre
j'essaie de détecter trois actions: quand un utilisateur commence à marcher, à courir ou à courir. Je veux savoir quand s'arrêter. J'ai réussi à détecter quand quelqu'un marche, fait du jogging ou court avec le code suivant:
- (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);
}
Le problème que je rencontre est double:
1) update est appelé plusieurs fois chaque fois qu'il y a un mouvement, probablement parce qu'il vérifie si souvent que lorsque l'utilisateur commence à marcher (i.e. _acceleration.x >= .1000), il est encore >= .1000 quand il appelle mise à jour à nouveau.
Exemple De Log:
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) j'ai de la difficulté à trouver comment détecter lorsque l'utilisateur s'est arrêté. Est-ce que quelqu'un a des conseils sur la façon de mettre en œuvre "Stop Detection"
4 réponses
en Fonction de vos journaux, accelerometerUpdateInterval
0.02
. Les mises à jour pourraient être moins fréquentes si vous changez la propriété CMMotionManager
.
vérification seulement X-l'accélération n'est pas très précise. Je peux mettre un appareil sur une table de telle façon (disons sur le bord gauche) que l'accélération x sera égale à 1, ou l'incliner un peu. Cela va causer un programme marche (x > 0.1) au lieu de idle.
Voici un lien vers avancé PODOMÈTRE POUR LE SUIVI DES ACTIVITÉS SUR SMARTPHONE publication. Ils suivent les changements dans la direction du vecteur d'accélération. C'est le cosinus de l'angle entre deux lectures consécutives du vecteur d'accélération.
évidemment, sans aucun mouvement, l'angle entre deux vecteurs est proche de zéro et cos(0) = 1
. Pendant d'autres activités d < 1. Pour filtrer le bruit, ils utilisent une moyenne mobile pondérée des 10 dernières valeurs de d.
après avoir implémenté ceci, vos valeurs ressembleront à ceci (marche rouge, course bleue):
vous pouvez maintenant établir un seuil pour chaque activité afin de les séparer. Notez que la fréquence moyenne des pas est de 2-4Hz. Vous devez vous attendre à ce que la valeur courante dépasse le seuil au moins quelques fois en une seconde afin d'identifier l'action.
une autre aide publications:
- ERSP: un podomètre à haut rendement énergétique pour Smartphone en temps réel (analyse des pics et des traversées)
- Un Gyroscopique Données en fonction Podomètre Algorithme (seuil de détection de gyro lectures)
UPDATE
_acceleration.x
,_accelaration.y
,_acceleration.z
sont les coordonnées du même vecteur d'accélération. Vous utilisez chacune de ces coordonnées dans d formule. Afin de calculer d vous devez également stocker le vecteur d'accélération de la mise à jour précédente (avec l'indice i-1 dans la formule).
WMA il suffit de prendre en compte les 10 dernières d valeurs avec des poids différents. Le plus récent d les valeurs ont plus de poids, donc plus d'impact sur la valeur résultante. Vous devez stocker 9 précédent d valeurs pour le calcul actuel. Vous devriez comparer la valeur de WMA au seuil correspondant.
si vous utilisez iOS7 et iPhone5S, je vous suggère d'examiner CMMotionActivityManager qui est disponible dans iPhone5S en raison de la puce M7. Il est également disponible dans une couple d'autres périphériques:
voici un extrait de code que j'ai mis en place pour le tester quand je l'apprenais.
#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);
}];
}
je l'ai testé et il semble être assez précis. Le seul inconvénient est qu'il ne sera pas vous donner une confirmation dès que vous commencez un action (marcher par exemple). Certains algorithmes de la boîte noire attend pour s'assurer que vous marchez ou courez vraiment. Mais alors vous savez que vous avez une action confirmée.
c'est mieux que de jouer avec l'accéléromètre. Apple a pris soin de ce détail!
vous pouvez utiliser cette bibliothèque simple pour détecter si l'utilisateur marche, court, sur le véhicule ou ne bouge pas. Fonctionne sur tous les appareils iOS et pas besoin de puce M7.
https://github.com/SocialObjects-Software/SOMotionDetector
Dans repo vous pouvez trouver projet de démonstration
je suis ce document (PDF via RG) dans le cadre de mon projet de navigation intérieure visant à déterminer la dynamique des utilisateurs(statique, marche lente, marche rapide) au moyen de simples données d'accéléromètre afin de faciliter la détermination de l'emplacement.
Voici l'algorithme proposé dans le projet:
Et voici mon implémentation dans 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)!)
}
}
après tout le classique code Swifty iOS à initiez la CoreMotion, voici la méthode de calcul des nombres et de détermination de l'état:
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
}
}
J'ai aussi utilisé l'extension suivante pour simplifier le réglage des chiffres significatifs:
extension Double {
func roundTo(precision: Int) -> Double {
let divisor = pow(10.0, Double(precision))
return round(self * divisor) / divisor
}
}
avec les valeurs brutes de CoreMotion, l'algorithme était haywire.
Espérons que cela aide quelqu'un.
EDIT (4/3/16)
j'ai oublié de donner mon roundingPrecision
valeur. Je l'ai défini comme 3. C'est tout simplement mathématique que l' une valeur significative est assez décent. Si vous le souhaitez, vous fournir plus.
une autre chose à mentionner est qu'à l'heure actuelle, cet algorithme exige que l'iPhone soit dans votre main tout en marchant. Voir l'image ci-dessous. Désolé c'est la seule que j'ai pu trouver.