Mark Gilbert's Blog

Science and technology, served light and fluffy.

What a Headache

For the last several months, I’ve been working on a new project that I’m tentatively calling "iSelf".  Here is the official version 0.1.0:

10

I’m building my own, custom wearable.  And before you ask, the answer is "no", the title of this blog does not refer to the spaghetti of breadboarding wires you see before you.  The title actually refers to what I hope iSelf will help me with.  Allow me to set this story up.

For more than a decade, I’ve had daily headaches.  I first noticed them as such in 2003.  At that point, I would feel the headache coming on mid- to late afternoon.  I would take two Excedrin with dinner, and by 8pm or so the headache would be gone.  About 2011 or 2012, I started noticing that the headaches were getting longer.  I’d feel them start earlier in the day, and it would be later into the evening before the Excedrin would kick in.

Then during the summer of 2013, I realized that I was waking up with a headache, and Excedrin was no longer knocking them out.  In other words, I’ve had a headache all day, every day, for the last two years.

In late 2013, and then much of 2014, I got even more serious about trying to determine what was causing them.  I spoke with my general doctor about it.  He had me try a couple of different medications.  When those didn’t work, he referred me to a neurologist, who tried a few different medications, which didn’t work.  He also had my head examined – both an MRI (which you can read about here).  Thankfully, nothing abnormal turned up.  They found a brain, and it showed no signs of bleeding or tumors.  Check and check.

I also went to see an ear, nose, and throat doctor.  Even after a CT scan, two home sleep studies, and a third sleep study in an overnight lab, he wasn’t able to find anything wrong with me either.

Whenever I went in for an exam or a follow-up, the doctors would usually ask me "on a scale from 1-10, how is your headache today?" and I would respond with some number.  But that question was asked once every two weeks, at most.  I don’t have the same headache every day – there are some days it is easier to move it to the background than others.  But why?  What is influencing the "badness level"?  If I can’t find a solution to the headaches and make them go away completely, could I find out if there is some external influence affecting their quality?  To answer that, I needed data – lots and lots of data.

So, in late 2014 I started sketching out what kind of data would I want to collect, and how could I analyze it.  I decided that taking readings every 30 minutes of the headache "badness level" was probably a good place to start, but I also wanted to capture things like what temperature and barometric pressure was I being exposed to (two things I’ve read affect headaches in some people).  I also wanted to record how long I stood, sat, and walked in a day.  That’s where the wearable comes in.

I considered buying an existing, off-the-shelf wearable, but after looking at a dozen different brands, I couldn’t find one that recorded the data points I wanted, and as far as I could tell none of them let me get at the raw data that they did collect.  They all had their own cloud- or mobile apps for displaying really pretty, interactive charts, but I none had anything like a "download to Excel" feature.  So, custom it was.

iSelf v0.1.0 features a temperature/pressure sensor that I scavenged off of the stratoballoon instrument pack, a microSD card reader/writer (also from the stratoballon), and an Arduino Micro as the processor.  I’m getting very near to the point where the software is ready, and I can solder the components together, get a case for it, and be able to wear it on my belt like a phone.

Eventually I’ll add an IMU (which stands for inertial measurement unit, a combination of a 3-axis accelerometer and a 3-axis gyroscope) so I can track how long I am sitting/standing/walking, and a Bluetooth Low Energy (LE) module so I can communicate with my mobile device.  The plan is for iSelf to send a signal to the mobile device (initially my Nook, but eventually a phone) to tell me to take a survey every 30 minutes.  I’ll answer one or more questions (how bad is your headache right now, are you hungry, etc.), and the mobile device will transmit the answers back to iSelf, which will add them to the raw data points that it collects directly.  At night, I’ll download the day’s data.

Once I have several weeks’ worth of data, I can start asking questions like "does my headache get worse when I’m hungry?" or "does my headache get better when I’m exposed to higher temperatures?"  I’ll hopefully be able to spot some patterns in the data, and that will allow me to create some experiments to run on myself.

There is a crazy number of things that can cause headaches.  I’ve eliminated a few.  At worst, iSelf will allow me to eliminate a few more.  At best, it will show me a couple that contribute.

July 3, 2015 Posted by | Embedded/Wearable, Science | Leave a comment

Science & Technology Podcast, Episode 30 – Baking Soda and Lemon Juice

In this episode, Mark and Lucy explore mixing acids and bases – and try to avoid volcanoes.  Given that today is the 35th anniversary of Mount St. Helens eruption, we think that’s an admirable goal.

 

https://markofquality.wordpress.com/2015/05/18/science-technology-podcast-episode-30-baking-soda-and-lemon-juice/

May 18, 2015 Posted by | Podcast, Science | Comments Off on Science & Technology Podcast, Episode 30 – Baking Soda and Lemon Juice

Science & Technology Podcast, Episode 29 – Snap Rover

In this episode, Mark and Lucy build an RC Snap Circuits Rover.

https://markofquality.wordpress.com/2015/03/29/science-technology-podcast-episode-29-snap-rover/

March 29, 2015 Posted by | Podcast, Science | Comments Off on Science & Technology Podcast, Episode 29 – Snap Rover

Science Podcast, Episode 28 – Robot!

In this episode, Mark and Lucy build a robot!

https://markofquality.wordpress.com/2015/02/14/science-podcast-episode-28-robot/

February 14, 2015 Posted by | Podcast | Comments Off on Science Podcast, Episode 28 – Robot!

Science Podcast, Epsiode 27 – Stratoballoon Rigging

Mark and Katherine describe how the capsule, radar reflector, parachute, and balloon were all held together.

https://markofquality.wordpress.com/2015/01/19/science-podcast-episode-27-stratoballoon-rigging/

January 19, 2015 Posted by | Podcast, Science | Comments Off on Science Podcast, Epsiode 27 – Stratoballoon Rigging

Science Podcast, Episode 26 – Stratoballoon Capsule Construction, Part 2 of 2

Mark and Katherine finish the details of the stratoballoon capsule construction:

https://markofquality.wordpress.com/2015/01/14/science-podcast-episode-26-stratoballoon-capsule-construction-part-2-of-2/

January 14, 2015 Posted by | Podcast, Science | Comments Off on Science Podcast, Episode 26 – Stratoballoon Capsule Construction, Part 2 of 2

Science Podcast, Episode 25 – Stratoballoon Capsule Construction, Part 1 of 2

Mark and Katherine walk through Part 1 of the stratoballoon capsule construction:

https://markofquality.wordpress.com/2015/01/13/science-podcast-episode-25-stratoballoon-capsule-construction-part-1-of-2/

January 13, 2015 Posted by | Podcast, Science | Comments Off on Science Podcast, Episode 25 – Stratoballoon Capsule Construction, Part 1 of 2

Science Podcast, Episode 24 – Stratoballoon Capsule Recovery!

Mark and Katherine celebrate the recovery of the capsule with some amazing photographs, and Rainbow Dash’s debriefing:

http://markofquality.wordpress.com/2014/11/04/science-podcast-episode-24-stratoballoon-capsule-recovery/

November 4, 2014 Posted by | Podcast, Science | Comments Off on Science Podcast, Episode 24 – Stratoballoon Capsule Recovery!

Will you just wait a minute?! NUnit and Async/Await

I was being a good-doobie.  Honest.

I had written a prototype – just something to prove that a particular approach could work.  It did, and so now it was time for me to actually bring that code up to production quality.  Part of that meant modifying how I was invoking the third-party web services – they  needed to be done asynchronously.

So I went through and wrote my unit tests to also run asynchronously:

        [Test]
        public async void Divide_4DividedBy2_Equals2()
        {
            AsyncUnitTest.Math MathLibrary = new AsyncUnitTest.Math();

            float Quotient = await MathLibrary.Divide(4, 2);

            Assert.AreEqual(2, (int)Quotient);
        }

I ran it through NUnit on my machine, and everything was peachy-keen.  I ended up writing nearly 50 unit tests* like that, converting over all of my calls.  I committed the code, and let TeamCity take over.

And watched every one of those new tests break.

When I looked at the TeamCity log, the errors seemed to hint that the test runner was simply not waiting for the thing under test to complete before trying to run the asserts.  I started searching for things like "nunit async", and pretty quickly across this two-part series by Stephen Cleary:

In this series, Cleary says that the underlying problem of running async tests is that they don’t have a proper context:

We’ve encountered a situation very similar to async in Console programs: there is no async context provided for unit tests, so they’re just using the thread pool context. This means that when we await our method under test, then our async test method returns to its caller (the unit test framework), and the remainder of the async test method – including the Assert – is scheduled to run on the thread pool. When the unit test framework sees the test method return (without an exception), then it marks the method as “Passed”. Eventually, the Assert will fail on the thread pool.

His solution is to simply give the test an async context, and he provides a very handy wrapper to do just that.  I first had to install his Nito.AsyncEx NuGet package, and then wrap my test in AsyncContext.Run:

        [Test]
        public void Divide_4DividedBy2_Equals2_Asynchrofied()
        {
            AsyncContext.Run(async () =>
            {
                AsyncUnitTest.Math MathLibrary = new AsyncUnitTest.Math();

                float Quotient = await MathLibrary.Divide(4, 2);

                Assert.AreEqual(2, (int)Quotient);
            });
        }

Notice that I’ve removed the "async" keyword from the test itself; AsyncContext.Run does all the work here.  After updating and committing my first test using AsyncContext.Run – a test test, if you will – it ran successfully on TeamCity.  I updated the other 48, and finally got a green build.

***

My build was stable again, but Cleary’s explanation didn’t answer the question of why this worked on my machine in the first place – without using his very awesome library – so, I kept digging.

I first looked up exactly what TeamCity was using to run the tests – it was NUnit, the same as what was on my machine, with a minor different in the version.  My local copy was 2.6.2, while the version on the build server was 2.6.1.  Could there be a difference in how 2.6.1 was handling async?

Why yes.  Yes there was.  In the NUnit 2.6.2 release notes I found this:

When running under .NET 4.5, async test methods are now supported. For test cases returning a value, the method must return Task<T>, where T is the type of the returned value. For single tests and test cases not returning a value, the method may return either void or Task.

– Source: http://nunit.org/index.php?p=releaseNotes&r=2.6.2

Are you serious?  I just happen to have the first version of NUnit that would properly handle async on my machine, but the build server was one notch older, and therefore couldn’t?  *facepalm*

To further prove that this was the real source of my issue, I installed NUnit 2.6.1 and 2.6.2 side by side on my machine.  I took my two tests from above, both of which should have tried to execute the MathLibrary.Divide function which included a 2-second delay:

    public class Math
    {
        public async Task<float> Divide(int Numerator, int Denominator)
        {
            await Task.Delay(2000);
            return Numerator / Denominator;
        }
    }

When I ran these two tests through NUnit 2.6.1, Divide_4DividedBy2_Equals2 completes in a couple hundredths of a second, while Divide_4DividedBy2_Equals2_Asynchrofied takes just over 2 seconds to complete, for a total of just over 2 seconds:

2-6-1

When I ran these through NUnit 2.6.2, EACH test takes just over 2 seconds to complete, for a total of just over 4 seconds:

2-6-2

So, I have two choices – switch my builds on TeamCity to use at least NUnit 2.6.2 to run the tests, or use Cleary’s Nito.AsyncEx library, which will allow me to leave the build server as is.  In any event, at least I have a reasonable explanation for what was happening. 

The funny thing is that it’s usually MSBuild that messes with me.  Apparently NUnit gave him the week off.

 


* Yes, I realize that by calling the service directly, this no longer counts as a "unit" test, but rather an integration test.  That distinction isn’t relevant to the issue described in this post, though, so I’m going to gloss over the mock objects in the real code.

October 23, 2014 Posted by | Agile, Visual Studio/.NET | Comments Off on Will you just wait a minute?! NUnit and Async/Await

Balloon Mapper

Our receiving station for the Stratoballoon project consisted of three major pieces of software:

I’ve gone into great depth about how the first two are configured on my technical blog (“Stratoballoon Radio Details”).  Today, I want to talk about the third one, BalloonMapper.  Here is the basic interface:

10

We would copy a dataline out of dl-fldigi and past it into the "Data Line" box (#1).  We could then hit Enter, or manually click the "Find Position" button in the upper right corner.  This would extract the altitude, and the lat/long from the data string.  It would convert the former into feet and display that in the "Altitude" box (#2).  It would also create the Google Maps URL that would show the lat/long as a pin on the map.

What did the data strings look like?  A picture-perfect data string that came off the radio would look like this:

    KD8VZA-KD8VZA-KD8VZA,120057.00,234.11,4214.7460,8533.3750,*4FF4

This is a comma-delimited string, and is made up of the following:

  • My callsign, repeated 3 times
  • A timestamp, in hhmmss.xx format (where the decimal places are ignored)
  • The altitude, in meters
  • The latitude (format explained below)
  • The longitude (format explained below)
  • A termination string, made up of an asterisk, followed by four alphanumeric characters

In most cases the callsigns came out a bit garbled, so it would look more like this:

    a8czZA-KD8VZA-KD8VZA,120057.00,234.11,4214.7460,8533.3750,*4FF4

The first part of the string got chewed up because it took us a second to tune dl-fldigi to lock onto the signal.  That’s the main reason I start the string with three copies – I wanted to give Katherine or I (whoever was working the radio) a second or two to get ahold of the signal.

Extracting the altitude was very straightforward.  Simply grab the 3rd piece of data in the string, multiple it by 3.28 to convert it from meters to feet, and display it in the box.

        public static String GetAltitude(String DataLine)
        {
            String[] DataLineComponents;
            String RawAltitude;

            DataLine = (DataLine ?? "").Trim();
            if (String.IsNullOrEmpty(DataLine)) { return ""; }

            DataLineComponents = DataLine.Split(',');

            RawAltitude = DataLineComponents[2];

            return String.Format("{0} ft", (double.Parse(RawAltitude) * 3.28).ToString("0"));
        }

The lat/long was a bit tricker.  First, I had to get them into a format that Google Maps would understand.  You can browse directly to a specific lat/long point on Google Maps like so:

    https://www.google.com/maps/place/42°17’44.76"N+85°43’22.50"W

The lat/long values, however, always come off the radio in the 4-dot-4 pattern.  Here is how they broke down:

    4214.7460 = 42° 14.7460′

    8533.3750 = 85° 33.3750′

So, I would need to split the degrees from the rest of the string, then convert the fractional arc-minutes into arc-seconds, before I could drop it into Google Maps:

        public static String GetUrl(String DataLine)
        {
            String[] DataLineComponents;
            String RawLat, RawLong, FormattedLat, FormattedLong;

            DataLine = (DataLine ?? "").Trim();
            if (String.IsNullOrEmpty(DataLine)) { return ""; }

            DataLineComponents = DataLine.Split(',');

            RawLat = DataLineComponents[3];
            RawLong = DataLineComponents[4];

            FormattedLat = String.Format("{0}°{1}'{2}\"", RawLat.Substring(0, 2),
                                                          RawLat.Substring(2, 2),
                                                          (double.Parse(RawLat.Substring(4)) * 60).ToString("00.00"));
            FormattedLong = String.Format("{0}°{1}'{2}\"", RawLong.Substring(0, 2),
                                                           RawLong.Substring(2, 2),
                                                           (double.Parse(RawLong.Substring(4)) * 60).ToString("00.00"));

            return String.Format("https://www.google.com/maps/place/{0}N+{1}W", FormattedLat, FormattedLong);
        }

So, now I had my URL.  I needed a way to embed a browser into BalloonMapper, which was a Windows desktop app.  I looked at a few options, but eventually settled on Gecko Effects: https://bitbucket.org/geckofx/geckofx-29.0/downloads.

I created a Gecko.GeckoWebBrowser object on my form called "GoogleMaps".  To browse to a URL, I simply called the .Navigate() method on the GoogleMaps object, and passed it the URL that I generated above:

                this.GoogleMaps.Navigate(GetUrl(this.DataLineBox.Text));

 

Using it was easy.  Getting the control installed and working was a little more difficult, and I had a few false starts.  In the end, here is what worked:

  • I downloaded Gecko Effects 29.0 (see link above).
  • Gecko requires another application called "xulrunner", which I obtained from here: http://ftp.mozilla.org/pub/mozilla.org/xulrunner/releases/29.0.1/runtimes/
  • I found that I needed to match the version of xulrunner to the version of Gecko, otherwise I got a "Specified cast is not valid" error.
  • I also found that the program has to be installed to a folder called "xulrunner" – all lowercase – or it wouldn’t work.

This made finding the capsule’s current location extremely easy:

20

For full source code and binaries, please visit http://TinyURL.com/MarkGilbertSource, and look for the BalloonMapper.zip archive.

October 10, 2014 Posted by | Science, Visual Studio/.NET | 1 Comment

Follow

Get every new post delivered to your Inbox.