2016-07-11 3 views
1

donc je me suis embarqué dans une quête pour calculer le nombre de mesures prises par un utilisateur en utilisant les données que je reçois de l'accéléromètre par exemple x, y et z coordonnées .Trouver un maximum de points locaux d'une donnée ensemble donné

J'essaie d'implémenter l'algorithme this mais je suis actuellement bloqué à la partie locale des maxima. Matlab a une méthode intégrée findpeaks() qui localise tous les maxima locaux d'un ensemble de données donné. Ci-dessous est ma tentative de mettre en œuvre l'algorithme, mais je reçois encore des résultats extrêmement énormes de celui-ci. Dans un premier temps, en utilisant un ensemble de données constitué de 20 étapes réelles, l'algorithme a calculé que le nombre de pas effectués était 990+. J'ai tordu et débogué et j'ai réussi à ramener ce nombre à environ 660 .. ensuite 110 finalement à un courant 45. Actuellement, je suis juste coincé et j'ai le sentiment que ma méthode findpeaks() est erronée.

Ceci est mon implémentation de la classe

import Foundation 

class StepCounter 
{ 
    private var xAxes: [Double] = [Double]() 
    private var yAxes: [Double] = [Double]() 
    private var zAxes: [Double] = [Double]() 
    private var rmsValues: [Double] = [Double]() 

    init(graphPoints: GraphPoints) 
{ 
    xAxes = graphPoints.xAxes 
    yAxes = graphPoints.yAxes 
    zAxes = graphPoints.zAxes 
    rmsValues = graphPoints.rmsValues 
} 

func numberOfSteps()-> Int 
{ 
    var pointMagnitudes: [Double] = rmsValues 

    removeGravityEffectsFrom(&pointMagnitudes) 

    let minimumPeakHeight: Double = standardDeviationOf(pointMagnitudes) 

    let peaks = findPeaks(&pointMagnitudes) 

    var totalNumberOfSteps: Int = Int() 

    for thisPeak in peaks 
    { 
     if thisPeak > minimumPeakHeight 
     { 
      totalNumberOfSteps += 1 
     } 
    } 

    return totalNumberOfSteps 
} 

// TODO: dummy method for the time being. replaced with RMS values from controller itself 
private func calculateMagnitude()-> [Double] 
{ 
    var pointMagnitudes: [Double] = [Double]() 

    for i in 0..<xAxes.count 
    { 
     let sumOfAxesSquare: Double = pow(xAxes[i], 2) + pow(yAxes[i], 2) + pow(zAxes[i], 2) 
     pointMagnitudes.append(sqrt(sumOfAxesSquare)) 
    } 

    return pointMagnitudes 
} 

private func removeGravityEffectsFrom(inout magnitudesWithGravityEffect: [Double]) 
{ 
    let mean: Double = calculateMeanOf(rmsValues) 

    for i in 0..<magnitudesWithGravityEffect.count 
    { 
     magnitudesWithGravityEffect[i] -= mean 
    } 
} 

// Reference: https://en.wikipedia.org/wiki/Standard_deviation 
private func standardDeviationOf(magnitudes: [Double])-> Double 
{ 
    var sumOfElements: Double = Double() 
    var mutableMagnitudes: [Double] = magnitudes 

    // calculates the numerator of the equation 
    /* no need to do (mutableMagnitudes[i] = mutableMagnitudes[i] - mean) 
    * because it has already been done when the gravity effect was removed 
    * from the dataset 
    */ 
    for i in 0..<mutableMagnitudes.count 
    { 
     mutableMagnitudes[i] = pow(mutableMagnitudes[i], 2) 
    } 

    // sum the elements 
    for thisElement in mutableMagnitudes 
    { 
     sumOfElements += thisElement 
    } 

    let sampleVariance: Double = sumOfElements/Double(mutableMagnitudes.count) 

    return sqrt(sampleVariance) 
} 

// Reference: http://www.mathworks.com/help/signal/ref/findpeaks.html#examples 
private func findPeaks(inout magnitudes: [Double])-> [Double] 
{ 
    var peaks: [Double] = [Double]() 

    // ignore the first element 
    peaks.append(max(magnitudes[1], magnitudes[2])) 

    for i in 2..<magnitudes.count 
    { 
     if i != magnitudes.count - 1 
     { 
      peaks.append(max(magnitudes[i], magnitudes[i - 1], magnitudes[i + 1])) 
     } 
     else 
     { 
      break 
     } 
    } 

    // TODO:Does this affect the number of steps? Are they clumsly lost or foolishly added? 
    peaks = Array(Set(peaks)) // removing duplicates. 

    return peaks 
} 

private func calculateMeanOf(magnitudes: [Double])-> Double 
{ 
    var sumOfElements: Double = Double() 

    for thisElement in magnitudes 
    { 
     sumOfElements += thisElement 
    } 

    return sumOfElements/Double(magnitudes.count) 
} 

} `

Avec cette datasheet, le nombre réel des mesures prises a été 20 mais je continue à se déplacer 45. Même quand je l'ai essayé avec un ensemble de données qui consiste en 30 étapes réelles, le nombre calculé approchait de la 100s.

Toute assistance/conseils seront grandement appréciés

PS: Format fiche technique X, Y, Z, RMS (root Mean square)

+0

Parce que je suis en train de mettre en œuvre le Matlab intégrés 'findpeaks()' méthode dans iOS – eshirima

+1

Dans votre méthode 'findPeaks', pourquoi faites-vous ceci:' peaks.append (max (magnitudes [i], grandeurs [i-1], grandeurs [i + 1])) '? Ne devriez-vous pas ajouter la valeur si le maximum est 'magnitudes [i]'? – jjatie

+0

* "Sont-ils maladroitement perdus ou bêtement ajoutés?" * Les deux. Il est certainement possible que deux pics indépendants aient la même valeur, auquel cas vous rejetterez des pics valides. D'un autre côté, si les données ont de minuscules oscillations, vous compterez trop de pics. Par exemple, cette donnée a un pic à 36, mais vous comptez 3 pics: 33,34,33,34,35,34,35,36,35,34,35,34,33,34,33. – user3386109

Répondre

1

Cette fonction fonctionne avec l'exemple que vous avez fourni. Il traite les plateaux comme un pic et permet de multiples pics de même valeur. Le seul problème est que - @ user3386109 points outs - s'il y a beaucoup de petites oscillations dans les données, vous obtiendrez plus de pics que ce qui est vraiment là. Vous pouvez mettre en œuvre la variance de l'ensemble de données dans ce calcul si vous traitez des données de ce type.

En outre, étant donné que vous ne changez pas la variable que vous passez il n'y a pas besoin d'utiliser inout

private func findPeaks(magnitudes: [Double]) -> [Double] { 

    var peaks = [Double]() 
    // Only store initial point, if it is larger than the second. You can ignore in most data sets 
    if max(magnitudes[0], magnitudes[1]) == magnitudes[0] { peaks.append(magnitudes[0]) } 

    for i in 1..<magnitudes.count - 2 { 
     let maximum = max(magnitudes[i - 1], magnitudes[i], magnitudes[i + 1]) 
     // magnitudes[i] is a peak iff it's greater than it's surrounding points 
     if maximum == magnitudes[i] && magnitudes[i] != magnitudes[i+1] { 
      peaks.append(magnitudes[i]) 
     } 
    } 
    return peaks 
} 
+0

MERCI SOOOOO MUCH..SERIOUSLY. J'aurais cassé le bouton up-vote si j'avais assez de représentants S/O. MERCI BEAUCOUP. – eshirima