Comment calculer le nombre de pas de pied exact à l’aide de l’accéléromètre dans Android?

Je développe des applications telles que Runtastic Pedometer en utilisant l’algorithme https://code.google.com/p/pedometer/ mais je n’ai aucune similitude entre les résultats.

mon code est le suivant:

public void onSensorChanged(SensorEvent event) { Sensor sensor = event.sensor; synchronized (this) { if (sensor.getType() == Sensor.TYPE_ORIENTATION) {} else { int j = (sensor.getType() == Sensor.TYPE_ACCELEROMETER) ? 1 : 0; if (j == 1) { float vSum = 0; for (int i=0 ; i mLastValues[k] ? 1 : (v  0 ? 0 : 1); // minumum or maximum? mLastExtremes[extType][k] = mLastValues[k]; float diff = Math.abs(mLastExtremes[extType][k] - mLastExtremes[1 - extType][k]); if (diff > mLimit) { boolean isAlmostAsLargeAsPrevious = diff > (mLastDiff[k]*2/3); boolean isPreviousLargeEnough = mLastDiff[k] > (diff/3); boolean isNotContra = (mLastMatch != 1 - extType); if (isAlmostAsLargeAsPrevious && isPreviousLargeEnough && isNotContra) { for (StepListener stepListener : mStepListeners) { stepListener.onStep(); } mLastMatch = extType; } else { Log.i(TAG, "no step"); mLastMatch = -1; } } mLastDiff[k] = diff; } mLastDirections[k] = direction; mLastValues[k] = v; } } } } 

pour enregistrer des capteurs:

 mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); mSensor = mSensorManager.getDefaultSensor( Sensor.TYPE_ACCELEROMETER); mSensorManager.registerListener(mStepDetector,mSensor,SensorManager.SENSOR_DELAY_NORMAL); 

dans l’algorithme j’ai différents niveaux de sensibilité en tant que vide public

 setSensitivity(float sensitivity) { mLimit = sensitivity; // 1.97 2.96 4.44 6.66 10.00 15.00 22.50 33.75 50.62 } 

sur différents niveaux de sensibilité, mon résultat est:

 sensitivity rantastic pedometer my app 10.00 3870 5500 11.00 3000 4000 11.15 3765 4576 13.00 2000 890 11.30 754 986 

Je ne reçois aucun modèle approprié pour répondre à l’exigence. Selon mon parsing, cette application utilise Sensor.TYPE_MAGNETIC_FIELD pour le calcul des étapes s’il vous plaît laissez-moi savoir un algorithme afin que je puisse répondre à l’exigence

https://github.com/bagilevi/android-pedometer

J’espère que cela pourrait être utile

La première chose à faire est de choisir un algorithme. Pour autant que je sache, il existe trois façons de détecter les étapes à l’aide d’accéléromètres décrits dans la littérature:

  1. Utilisez le théorème de Pythagore pour calculer l’amplitude du vecteur d’accélération de chaque échantillon à partir de l’accéléromètre. Filtre passe-bas du signal d’amplitude pour supprimer les bruits de haute fréquence, puis rechercher les pics et les creux dans le signal filtré. Vous devrez peut-être append des exigences supplémentaires pour supprimer les faux positifs. C’est de loin le moyen le plus simple de détecter des pas, c’est aussi la façon dont la plupart des podomètres ordinaires du genre que vous pouvez acheter dans un magasin de sport fonctionnent.

  2. Utilisez Pythagoras comme dans (1), puis exécutez le signal via une FFT et comparez la sortie de la FFT aux sorties connues de la marche. Cela nécessite que vous ayez access à une quantité assez importante de données de formation.

  3. Alimentez les données de l’accéléromètre en un algorithme utilisant une technique d’apprentissage automatique appropriée, par exemple un neural network ou une transformée en ondelettes numérique. Vous pouvez bien sûr inclure d’autres capteurs dans cette approche. Cela nécessite également que vous ayez access à une quantité assez importante de données de formation.

Une fois que vous avez choisi un algorithme, vous voudrez probablement utiliser quelque chose comme Matlab ou SciPy pour tester votre algorithme sur votre ordinateur en utilisant les enregistrements que vous avez effectués sur les téléphones Android. Videz les données de l’accéléromètre dans un fichier cvs sur votre téléphone, notez le nombre d’étapes que le fichier représente, copiez le fichier sur votre ordinateur et exécutez votre algorithme sur les données pour voir si le nombre de pas est correct. De cette façon, vous pouvez détecter les problèmes avec l’algorithme et les corriger.

Si cela vous semble difficile, le meilleur moyen d’accéder à une bonne détection de pas est probablement d’attendre qu’un plus grand nombre de téléphones intègrent le compteur de pas intégré que KitKat active.

J’utilise la détection de pas dans mon instrument de marche. Je reçois de bons résultats de détection de pas. J’utilise achartengine pour tracer les données de l’accéléromètre. Jetez un oeil ici: https://github.com/MichalDanielDobrzanski/WalkingSynth/blob/master/app/src/main/java/com/dobi/walkingsynth/accelerometer/AccelerometerProcessing.java Ce que je fais:

  1. Analyse du vecteur de magnitude pour capteur accéléromètre.
  2. Définition d’un niveau de seuil modifiable . Lorsque le signal de l’accéléromètre est au-dessus, je le considère comme une étape.
  3. Réglage de l’heure d’inactivité (pour la détection d’étape) après le premier franchissement du seuil.

Le point 3. est calculé:

  • réglage arbitraire du tempo maximum de notre marche (ex: 120bpm)
  • si 60 bpm – 1000 ms par étape, puis 120 bpm – 500 ms par étape
  • l’accéléromètre transmet les données avec la fréquence souhaitée (SENSOR_DELAY_NORMAL, SENSOR_DELAY_GAME, etc.). Lorsque DELAY_GAME: T ~ = 20ms (ceci est inclus dans la documentation Android)
  • n – échantillons à omettre (après dépassement du seuil)
  • n = 500 ms / T
  • n = 500/20 = 25 (beaucoup d’entre eux. Vous pouvez ajuster cette valeur).
  • après cela, le seuil devient actif .

Regardez cette photo: Ma candidature

Ceci est ma réalisation. Il a été écrit il y a environ 1,5-2 ans. Et je ne me souviens vraiment pas de tout ce que j’ai écrit. Mais ça a marché. Et cela fonctionnait bien pour mes besoins.

Je sais que c’est vraiment une grande classe (certaines méthodes sont supprimées), mais cela pourrait être utile. Sinon, je vais juste supprimer cette réponse …

 public class StepDetector implements SensorEventListener { public static final int MAX_BUFFER_SIZE = 5; private static final int Y_DATA_COUNT = 4; private static final double MIN_GRAVITY = 2; private static final double MAX_GRAVITY = 1200; public void onSensorChanged(final SensorEvent sensorEvent) { final float[] values = sensorEvent.values; final Sensor sensor = sensorEvent.sensor; if (sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) { magneticDetector(values, sensorEvent.timestamp / (500 * 10 ^ 6l)); } if (sensor.getType() == Sensor.TYPE_ACCELEROMETER) { accelDetector(values, sensorEvent.timestamp / (500 * 10 ^ 6l)); } } private ArrayList mAccelDataBuffer = new ArrayList(); private ArrayList mMagneticFireData = new ArrayList(); private Long mLastStepTime = null; private ArrayList mAccelFireData = new ArrayList(); private void accelDetector(float[] detectedValues, long timeStamp) { float[] currentValues = new float[3]; for (int i = 0; i < currentValues.length; ++i) { currentValues[i] = detectedValues[i]; } mAccelDataBuffer.add(currentValues); if (mAccelDataBuffer.size() > StepDetector.MAX_BUFFER_SIZE) { double avgGravity = 0; for (float[] values : mAccelDataBuffer) { avgGravity += Math.abs(Math.sqrt( values[0] * values[0] + values[1] * values[1] + values[2] * values[2]) - SensorManager.STANDARD_GRAVITY); } avgGravity /= mAccelDataBuffer.size(); if (avgGravity >= MIN_GRAVITY && avgGravity < MAX_GRAVITY) { mAccelFireData.add(new Pair(timeStamp, true)); } else { mAccelFireData.add(new Pair(timeStamp, false)); } if (mAccelFireData.size() >= Y_DATA_COUNT) { checkData(mAccelFireData, timeStamp); mAccelFireData.remove(0); } mAccelDataBuffer.clear(); } } private void checkData(ArrayList accelFireData, long timeStamp) { boolean stepAlreadyDetected = false; Iterator iterator = accelFireData.iterator(); while (iterator.hasNext() && !stepAlreadyDetected) { stepAlreadyDetected = iterator.next().first.equals(mLastStepTime); } if (!stepAlreadyDetected) { int firstPosition = Collections.binarySearch(mMagneticFireData, accelFireData.get(0).first); int secondPosition = Collections .binarySearch(mMagneticFireData, accelFireData.get(accelFireData.size() - 1).first - 1); if (firstPosition > 0 || secondPosition > 0 || firstPosition != secondPosition) { if (firstPosition < 0) { firstPosition = -firstPosition - 1; } if (firstPosition < mMagneticFireData.size() && firstPosition > 0) { mMagneticFireData = new ArrayList( mMagneticFireData.subList(firstPosition - 1, mMagneticFireData.size())); } iterator = accelFireData.iterator(); while (iterator.hasNext()) { if (iterator.next().second) { mLastStepTime = timeStamp; accelFireData.remove(accelFireData.size() - 1); accelFireData.add(new Pair(timeStamp, false)); onStep(); break; } } } } } private float mLastDirections; private float mLastValues; private float mLastExtremes[] = new float[2]; private Integer mLastType; private ArrayList mMagneticDataBuffer = new ArrayList(); private void magneticDetector(float[] values, long timeStamp) { mMagneticDataBuffer.add(values[2]); if (mMagneticDataBuffer.size() > StepDetector.MAX_BUFFER_SIZE) { float avg = 0; for (int i = 0; i < mMagneticDataBuffer.size(); ++i) { avg += mMagneticDataBuffer.get(i); } avg /= mMagneticDataBuffer.size(); float direction = (avg > mLastValues ? 1 : (avg < mLastValues ? -1 : 0)); if (direction == -mLastDirections) { // Direction changed int extType = (direction > 0 ? 0 : 1); // minumum or maximum? mLastExtremes[extType] = mLastValues; float diff = Math.abs(mLastExtremes[extType] - mLastExtremes[1 - extType]); if (diff > 8 && (null == mLastType || mLastType != extType)) { mLastType = extType; mMagneticFireData.add(timeStamp); } } mLastDirections = direction; mLastValues = avg; mMagneticDataBuffer.clear(); } } public static class Pair implements Serializable { Long first; boolean second; public Pair(long first, boolean second) { this.first = first; this.second = second; } @Override public boolean equals(Object o) { if (o instanceof Pair) { return first.equals(((Pair) o).first); } return false; } } } 

L’une des principales différences entre votre implémentation et le code dans le projet grepcode est la manière dont vous enregistrez le programme d’écoute.

Votre code:

 mSensorManager.registerListener(mStepDetector, mSensor, SensorManager.SENSOR_DELAY_NORMAL); 

Leur code:

 mSensorManager.registerListener(mStepDetector, mSensor, SensorManager.SENSOR_DELAY_FASTEST); 

C’est une grande différence. SENSOR_DELAY_NORMAL est destiné aux changements d’orientation et n’est donc pas si rapide (vous avez déjà remarqué qu’il faut un certain temps entre la rotation de l’appareil et la rotation réelle de l’appareil? C’est une fonctionnalité qui n’a pas besoin d’être très rapide probablement même assez ennuyeux. Le taux auquel vous obtenez des mises à jour n’est pas si élevé).

En revanche, SENSOR_DELAY_FASTEST est conçu pour des choses comme les podomètres: vous souhaitez que les données des capteurs soient aussi rapides et souvent que possible, afin que vos calculs d’étapes soient aussi précis que possible.

Essayez de passer au taux SENSOR_DELAY_FASTEST et testez à nouveau! Cela devrait faire une grande différence.