## Algo Optomization

I wanted to test the algorithm from a previous post on multiple samples, so I recorded three trips on my tracker, Flex and M7 while walking around SF. The algorithm has two parameters than can be adjust in order to fine tune it: The cutoff point for the amplitude above and below 1G needed to trigger the peak sample counter, and the minimum number of data points above that threshold in order to record a peak (two peaks = one step). I sampled this data at 100Hz, because when I last used the algorithm I was running out of resolution.

I wrote a script MultiComplexCounter.m which took the vector sum for a given trip, and calculated the absolute percent difference between its calculated steps and the Felx’s steps for an array of different values for the two parameters mentioned above. I then took this data from the three trips and averaged it, to produce the table below.  Combinations of parameters which have less than a 3% error are in Red, less than a 10% error are in Yellow:

Averaged Percent Error For 3 Separate Trials Across and Spectrum of Values for Two Parameters

I was pretty stoked that the average percent error was so low in several places. I would imagine that the Flex’s error versus the actual number of steps walked is somewhere in this range, so I am not that far off. I think it is also comforting to see that there is a clear band which shows a relationship between the number of samples in the peak and the threshold of peak detection. As the threshold for beginning to count samples expands on either side of 1G, it makes sense that there would be fewer samples in that peak to be counted.

The data gets even better, however, when you look at the individual trials, which boast combinations of parameters which yield percent errors as low as 0.2%, 0.3% and 0.9%! To put this in perspective, a 0.2% difference from the Flex is 1 step in 500. That is surely just as accurate as anything FitBit can do! You can see all the data tables here in Trial Tables.

Analyzing the data further, if you plot all the parameter combinations which give errors of less than 1% (there is at least one combination for each trial) on an individualized basis, you can see that the black boxes representing them are all fairly tightly clustered:

Black Boxes for Individual Values less than 1% On Top of Averaged Data

If you then take the average values for the parameters the black boxes represent, and round as needed since the number of samples must be an integer, you find that the ideal values moving forward are a +/-Threshold = 0.1583 and an Average Samples per Peak of 7. When using this algorithm to analyze data moving forward, I will be sure to use these values!

## A Six-Pack in Six Positions

Over the holidays, I started thinking that an activity tracker algorithm should be position agnostic, i.e. it shouldn’t make a difference whether you have your arm by your side, over your head, etc. It also shouldn’t matter what the loading on that arm is, and the algorithm should produce the same result whether you’re carrying a dumbbell back to the rack at the gym or simply walking down the street. It is the vibration caused by taking a step, which is transmitted through the body to wherever the tracker is being worn, that is really the key signal. I decided to investigate this.

I picked a nice level spot of sidewalk in SF where I walked 50 steps six times in a row, taking care to make the exact same strides each time by stepping on the regularly spaced expansion joints in the cement. Each time I made the trip, I held my left arm outstretched in one of the following positions:

• Down at my side, perpendicular to the ground
• Above my head, perpendicular to the ground
• In front, parallel to the ground and perpendicular to the plane of my chest
• Behind, parallel to the ground and perpendicular to the plane of my chest (or as close as I could get it)
• Left of me, parallel to the ground and the plane of my chest
• Right, parallel to the ground and the plane of my chest

In case that language isn’t clear, here’s an amazing diagram which shows the the single letter references I’ll use throughout this post to refer to each position:

DaVinci Caliber Sketch of the Six Different Positions

I also decided I would have a better chance of holding my arm steady if it was weighted, so I choose to hold a 5-pack of Coors Light in my left hand, grabbing onto the empty loop where the missing 6th beer should have been. This put a mass of around 1.8Kg at the tip of my arm,  but what I failed to anticipate until I was half way through the experiment was that the 5-pack oscillated back and forth on its plastic collar, potentially introducing undesirable signals. As I have often thought on Saturday and Sunday mornings, Coors Light turned out to be a bad decision. In future experiments, I will choose something less dynamic like a barbell or a book.

As I was pacing off my 50 steps with my arm in each position, I also recorded data from my Flex (located on the same wrist as my tracker) and my iPhone 5s M7 processor (in my left pants pocket). Here are the results:

Device Step Counts

Of course, the M7 was unaffected by the arm position because it was in my pocket, but both of these devices turned out to be pretty darn accurate in this setting. FULL DISCLOSURE: I lost my old Flex diving on a reef off the cost of Great Abco Island, so the measurements here are coming from a new device versus previous posts. Given the volume at which FitBit is manufacturing , however, I will assume that any variations  between the two devices is negligible.

The Raw Data for the 6 Position Trial is plotted below, along with the vector sum of the three axes. I’ve also labeled when the trials are occurring, to help them stand out from some of the other noise that’s in here (like me walking back to the other end of the sidewalk in order to repeat the exact same 50 steps):

Plot of All Six 50 Step Trials

I feel pretty good about all these, except for the trial B when the 5-pack was behind my back… This was a really awkward position to maintain, and combined with the oscillating beers makes it a pretty junk signal. I decided to throw it out, and plotted the vector sums for all the other 5 trials bellow:

Vector Sums for the 5 Good Trials

The next thing I wanted to do was revisit the methodology from an earlier post, and figure out what the average step looked like for the vector sum each of the 5 trials with the tracker in different orientations. Here are the results:

The “Average Step” From each of the 5 Trials

From this plot, we can learn that no matter what orientation the arm is in, a step looks pretty much the same when looking at the vector sum of all three axes. I then added the average of all 5 trials to the plot, and threw in some annotations which I believe will be useful in developing a new step counting algorithm:

Annotated Average Signals

As the plot shows, the feature of all these signals that is the most similar is the period of the step and the slope of the signal between 0.9Gs < x < 1.1Gs (see yellow circles). I therefor believe it will be interesting to build an algorithm with the following criteria for what constitutes a step:

1. Go from 0.9Gs to 1.1Gs in 1, 2 or 3 samples without any decrease in force (i.e. S1 < S2 < S3)
2. Remain above 1.1Gs for at least 5 samples
3. Go from 1.1Gs to 0.9Gs in 1, 2 or 3 samples without any increase in force (i.e. S1>S2>S3)
4. Remain below 0.9Gs for at least 5 samples

If all of the above criteria are met, a step would then be recorded. Obviously this is a continuous cycle, where you could start counting at either positions 1 or 3. I wrote a script ComplexCounter.m which approximated the above, although I wound up not coding in anything related to the slope because I found I often had no data points in that range due to a low sample rate. I adjusted the algorithm so that in order to count as a step, the signal had to remain above 1.1Gs or below 0.9 Gs for two continuous samples, and generated these results:

ComplexCounter.m Results

The algorithm performed pretty well, even when back tested against a much nosier signal from a previous post. Overall, I think I came away thinking that the right way to approach this problem is through the vector sum of the forces, since the signals look pretty much the same no matter how your wrist / arm are oriented. I also think there is something to the approach I’ve taken of measuring a minimum number of samples above a threshold, but I don’t believe my algorithm is sufficiently robust at present. I need to gather some more real world data to back test it with and potentially make some further tweaks.

## Fitbit Force Review

I was excited to receive my Fitbit Force in the mail last week, because I’m constantly looking at my Flex to see what time it is (there is, of course, no clock on the Flex, so this habitual action frequently leaves me feeling quite stupid). The Force is definitely a bit heavier and almost twice as wide, but the quality of the display was excellent and the ability to interact with the device with a button rather than crude tapping gestures was great. Unfortunately, the Force is not even remotely waterproof! I wore it accidentally in the shower for 20 seconds before remembering to take it off, and the device shorted out. For about half a day, the Force flickered on and off while intermittently displaying the Fitbit logo, and condensed water was visible inside the display. Although it ultimately started working again, the problem reemerged after 5 minutes of washing dishes so I stopped wearing the device.

Condensed Water Inside the Force

Given the durability of the Flex, I was shocked that a device which feels just as rugged can’t even handle a splash of water. Having a display to show time and step count is a great feature, but if you can’t even wash dishes with it, I think there’s a brand-damaging design flaw in this product. The whole point of the Flex is that it’s thoughtless, and simply disappears into your life for days at a time until it needs to be charged. If getting my activity tracker wet is instead tantamount to spilling water on a mogwai,  that completely changes the use case and makes it stick out like a sore thumb in my daily routine. I’ll be returning Fitbit’s latest creation, and leaving “the force” to Starwars…

## Sample Signal Selection

While reviewing some previous posts, it occurred to me that my methodology for identifying cross correlation sample signals – i.e.,  choosing a “representative” signal at an arbitrary point in time for an arbitrary duration – was not very scientific. Using any discrete sample walking signal (rather than the average walking signal) might result in lower than expected correlations. So, I decided to build a script which would automatically extract an average sample signal from a specified window of data, in the hope that it could be used in the future to generate better correlations.

I used the data from a previous post, and found a window of data that I consider to be representative of general walking, from time 160 < t < 180:

Plotted Data from All 3 Axis from Time 160 < t < 180

There are a lot of interesting features in the plot above which could be used to identify a step – for example, each Z axis peak seems to be accompanied by a Y axis peak, and every other local minima in the X axis seems to correspond to a peak in both the Y and Z axes. I will ignore these for now, and focus on the X axis, where it is clear that period of the signal is two peaks long, i.e. there is a larger peak, a smaller peak, and then the signal repeats. This makes sense in the real world, in which the force the logger experiences in the X axis is larger from the step of one foot (presumably, the step which occurs on the same side of the body on which the logger is being worn) than in the other. I created a script, signalextractor.m, which takes the data from an input window, runs a peak detection, and then extracts the data in two-peak long periods. Plotted on top of each other, the data for each two-step period looks like this:

Data from Multiple Steps in the X Axis

I was very pleased with the consistency between the various periods shown in the plot, although the discontinuity between the beginning and ending values is disconcerting. I will assume however, that this is simply due to the low sample rate, and that if I had sampled at the logger’s maximum rate of 200Hz, the fist and last values for each plotted period would be nearly the same.  I then used this extracted data to produce an average sample signal, which is plotted below ontop of the underlying sample data points:

Average Signal ontop of Multiple X-Axis Two-step Cycles

I now have a useful script which I can use in the future to generate an average sample signal, as well as a means for investigating the standard deviation of accelerometer readings at each point in the step cycle. It might be useful in a future step counting algorithm, for example, to reject any signal as a step if it falls outside of a given range at a given point in time.

## DIY Medical Implant

Many thanks to TKM for letting me know about this DIY implant a bio-hacker recently embedded into his arm. As he aptly pointed out, I will never be this hardcore, although I’d like to think I would have done a better job with those sutures…

## Coors Light & Fourier Transforms

I wanted to use the same methodology from a previous post (Coffee Run) to analyze a new set of data,  so I took a  different route  around the block to buy a six pack of Coors Light at the corner store. I also wanted to test out my iPhone 5s’ M7 motion co-processor, so I kept my phone in my left pant’s pocket and used the Argus app to note the number of steps (any app should give the same results, since it’s just calling an API from the M7).  I used the correlationwindower.m script from an earlier post on the raw data (beerrundata), and generated the following result using the first block of steps just before t=100 as the sample data:

Plot of the Correlation of a Sample Signal (91<t<97) With the Dataset (blue) ontop of the Raw Data (Green)

Immediately, you can tell something is wrong because from 260 < t < 310 on the X axis, when I am clearly standing in line not moving, the correlation is really high. This led me to think about micro-oscillations that might be showing up in the noise during periods of non-motion, so I wanted to look at the data in frequency rather than time. I built a simple script to perform a discrete Fourier transform on the data using the fft command in Matlab (quickdft.m), and produced the following plot:

Fourier Transform of the Data from Each Axis

I was pretty excited by this data. First, the data from the three axes are all very consistent with each other, which gave me a lot of confidence that I can ultimately build an algorithm that can extract motion from any axis (versus just the X axis, currently). Secondly, I thought it was very interesting that the peaks for the Y and Z axis were greatest around 1 Hz, while the X axis peak was greatest at around 2 Hz. I timed my gate, and found that each step takes about a half second, so what must be going on is that the X axis is oscillating with each step, while the Y and Z axes are oscillating with each stepping cycle (i.e. both the left and right foot). This makes sense, given that my hand was positioned as follows:

Logger Positioning During Normal Walking Motion

So, you get an acceleration in the X axis with every step as you bob up and down while walking, you probably get some lurching back and forth in the Y axis which occurs with each step pair, and in the Z axis you sway side to side a bit with each step pair since no two legs are exactly the same length. It is also interesting to note the 2Hz frequency component of the Y axis signal, which is probably capturing some of that same individual step motion as the X axis because some part of my the raising and lowering with each step is actually occurring in the Y axis. At the same time, the absence of any 2Hz signal in the Z axis is very comforting as it reinforces the idea that the Z axis is experiencing a side to side sway.

I thought that perhaps creating a band pass filter might solve the problem of the phantom correlation data during periods of no motion; perhaps there was a high frequency noise signal with lower frequency elements that were seeping into the data. So, I created the following filter in Matlab’s filter design tool, which was launched with the fdatool command.

A Simple Bandpass Filter

I used the bandpass filter on the X axis raw data, and produced the plot below:

X Axis Data After Bandpass Filtering

Running a simple peak detection on this data  ([x_pks, x_locs] = findpeaks(xf,’MINPEAKHEIGHT’,.1,’MINPEAKDISTANCE’,10);) counted 549 steps, which is pretty close to the 539 recorded by my Fitbit Flex and the 536 recorded by the iPhone 5s. I then changed the parameters of the filter to focus even more tightly on the 2Hz frequency with the following settings (fstop 1.5, fpass1 = 1.8, fpass2 = 2.2, fstop2 = 2.5), and counted only 507 steps, which led me to believe that the previous answer was mostly just lucky, although it is possible that tightening the filter might have excluded steps which occurred at a slower pace. Overall, I was a little disappointed with this experiment in frequency, but I learned a lot which can hopefully be applied to future experiments.

## Interesting post from FitBit’s Blog

Found this really interesting blog post (pdf here: Fitbit 11-23-10) from Fitbit’s chief data scientist explaining how steps do not necessarily equate to calories. Will have to check out the two authors mentioned in the post as well….  Of course, I need to figure out how to reliable detect steps first! It had not occurred to me to look for academic research on the the matter, however, so perhaps I should look for some literature on the subject before blinding performing my next analysis.

## Coffee Run

I decided it was finally time to do some real signal processing, so I thought I would start off by trying to count the number of steps in one of my daily routines: walking to Real Foods in the morning to get a coffee and a bagel. I walked naturally across my apartment to establish a baseline signal, with both my Flex and my logger on my right arm. The Flex recorded 21 steps in this period. I then walked out of the apartment, down about 10 steps, down a gently downward sloping street for about 1.5 blocks, up a flight of about 10 steps into the Real Foods, got a cup of coffee and ordered my bagel. I stood around for a while waiting, and then reversed the process after check out.  After the initial calibration steps, I recorded 517 additional steps on my Flex which equated to 0.24 miles as I undertook the following trip:

I then plotted the data (Real Foods Data) my logger had recorded at a sample rate of 25 Hz, as shown below:

Plot of Logger Data From a Quick Trip to Real Foods

The first yellow bar shows the calibration steps, and the second and third bars show the trips to and from Real Foods, respectively. My first thought was to run a script from a previous post for the calibration step data to see how it performed.  I did this from time t = 43 to t = 60, with the minimum distance between samples set at d = 10, and produced the following plot:

myfirstpeakdetector.m Running From Time t = 43 to t = 60

The simple algorithm (which is incredibly sensitive to the input data range is defined) calculated the following number of peaks (i.e. step count):

Algorithm Output

While the Y and Z axes are close to the expected value of 21, the X axis seems to be an outlier, which drags the average value higher. I won’t get into a discussion about potential causes for this, since the real goal here was simply to find a data range within the calibration steps that was suitable to use as a sample data signal. I chose to use t = 45 to t = 55, which seems like it should contain a very crisp, uniform signal for all three axes. I wanted to run a cross correlation of the sample data range versus all the data for each axis, with hoped that I could use periods of high correlation to window a peak detection algorithm, thereby only counting peaks which matched the pattern of a series of steps. I created a script correlationplotter.m which uses the xcorr function to sweep data from each axis from t = 45 to t=55 across all the data from that axis, and then plot the correlation (blue) on top of the original data (green). It produced the following plot:

Correlation Between All Data and a Data Sample from t=45 to t=55 Plotted Ontop of the Original Data for each Axis

The X Axis appears to have good data. The correlation output is high (magnitude has been scaled to match original signal magnitude) during the sample data period, as well as during the two heavy period of walking to and from the store. The relationship between the two data sets from t=550 to t=650 is truly text book, and gave me great confidence in the methodology being used Unfortunately, this methodology does not seem to hold up as well for the Y and Z axes, in which the relationship between the correlation and the original data seems to be the opposite of what it should be; it is lower during periods of heavy walking, and higher during periods of random motion or little movement. This could possibly be explained by the fact that with my arm in the normal walking position, i.e. hanging to my side, the X axis is most likely to experience a force that is directly related to the number of steps, as my arm is moved up and down when the arch of my foot expands and contracts as part of my stride. I will move on with an analysis solely of the X axis, but if anyone can spot an error in my correlation methodology for the other two axes, I would greatly appreciate a comment on what I’m doing wrong.

I created a script correlationwindower.m, which performs a cross correlation of the data from an axis with a sample data set selected by a user definable range. The script then creates a windowing vector by converting every data point in the correlation vector to either a 0 or a 1 based on whether its value is greater or less than a user definable threshold, expressed as a percentage of the maximum value in the correlation data set (after scaling). This windowing vector is then multiplied by the original data set to remove all values which do not have a decent correlation with the sample data set. It then performs a peak detection on this new windowed data, where peaks must be greater than the mean of all non-zero values, and have a minimum distance between them of a user definable number of samples. The input window for the script looks like this:

Input Window for correlationwindower.m

The windowed signal looks like this:

X Axis Signal Windowed by It’s Correlation With a Sample Dataset

And the script outputs the detected peaks plotted on top of the original, “un-windowed” signal:

Original Signal With Detected Peaks

As you can see, for the input parameters shown in the previous screenshot of the inputs window, the script detected 583 peaks, which is about 13% more than we expected; not too bad considering all the non-cyclical motion that was going on. I thought it was also worth performing a brief sensitivity analysis around both the correlation windowing threshold value and the minimum distance between peaks. The table below shows the absolute percentage different between the number of steps the script calculated given different values for the aforementioned parameters, and the 517 steps the Flex recorded. All parameter pairs with a 13% or less absolute difference have been highlighted, to show that inputting those parameters would have been at least as accurate as the data shown above:

Sensitivity Analysis Around Minimum peak distance and Windowing Threshold

The sensitivity analysis shows that there is a broad tolerance centered roughly around the 10 samples, 60% cut off threshold for the windowing. This is probably a good thing, although it would be nice to expand the map further. Overall, I was happy with the first real signal processing that I’ve done so far, and I look forward to trying the script methodology out on other data sets in the future.

UPDATE: I just realized that my algorithm is actually more accurate than I had previously thought. The 583 detected peaks includes ALL the peaks in the sample, when what should be compared to the Fitbit’s 517 measured peaks are just the peaks which occurred after calibration set was recorded. Removing the peaks that occurred before t = 55s brings the total detected peaks down by 30 to 553, which is only a 7% difference from what the Fitbit calculated. The sensitivity table above is now invalid because it includes these early peaks, but I’m not going to bother to recalculate it because it’s scotch thirty.

## A Good Night’s Rest

I wanted to compare actual accelerometer data to the sleep report from my Fitbit Flex, so for the past several weeks I’ve been sleeping with both the flex and the data logger on my left hand. I chose a night where I felt like I had slept very well the next morning, and recorded the following screenshot from the FitBit app:

Screenshot of the Sleep Pattern screen from the Fitbit App

I then compiled data from the logger, which was tedious because I was sampling at 25Hz with a max file size of 90,000 samples. So, I had to combine many files in excel to produce a single data set for the accelerometer output which had 885,265 data points (Raw Data)… In retrospect, this was a little overkill, as there is nothing in the body that is happening so fast that you need to sample 25 times a second! Once this data was imported into Matlab, I was able to plot it versus time, where time was given in seconds since the beginning of the recording period. I wanted to plot the data versus the hour of the day however, and it took me a while to figure out the ultimately trivial commands. I first used the command ttime= datestr(t/86400+datenum(2013,10,14,22,54,14)) to create a date string which would combine the seconds elapsed with the start time to produce absolute rather than relative time measurements.  I then converted that string back into numbers using the command tdate = datenum(ttime), and plotted all the data versus this new time variable. Finally, I changed the formatting of time ticks to just show the hour of the day using the datetick(‘x’,'HH PM’) command. I also created a vector based on the FitBit sleep data, which I had to manually grab from the app by sliding my finger around the plot and noting the start and stop times of “restlessness”. This was then overlaid ontop of the accelerometer data (as shown below), with an arbitrary magnitude.

Plot of Raw Output Data Versus FitBit Data

Needless to say, I was very surprised by this data. First, there was much more movement than I had anticipated given the relatively stable reading from the Fitbit. Second, I was surprised at the low correlation between the data from the Fitbit and the logger. Without doing any quantitative analysis, it is easy to see that Restless Period (RP) 1 is due to a flurry of motion, which most likely represents me trying to fall asleep. RP2 seems to correlate with the spike in logger data which occurs just after it, and the discrepancy in timing could be due to the fact that FitBit quantizes data into 1 minute intervals, as well as differences in timing between the two devices. RP3 corresponds nicely with a large spike in the Y Axis, however the subsequent movements between 3am and 7am do not trigger any “restlessness” events, and there does not appear to be a clear trigger for restlessness based on either magnitude or duration of movement, which is somewhat perplexing. Perhaps FitBit’s algorithm is more nuanced, and takes into account the predicted sleep cycle. For example, the extended period of stillness from about 1230am to 130am might have registered as the first REM cycle, such that motion which occurred 4 hours latter in the next cycle was ignored because the algorithm predicted that I would be in REM sleep once again. It should also be noted that I was not sleeping alone during this data collection cycle, but as the data shows, there was nothing going on but sleeping because there are no high frequency, sinusoidal movements…. Giggity.

## 100 Step Trial

In order to test the logger in a real world situation I needed to mount it. I chose the wrist as the test location, so that its data could be easily compared to that from a FitBit or other activity tacker. I bought several wrist bands from Amazon, and used electrical tape to secure it to \$5 nylon band. I thought this would only be a trial solution, but despite the clunkyness of the mounted logger, it actually turned out really well and there was no need to improve upon the mount.

Mounted Logger (Overhead View) Alongside FitBit Flex

Mounted Logger (SideView) Alongside FitBit Flex

Once mounted on my left wrist, I had to decide what to do with my arm while walking. I chose to hold my phone in the monitored hand and walk with my arm stretched out in front of me as shown below. I wanted to keep the step signal as simple as possible and avoid the introduction of any swaying arm motion back and forth at this point. Figured holding my phone would give it additional inertia and help damp out any swaying back and forth (in addition to allowing me to see my fitbit step count).

Hand Position While Walking

With my arm held steady as shown above, I recorded a brief sample of data at 25Hz while standing still in order to see what the baseline measurements for the logger mounted in this location were. I produced the plot below, which includes the average values for the X, Y and Z axes from time t = 5 to t = 17.

3 Axis Plot From Mounted Sensor – (Stationary, i.e. no steps)

The change in the forces at the beginning and end of the plot makes sense, as I had to activate the logger with a magnet while looking at it as you would a watch, and then roll my wrist over to hold the phone as shown in the previous photo. I then had to roll it back to turn the logger off with the magnet at the end of the plot, which took a bit longer. I was initially concerned that the sum of the three highlighted forces did not equal 1, because in a previous post , where the device was sitting at rest on a table, the sum of the all three forces was always approximately equal to 1. I then realized, of course, that is the vector sum of the forces which should be equal to 1, i.e. sqrt(X^2+Y^2+Z^2) == 1. This calculation was not necessary in the first post because the static force of gravity was always parallel to an axis. With fractional components of the gravitational force in each axis as in the above, however, it is extremely important, and the vector sum of 1.0152 for the three values above gave me sufficient confidence in the device to proceed.

With my hand positioned as described, I walked exactly 100 steps at a brisk pace along a flat gravel road while wearing flip flops. My FitBit Flex recorded 101 steps, which is pretty close, and may actually be the more accurate number as I could have miscounted somewhere. I analyzed the raw data (DataPost2) in Matlab, scaled it, and produced the following plot with the mean values for each axis from t = 29 to t = 84 seconds superimposed:

3 Axis Plot From Mounted Sensor – (100 Steps)

The first thing that jumps out in the plot above is that the X and Z axes have flipped position. I think this must be due to a slightly different hand position while walking, which is supported by the very different mean values that the axes are experiencing. Although there was also motion introduced into the data here, this is probably not the primary cause because even during the period of non-motion which occurs after the steps from about t = 85 to t = 110 seconds, the X and Z axis are still flipped. Regardless, trying to compare the two plots in this post based on something as vague as my general arm position is not a good use of time – I will just assume the data logger is correct.

As part of my first real analysis of accelerometer data, I thought I would just do a simple peak detector to see if I could get some code running in Matlab. I created a Matlab script (myfirstpeakfinder) which to accomplish this, which generally runs as follows:

1. Load raw data into Matlab; scale to G units
2. Run the script, which will prompt the user for the start and stop time of the period they would like to analyze in the data, as well as for the accelerometer sampling frequency.
3. The script then uses the findpeaks function built into matlab, and passes it inputs around the minimum peak height and the minimum distance between peaks (‘MINPEAKHEIGHT’ and ‘MINPEAKDISTANCE’). I used the mean value of the data for a given axes in the given time frame as the minimum height (so as not to double count cycles), and set the minimum peak distance to 10 samples. In the future, it would be interesting to run a FFT on the data, figure out what the average frequency of my walk is, and then have that data inform the minimum distance between steps. But let’s just keep it simple for now….
4. The peak data are then plotted back onto the original input data, which have been cropped by the start and stop times.
5. The number of Peaks, aka “Steps”, are then displayed for the data from each axis, along with an average of all the axes.

By selecting only the cleanest portion of the data, from time t = 29 to t =  84, and keeping the min distance between peaks at 10 samples, I was able to generate the following plot:

3 Axis Plot From Mounted Sensor – (100 Steps, Analyzed with myfirstpeakdetector.m)

The diamonds indicate detected peaks, and the the data for each axis were as follows:

Matlab Output (Better To Be Lucky Than Smart!)

Now, there are obviously many issues with the algorithm, but it felt pretty damn good to achieve the same accuracy as my flex (+/- 1 Step) on the very first trial! Of course, taking a larger bite of data completely blows up the script, and inputting a minimum peak distance other than the one I serendipitous happened to input on the first trial dramatically decreases the accuracy. But – it’s a start. The next thing I would like to do is create an aggregate metric for motion in excess of 1g, and use that to inform the peak detector… more to come on that. But for now, I thought I would also include a sensitivity analysis showing how the average number of steps calculated from t=29 to t=84 is effected by the minimum step distance changing over a series of values:

Sensitivity Analysis: Minimum Number of Samples Between Steps versus Average Number of Steps Calculated