Mark Gilbert's Blog

Science and technology, served light and fluffy.

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

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

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

Science Podcast, Episode 23 – Stratoballoon Eggbeater Ground Antenna

Mark and Katherine build an antenna.  Or mangle a kitchen utensil.  Or possibly both.

http://markofquality.wordpress.com/2014/10/06/science-podcast-episode-23-stratoballoon-eggbeater-ground-antenna/

October 6, 2014 Posted by | Science | Comments Off

Stratoballoon – Thank You

Mark and Katherine say a heartfelt "Thank You" to everyone who contributed to the Stratoballoon project.

http://markofquality.wordpress.com/2014/09/23/stratoballoon-thank-you/

September 23, 2014 Posted by | Podcast, Science | Comments Off

Come in ground control: Stratoballoon sketch updated for radio transmitter

It’s been a long time coming, but the main Balloon sketch has finally been updated to include code to control the radio transmitter.  And true to form, the transmitter had what I hope are the final few instrument pack monkey wrenches for us.

I detailed in Episode 22 the work needed to get the NTX2 board attached to the instrument pack.  Once I had that in place, I could incorporate the logic for transmitting over it from the RTTY test radio sketch we had been playing with for the last few months.

Monkey Wrench #1

Before I could drop those pieces in, however, I needed to relearn how to do string concatenation.  I wanted to transmit my call sign, a timestamp, altitude, latitude and longitude in a single comma-delimited string.  These values are a string, and four floating point values, respectively.  If this were straight C, I could use sprintf and format the floating point values to whatever precision I needed.  However, the Arduino C libraries don’t support sprintf for floats.

I could, however, use another built in function call "dtostrf()" which would convert my floats into a character array.  From there, I could use sprintf to concatenate the strings together into my "TransmitBuffer".

Monkey Wrench #2

Doing that, however preserved all of the whitespace in the character arrays.

KD8VZA,            21515.00,              314.28,              0.0000,              0.0000,*9395

It’s at points like these where I realize how spoiled I’ve gotten using a language like C# that supports things like ".Trim()".  Unfortunately, Arduino C doesn’t, so I had to roll my own.

What I ended up with was a routine that would copy one array into another, one byte at a time:

// This copies the SourceBuffer into DestBuffer starting at DestIndex,
// but trims out any leading spaces in SourceBuffer
int TransferBuffer(char* SourceBuffer, int SourceBufferSize, char* DestBuffer, int DestIndex, boolean ShouldAddComma) {
  int BufferIndex = 0;
 
  // Skip all characters from 0-32, but don’t count carriage returns, chr(13)
  while (BufferIndex < SourceBufferSize-1
          && SourceBuffer[BufferIndex] <= 32 && SourceBuffer[BufferIndex] != 13) { BufferIndex++; }
  while (BufferIndex < SourceBufferSize-1) {    
    DestBuffer[DestIndex] = SourceBuffer[BufferIndex];
    DestIndex++;
    BufferIndex++;
  } 
 
  if(ShouldAddComma) {
    TransmitBuffer[DestIndex] = ‘,';
    DestIndex++;
  }

  return DestIndex;
}

The TransmitBuffer method takes the source and destination arrays, the size of the source array, and the current position in the destination array where it needs to start writing.

The method starts by skipping past any whitespace or non-printable characters in the source array, except for carriage returns (character 13).

Once I know where in the source array I need to start copying, I copy the bytes into the destination array one by one, until I reach the end of the source array.  In that main loop, I’m keeping track of where I am in the destination array – this index will be the function’s return value.

The very last thing I do it check to see if I should append a comma to the end of the new string.  That is determined by the last parameter to the TransferBuffer array, ShouldAddComma.

Putting Monkey Wrenches 1 and 2 together

My original version of the TransmitDataToGround function uses these two solutions – dtostrf and TransferBuffer – to combine the call sign, timestamp, altitude, latitude, and longitude into a single string that can be transmitted over the NTX2:

void TransmitDataToGround(float TimeStamp, float Altitude, float Latitude, float Longitude) {
 
  // Build the string to transmit
  dtostrf(TimeStamp, 20, 3, TimeStampBuffer);
  dtostrf(Altitude, 20, 3, AltitudeBuffer);
  dtostrf(Latitude, 20, 5, LatitudeBuffer);
  dtostrf(Longitude, 20, 5, LongitudeBuffer);

  int TransmitIndex = 0;
  TransmitIndex = TransferBuffer(CALL_SIGN, sizeof(CALL_SIGN), TransmitBuffer, TransmitIndex, true);
  TransmitIndex = TransferBuffer(TimeStampBuffer, sizeof(TimeStampBuffer), TransmitBuffer, TransmitIndex, true);
  TransmitIndex = TransferBuffer(AltitudeBuffer, sizeof(AltitudeBuffer), TransmitBuffer, TransmitIndex, true);
  TransmitIndex = TransferBuffer(LatitudeBuffer, sizeof(LatitudeBuffer), TransmitBuffer, TransmitIndex, true);
  TransmitIndex = TransferBuffer(LongitudeBuffer, sizeof(LongitudeBuffer), TransmitBuffer, TransmitIndex, true);

  unsigned int CHECKSUM = gps_CRC16_checksum(TransmitBuffer);  // Calculates the checksum for this datastring
  sprintf(TransmitBufferChecksum, "*%04X\n", CHECKSUM);
  TransmitIndex = TransferBuffer(TransmitBufferChecksum, sizeof(TransmitBufferChecksum), TransmitBuffer, TransmitIndex, false);
 
  rtty_txstring (TransmitBuffer);
}

The logic for calculating the checksum, and the rtty_txstring() function which does the actual transmission, come from the UKHAS site.

Monkey Wrench #3

Once I had TransmitDataToGround() in place, I needed to determine how frequently to call it.  I ultimately decided that I would transmit every 10th reading (where a "reading" is a sampling of the temperature, pressure, and GPS sensors).  I updated the last section of the main loop logic (which checked that it had a good temperature and GPS reading before logging the reading) to include this call. 

// Now that we have a good GPS and temperature reading, grab
// the rest of the data, and log it.
if(HasGoodGPSReading && HasGoodTempReading)
{
  CurrentPressure = GetPressure(bmp085ReadUT(), bmp085ReadUP());
  CurrentAltitude = CalculateAltitude(CurrentPressure);
 
  PrintToSerialOutput(CurrentTimeStamp, CurrentTemp, CurrentPressure, CurrentAltitude, CurrentLatitude, CurrentLongitude);
  WriteDataToLogger(CurrentTimeStamp, CurrentTemp, CurrentPressure, CurrentAltitude, CurrentLatitude, CurrentLongitude);

  if(TransmitNumber > TRANSMIT_EVERY_Nth_READING) {
    TransmitDataToGround(CurrentTimeStamp, CurrentAltitude, CurrentLatitude, CurrentLongitude);
    TransmitNumber = 0;
  } else {
    TransmitNumber++;
  }
 
  HasGoodGPSReading = false;
  HasGoodTempReading = false;
}

 

I added a new loop index called "TransmitNumber" that I would increment with every reading, and reset when I invoked TransmitDataToGround().

All appeared to be fine at first – the data was coming through exactly as I had expected.  However, I noticed that the radio wasn’t ever turning off in between transmissions.  During the nine readings that weren’t being transmitted, it would generate a solid tone.  I needed to be able to programmatically enable and disable the transmitter.  That led me to rewire the NTX2 – for full details, see the Episode 22 Addendum.

Once I had digital pin 5 wired up properly, I reworked TransmitDataToGround() to turn the transmitter at the beginning, and turn it off again at the end.

void TransmitDataToGround(float TimeStamp, float Altitude, float Latitude, float Longitude) {
 
  // Build the string to transmit
  digitalWrite(RADIO_ENABLE_PIN, HIGH);

  dtostrf(TimeStamp, 20, 3, TimeStampBuffer);
  dtostrf(Altitude, 20, 3, AltitudeBuffer);
  dtostrf(Latitude, 20, 5, LatitudeBuffer);
  dtostrf(Longitude, 20, 5, LongitudeBuffer);

  int TransmitIndex = 0;
  TransmitIndex = TransferBuffer(CALL_SIGN, sizeof(CALL_SIGN), TransmitBuffer, TransmitIndex, true);
  TransmitIndex = TransferBuffer(TimeStampBuffer, sizeof(TimeStampBuffer), TransmitBuffer, TransmitIndex, true);
  TransmitIndex = TransferBuffer(AltitudeBuffer, sizeof(AltitudeBuffer), TransmitBuffer, TransmitIndex, true);
  TransmitIndex = TransferBuffer(LatitudeBuffer, sizeof(LatitudeBuffer), TransmitBuffer, TransmitIndex, true);
  TransmitIndex = TransferBuffer(LongitudeBuffer, sizeof(LongitudeBuffer), TransmitBuffer, TransmitIndex, true);

  unsigned int CHECKSUM = gps_CRC16_checksum(TransmitBuffer);  // Calculates the checksum for this datastring
  sprintf(TransmitBufferChecksum, "*%04X\n", CHECKSUM);
  TransmitIndex = TransferBuffer(TransmitBufferChecksum, sizeof(TransmitBufferChecksum), TransmitBuffer, TransmitIndex, false);
 
  rtty_txstring (TransmitBuffer);
  digitalWrite(RADIO_ENABLE_PIN, LOW);
}

Monkey Wrench #4

I found that when I enabled the transmitter, I was losing several characters off of the beginning.  This was because dl-fldigi needed 2-3 seconds between when the transmitter booted up until it actually started sending data to find the signal again, and start decoding it.  I added a 3-second delay to TransmitDataToGround, right after I enabled the transmitter, to provide this buffer.

void TransmitDataToGround(float TimeStamp, float Altitude, float Latitude, float Longitude) {
 
  // Build the string to transmit
  digitalWrite(RADIO_ENABLE_PIN, HIGH);
  delay(3000);
  dtostrf(TimeStamp, 20, 3, TimeStampBuffer);
  dtostrf(Altitude, 20, 3, AltitudeBuffer);
  dtostrf(Latitude, 20, 5, LatitudeBuffer);
  dtostrf(Longitude, 20, 5, LongitudeBuffer);

  int TransmitIndex = 0;
  TransmitIndex = TransferBuffer(CALL_SIGN, sizeof(CALL_SIGN), TransmitBuffer, TransmitIndex, true);
  TransmitIndex = TransferBuffer(TimeStampBuffer, sizeof(TimeStampBuffer), TransmitBuffer, TransmitIndex, true);
  TransmitIndex = TransferBuffer(AltitudeBuffer, sizeof(AltitudeBuffer), TransmitBuffer, TransmitIndex, true);
  TransmitIndex = TransferBuffer(LatitudeBuffer, sizeof(LatitudeBuffer), TransmitBuffer, TransmitIndex, true);
  TransmitIndex = TransferBuffer(LongitudeBuffer, sizeof(LongitudeBuffer), TransmitBuffer, TransmitIndex, true);

  unsigned int CHECKSUM = gps_CRC16_checksum(TransmitBuffer);  // Calculates the checksum for this datastring
  sprintf(TransmitBufferChecksum, "*%04X\n", CHECKSUM);
  TransmitIndex = TransferBuffer(TransmitBufferChecksum, sizeof(TransmitBufferChecksum), TransmitBuffer, TransmitIndex, false);
 
  rtty_txstring (TransmitBuffer);
  digitalWrite(RADIO_ENABLE_PIN, LOW);
}

Now when the radio turns on, the waterfall in dl-fldigi looks like this:

10

The blank horizontal line in the waterfall above shows this 3-second delay.  The red line that starts out horizontal, and then quickly curves to be vertical is the data coming over the airwaves.  That red line, and the accompanying one to the left, need to be lined up with the two thin red lines that make up the dl-fldigi cursor.  Until those two pairs of lines line up, nothing is decoded. 

I also found that the transmitter will drift slightly while it is transmitting, and that the dl-fldigi cursor will drift in between transmissions.  The 3-second delay gives me a chance to adjust the cursor if I need to when the next transmission starts.

Monkey Wrench #5

Even with the delay, I found I was still losing characters off the beginning of the transmission string.  I solved this by simply appending more than one copy of my call sign to the beginning.  As a result, the transmitted strings usually ends up looking like this now:

jf7&VZA-KD8VZA-KD8VZA,21515.00,314.28,0.0000,0.0000,*9395

Finally, I adjusted the squelch control in dl-fldigi to avoid having so much garbage between transmissions appear in the output window.  I still get some, but it’s not the constant barrage that it was when I started.

***

It feels good to be able to put this piece of the balloon to rest.  I may end refactoring the code a little, or adjusting it based on our instrument pack endurance/distance test, but otherwise I think its basically there.           

You can get the newly completed sketch from GitHub

July 8, 2014 Posted by | Science | Comments Off

Science Podcast, Episode 22 – Stratoballoon Radio Part 2

In this episode, Mark finally finishes the balloon’s antenna.

http://markofquality.wordpress.com/2014/07/01/science-podcast-episode-22-stratoballoon-radio-part-2/

July 1, 2014 Posted by | Podcast, Science | Comments Off

Stratoballoon Radio Details

Towards the end of our last podcast, I did a bit of hand-waving when it came to how we sent and received the test beacon data over the radio.  I quickly walked through the setup of the major pieces of software involved, but skipped over all of the details.  Today, I’ll be walking through those weeds.

On the transmission side, we have the second sample sketch available from the UKHAS site (link: http://TinyURL.com/UKHAS-NTX2 ) running on the Arduino sending the test beacon data through the NTX2 transmitter.

On the receiving side, there are actually three pieces of software at work:

  1. SDR#, pronounced "SDR-sharp", which is used to pull the raw radio signals off of the NooElec receiver
  2. dl-fldigi, which is used to translate the audio signals back into data
  3. VB-Audio Virtual Cable, which as the name implies is a virtual audio cable between SDR# and dl-fldigi

When I first got the SDR in the mail, I didn’t try transmitting the test beacon data right away.  My first test was actually to get the base software installed and try tuning in a local radio station.  For that test, I found some extremely helpful comments on the Amazon page that I purchased it from.  Those instructions involved going to NooElec’s site, downloading the Zadig driver installer and SDR# from there.  I did, and was in very short order up and running.  Here are the exact steps I took:

  • Went to NooElec’s site, and the product page for the R820T SDR Receiver: http://www.nooelec.com/store/sdr/sdr-receivers/tv28tv2-sdr-dvb-t-usb-stick-set.html#.UzbdOahdXNk
  • Went to Downloads, and downloaded the SDR# AutoInstaller
  • Extracted the downloader, and ran the Install.bat that came with it
  • Plugged in the USB stick. When Windows prompted me to install drivers, I cancelled it.  I can’t remember if it asked me to do this more than once, but if it did, I cancelled both attempts.
  • I ran Zadig.exe.  This is one of the EXEs that was installed to the /sdrsharp folder created by Install.bat.  It should have had WinUSB selected by default. I clicked "Install Drivers".  I closed Zadig when it finished.
  • I plugged in the antenna.
  • I ran SDR#.
  • To initially test it, I first selected "RTL-SDR / USB" from the drop down (my device), then clicked "Configure".

10
And configured it as follows:

20
I think the key things that I tweaked on this dialog were the Sample Rate and the RF Gain.

  • I clicked Close to return to the main screen.
  • I set the frequency to 107.7 MHz, a local rock station, checked "WFM" (Wide FM) and hit "Play". 

30

That worked – I could hear the radio station coming in fairly clearly, even in my basement, and I could then use the mouse wheel to change frequencies to other radio stations.  I could also change it manually.

Now that I had the receiver and SDR# working, it was time to try it out with the NTX2.  To decode the data, we would be using dl-fldigi, which was a free download.  While the source code is available off of Github, there are installers and binaries available off of the UKHAS site here: http://ukhas.org.uk/projects:dl-fldigi.  Once that was installed, I fired it up.

I initially spent 15 minutes or so trying to figure out a way to feed the output of SDR# directly the input of dl-fldigi, but didn’t have any luck.  I began to wonder if I needed something else to bridge the gap.  I found yet another page on the UKHAS site that described just such a bridge: VB-Audio

After I installed this, I rebooted my machine, and then followed the rest of the instructions found here:

  • Go into Control Panel / Hardware and Sound / Sound / Recording
  • You should see an input called Virtual Audio Cable.  Click properties and rename it to SDR.

40

  • Click the "Listen" tab
  • Check the "Listen to This Device" checkbox

50

  • Close the dialog
  • Stop SDR# and under the Audio section select "[MME] CABLE Input (VB-Audio Virtual C".  (I also played around with the main settings, and ultimately landed on a Filter Type of "Blackman-Harris 7" and a Filter bandwidth of "2400".  I honestly don’t know how much of a difference this makes yet.)

60

  • I clicked start, but had to do a couple of things before I could hear the test beacon through my speakers:
    • I had to change the receiver from WFM mode to USB, or "Upper Side Band"

70

    • I had to position the red line just to the left of the signal, otherwise it wouldn’t work.

80

    • Even though the NTX2 reports that it was transmitting at 434.650 MHZ, I could only really pick up the signal if I tuned the receiver to 434.635 MHZ.
  • Next, I started dl-fldigi again.  I clicked Op Mode / RTTY / Custom / Audio / PortAudio / Capture, and selected "CABLE Output (VB-Audio Virtual" from the drop down.  I clicked Close to return to the main screen.

90

Before I could actually see the test beacon correctly, I had to be sure that dl-fldigi was configured to decode it.  The instructions for this are described in http://TinyURL.com/UKHAS-NTX2, and the actual configuration is done under Op Mode / RTTY / Custom / Modems:

95

Finally, once I had everything configured, I had to adjust where the two red "data" lines appeared in the waterfall trace by tuning SDRSharp.  Once I could see that, I could match the two red "tuning" lines with the data lines, and actually start seeing data appear in the data box.

100

I found a few different ways that the tuning lines and the data lines wouldn’t match up:

First, if the two in the latter were too far apart, they wouldn’t match up with the data lines in the waterfall trace.

110
To fix that, I needed to adjust the carrier shift (otherwise, I wouldn’t see the data coming through).

120

 

Second, if the red lines were lined up with the signal in the waterfall, I would only see gibberish in the data window.

130

To fix that, I simply clicked the left data line in the waterfall to force the tuning line to match it.  The other line would stay in lockstep, always the same distance away (as determined by the carrier shift).

Finally, I also found that as I tuned SDR# up or down, the data lines in dl-fldigi would slide left or right.  If I let the signal slide away from the SDR# band completely, it would disappear from the waterfall trace in dl-fldigi.  This is something I need to keep in mind if I have problems getting the data to come in properly when we were out in the field trying to track the balloon while it was in flight.

There you have it.  The basic setup for our transmission and receiving station.  We still have a long way to go to getting the NTX2 fully incorporated into the instrument cluster, but Katherine and I feel we at least have a good foundation now.

May 8, 2014 Posted by | Science | Comments Off

Pixie Password Policy

One of our recent movie acquisitions was The Pirate Fairy, the fifth in Disney’s "Fairies" series, which shows Tinker Bell’s origins and develops the entire Pixie Hollow universe.  Don’t let the fact that these have never been in the theater* fool you – these movies have good stories, have great characters, are well-cast, and they’re funny!

"The Pirate Fairy" is about a dustkeeper named Zarina.  Pixie dust, you see, is what enables the fairies (and anything else) to fly, and it’s up to the dustkeepers to manage and distribute it.  Up until this movie, we know about two major kinds of dust – the golden pixie dust that you see getting sprinkled on everything, and a much rarer blue dust.  The blue dust is so rare and precious, in fact, that the dustkeepers actually keep it in a locked vault.  All of the dustkeepers apparently have the combination because one of the earliest scenes is of Zarina pulling "blue dust duty", which involves her and her boss, Fairy Gary, opening the vault to take some of the blue dust out for use.

Now, Zarina is not just any dustkeeper.  She’s an inquisitive dustkeeper.  A VERY inquisitive dustkeeper.  In her spare time, Zarina has been running a few, shall we say, "unsanctioned" experiments with pixie dust, trying to learn more about what it can do.  When one of her experiments gets away from her, Fairy Gary fires her.  She packs up her things, and leaves Pixie Hollow.

A year later, she returns during a festival where all of the fairies are gathered at the stadium, and puts all of them to sleep using poppy pollen – all except our heroes, of course.  She then proceeds to open the vault and steals all of the blue pixie dust.  I won’t ruin the rest of the movie for you, but it does have a happy ending.

***

What I’m going to focus on, though, is actually Fairy Gary and his lack of good password policies.  Let’s start with the sheer number of people that know the combination to the vault holding probably the most precious thing in all of Pixie Hollow.  How many dustkeepers do you have in your employ, Gary?  Do they ALL really need full admin rights?

And then there’s the fact that you haven’t change the combination to the vault in at least a year.  Even if Zarina hadn’t left, good password hygiene demands that a combination like this should be rotated every couple of months – at the minimum.

But then you fired an employee with full admin access.  That event alone should have triggered an immediate change to the combination.

And do I really need to even ask?  We’re only talking ONE combination to be changed here.  How much effort does it really take to change and distribute the new combination, really?

Sigh.  All this trouble could have been thwarted had Fairy Gary just used some basic system administration best practices.

 

* Well, almost never – accordingly to IMDB, Tinker Bell and the Lost Treasure apparently spent a week in the theaters in LA, just long enough to qualify for the 2010 Oscars.

May 6, 2014 Posted by | General | Comments Off

Science Podcast, Episode 21 – Stratoballoon Radio Part 1

Mark and Katherine try to cut through the gibberish and static, and get their radio transmitter working:

http://markofquality.wordpress.com/2014/05/03/science-podcast-episode-21-stratoballoon-radio-part-1/

May 3, 2014 Posted by | Podcast, Science | Comments Off

Follow

Get every new post delivered to your Inbox.