Wednesday, February 6, 2013

Learning by doing: Nike+ and Matlab

I subscribe to the view that the best way to learn a complex and powerful tool or programming language is by doing.

Matlab is particularly nice for dealing with quantitative data. I decided to dive deeper into the tool by coding up a graphing application for my treadmill workouts recorded using the Nike+ application that samples data from the built-in accelerometer of the iPod Nano.

This is not necessarily functionality that I'm currently missing; normally I use Excel or the Nike+ website (based on Adobe Flash). Perhaps Matlab is overkill, but there's something deeply satisfying about smoothing the accelerometer data using just one function call like:

c = smooth(b);

where b and c are vectors. The default is a simple moving average (span 5). But because it's Matlab, you can play with many different smoothing options:

I'm looking to produce a graph like this automatically:

We have three graphs overlaid on top of one another; I'm plotting speed against time:
  1. the raw data (in gray),
  2. the smoothed data (in thick red), and
  3. the treadmill speed setting (in blue)

When the iPod Nano is attached to my Mac, the raw xml file for my workout looks something like this:

The Nano records a datapoint, the cumulative distance in km, every 10 seconds.

We can grab those raw distances between the <extendedData dataType="distance"> and </extendedData> tags using a simple 3 line Perl program, as Matlab is perhaps not the best tool for this job:

The cool thing though is that Matlab can call Perl to stick the distances in a file (distances.txt):


Then we can call the importdata function to read those distances into an array (a):

a = importdata('distances.txt');

To extract the speeds in km/h units, we do a little conversion from our raw cumulative distances in km/10 sec units. It's a shame that the MuPad (symbolic math) part of Matlab is not well-integrated with Matlab proper because the unit::convert system there is cool. For example, you can define your own units like km/10 sec. (Anyway, I couldn't figure out how to make MuPad and Matlab work together.) Fortunately, the function convvel (convert velocity) can do km/s to km/h.

Finally, the rest is just plotting the data points. Setting a few labels and the ticks on the graph. I packaged this whole sequence up in a function called nike and saved it in Documents/Matlab/nike.m:

To use the graphing, I just call the function nike with the xml filename recorded by the iPod. (Matlab knows to look for this function in Documents/Matlab by default.) The call to nike (see below) returns the number of data points (181).

And up pops this graph:

This only works well when I have Matlab already open. For some reason, on my Macbook Pro, Matlab takes forever to start up.

There is a second call above to a function called treadmill, which handles the overlay of my treadmill program onto the iPod data.

I supply a vector [7,15,7.5,5,7,5,7.5,5] describing my workout: this means first 7 mph for 15 mins, followed by 7.5 mph for 5 mins, followed by 7 mph for 5 mins, and finally, 7.5 mph for 5 mins, for a total of 30 minutes. Note this is America, so the treadmill is in mph and I use convvel again to flip the values to km/h. Function implementing this is stored in Documents/Matlab/treadmill.m:

And I get my overlay:

Now, what's also cool about Matlab is that it's both interactive and programmatic. So, after running those two functions, I can simply click on the y-axis and zoom into where I want, resize the graph, add a few more labels, and put up a legend. The result:

So nice and easy.

Actually, the Adobe Flash-based graph from the Nike+ website is not bad either (although we can't have overlays):

No comments:

Post a Comment