2

Plot of instantaneous accelerometer values against time

I need to find the number of times the accelerometer value stream attains a maximum. I made a plot of the accelerometer values obtained from an iPhones against time, using CoreMotion method to obtain the DeviceMotionUpdates. When the data was being recorded, I shook the phone 9 times (where each extremity was one of the highest points of acceleration).

I have marked the 18 (i.e. 9*2) times when acceleration had attained maximum in red boxes on the plot.

But, as you see, there are some local maxima that I do not want to consider. Can someone direct me towards an idea that will help me achieve detecting only the maxima of importance to me?

Edit: I think I have to use a low pass filter. But, how do I implement this in Swift? How do I choose the frequency of cut-off?

Edit 2: Accelerometer data passed through a low pass filter I implemented a low pass filter and passed the raw motion data through it and obtained the graph as shown below. This is a lot better. I still need a way to avoid the insignificant maxima that can be observed. I'll work in depth with the filter and probably fix it.

  • Possible duplicate of [Algorithm to locate local maxima](http://stackoverflow.com/questions/3242910/algorithm-to-locate-local-maxima) – andand Nov 04 '16 at 15:01
  • @andand this is not a duplicate of that. That question asks how to find local maxima. This asks how to find global maxima – Nyakiba Nov 04 '16 at 15:05
  • I don't think you're looking for the global max; that would be just one value which you can find using exhaustive search in linear time. It looks to me like you want to count all local maxima which exceed a certain threshold value. If that's not the case, you will need to reword your question. – andand Nov 04 '16 at 15:14
  • @andand I'm not looking for the global maximum nor the local maxima. If you notice, in the image, two maxima closely occur with each other before dropping significantly to two closely-spaced minima. I am only interested in one maxima which ideally will represent an extremity when shaking the phone. But, I am getting two maxima, probably produced by the bouncing of the hand when changing direction while shaking the phone. How do I count the number of extremities by ignoring the bounces? – Vishal V. Shekkar Nov 04 '16 at 15:24
  • @Nyakiba I am not looking for a local maxima. I am looking to avoid certain maxima as they do not make sense for the data I'm trying to read out of the graph. When I shake the phone, the accelerometer, I suspect undergoes some kind of a bounce when the direction switches. I need to avoid reading those maxima. – Vishal V. Shekkar Nov 04 '16 at 15:26
  • @andand if you look at the image, the second maximum in the first red rectangle is higher than the largest maximum in the second rectangular box. I cannot use a threshold because of this. The user may shake the phone less or more wildly and my algorithm should still be able to detect the number of times extremities have been reached when the shaking happened. Although I wouldn't consider this a duplicate, the question you posted is very insightful for my problem. – Vishal V. Shekkar Nov 04 '16 at 15:29

1 Answers1

1

Instead of trying to find the maximas, I would try to look for cycles. Especially, we note that the (main) minimas seem to be a lot more consistent than the maximas.

I am not familiar with swift, so I'll layout my idea in pseudo code. Suppose we have our values in v[i] and the derivative in dv[i] = v[i] - v[i - 1]. You can use any other differentiation scheme if you get a better result.

I would try something like

cycles = [] // list of pairs
cstart = -1
cend = -1
v_threshold = 1.8 // completely guessing these figures looking at the plot
dv_threshold = 0.01
for i in v:
    if cstart < 0 and
       v[i] > v_threshold and 
       dv[i] < dv_threshold then:
       // cycle is starting here
       cstart = i
    else if cstart > 0 and
            v[i] < v_threshold and
            dv[i] < dv_threshold then:
        // cycle ended
        cend = i
        cycles.add(pair(cstart, cend))
        cstart = -1
        cend = -1
    end if

Now you note in comments that the user should be able to shake with different force and you should be able to recognise the motion. I would start with a simple 'hard-coded' cases as the one above, and see if you can get it to work sufficiently well. There is a lot of things you could try to get a variable threshold, but you will nevertheless always need one. However, from the data you show I strongly suggest at least limiting yourself to looking at the minimas and not the maximas.

Also: the code I suggested is written assuming you have the full data set, however you will want to run this in real time. This will be no problem, and the algorithm will still work (that is, the idea will still work but you'll have to code it somewhat differently).

pingul
  • 3,351
  • 3
  • 25
  • 43