High Speed Balloon Data Link

Today Mark and I spent an afternoon working on a 115 kbit/s FSK data system for high altitude balloons. Here is a video of Mark demonstrating the system:

In our previous tests, we needed -75dBm to get jpeg images through the system, much higher that the calculated MDS of -108dBm + NF. So we devised a series of tests – “divide and conquer” – to check various parts of the system in isolation.

First, some SDR noise figure tests. We added to these measurements today by trying a few SDRs with a low noise pre-amplifier. First, we measured the pre-amp NF. This was quoted as 0.6dB, we measured 2dB with the spec-an (which has 1.5dB uncertainty). We then tested combinations of the pre-amp with various SDR gains:

RTLSDR G=20.......: Pin: -100.0 Pout: 15.5 G: 115.5 NF: 19.4 dB
RTLSDR G=50.......: Pin: -100.0 Pout: 38.8 G: 138.8 NF:  5.6 dB
RTLSDR G=50 Preamp: Pin: -100.0 Pout: 59.0 G: 159.0 NF:  2.0 dB
AirSpy G=10.......: Pin: -100.0 Pout: -1.0 G: 99.0  NF: 19.4 dB
AirSpy G=21.......: Pin: -100.0 Pout: 33.9 G: 133.9 NF:  6.7 dB
AirSpy G=21 Preamp: Pin: -100.0 Pout: 53.1 G: 153.1 NF:  2.8 dB

The RTLSSDR was a R820T and the pre-amp model number PSA4-5043.

When the pre-amp was used, it boosted the overall gain of the system, and set the system NF to 2dB. It was great to see system NFs close to our measured pre-amp NF – gave us some confidence that our measurements were OK.

The SDRs require high RF gain levels to achieve a low NF. We did notice that at high RF gain levels, birdies appeared in the SDR output spectrum, and there were some signs of compression. We will look into SDR gain distribution more in future.

Testing The Modem Off Line

I wanted to test the modem over the RF link, and the best way to do that is with a BER test. Mark configured the Rpi Tx to send fixed frames of known test data. We used a HackRF to down-convert the received FSK test frames and store them to file.

The data rate of the link is Rs=115.2 kbit/s, which is sampled by the demodulator at Fs = 115200*8 = 921.6 kHz. However to the modem it just looks like an 8 times oversampled signal. So here is 10 seconds of the modem signal replayed at Fs=9600 Hz. You can hear the packets starting by the sound of the header. When replayed at this low sample rate, the bit rate is 1200 baud, and the packets are a few seconds long. At the full sample rate they are just 23ms long.

The non-real time reference Octave demodulator was used to demodulate the FSK sample files, pop up some plots, and measure the BER. Much easier to see what’s going on with the off-line simulation version of the modem. After a few hours of wrangling with fsk_horus.m, I managed to decode Mark’s test frames.

The tx signal we sampled was noise free, so I added calibrated AWGN noise in the Octave simulation to test BER performance of the real-time FSK modulator and transmitter. It was spot on – 1% BER at an Eb/No of 9dB. Great! I do like FSK – real world implementations (like the FSK tx chip) work quite close to theory. This verified that the hardware tx side was all OK in terms of modem performance.

I did however discover a fairly large baud rate error (sample clock offset), of around 1700ppm. This suggested the tx was actually sending at 115,200*1.0017 = 115.396 kbit/s.

Simultaneously – Mark worked out how to measure the baud rate of the RPi serial port. He used the clever idea of sending 0x55 bytes, which when combined with the RS232 start and stop bits, leads to a …010101010… sequence on the RS232 tx line – a square wave at half the baud rate. We connected a frequency counter, and measured the actual baud rate as 115.387 kbit/s, right in line with my numbers above.

The C version of the demod doesn’t like such a large clock offset (baud rate error), so we tweaked the resampling code to adjust for the error. Could this baud rate error could be our “smoking gun” – the reason such a high rx level was required to push images through?


You need to test receivers at very low signal levels. The problem was a relatively high power transmitter nearby generating the tx signal. In our case, the tx power of 25mW (14dBm) is attenuated down to -110dBm, a total of 124dB attenuation. The tx signal tends to radiate around the attenuator (it is a radio transmitter after all). When you reduce the step attenuator 10dB but the signal on the spec-an doesn’t drop 10dB, you have a RF radiation problem.

We solved this by putting the tx in a metal box in another room, then (at Matt, VK5ZM’s suggestion), connecting the tx to the attenuator and rx using coax with a intentionally high loss at UHF. This keeps the high level tx signals well away from the rx.

Mark fired up the real time code again, adjusted for the baud rate error, and suddenly we were getting much better results – good images at -94dBm. He added the pre-amp, and now we could receive images at -106dBm. This is exactly, almost suspiciously close to what we calculated:

  MDS = Eb/No + 10*log10(B) - 174 + NF
  MDS = 15 + 10*log10(115E3) - 174 + 2
  MDS = -106.4 dBm

It doesn’t usually work out this well ….. guess we are getting our head around this radio caper!

Dropping the signal level to -111dBm meant just a few SSTV packets were making it through. Most of them were bombing on a CRC error. At -111dBm, our Eb/No = 10dB, or a BER of 3E-3. Now our packets are a few thousand bits long, so with BER = 3E-3, we are very likely to cop a few bit errors per packet, which are then discarded due to a CRC fail. So this fits exactly with what was observed at this signal level. Check.

Here a video of Mark running through the experimental set up:

Command Lines

RTLSDR Samples Captured using:

rtl_sdr -s 1000000 -f 440000000 -g 20 - | csdr convert_u8_f > rtlsdr_gain20_sig.bin

AirSpy samples captured using:

airspy_rx -f440.0 -r /dev/stdout -a 1 -h 21  | csdr convert_s16_f > airspy_gain21_sig.bin

Commands for complete end-to-end decoding (assuming csdr is installed):

rtl_sdr -s 1000000 -f 441000000 -g 35 - | csdr convert_u8_f | csdr bandpass_fir_fft_cc 0 0.4 0.1 | csdr fractional_decimator_ff 1.08331 | csdr realpart_cf | csdr convert_f_s16 | ./fsk_demod 2X 8 923096 115387 - - | ./drs232 - - | python rx_ssdv.py --partialupdate 8

The python code is here.

Visualising our Packets

Brady, KC9TPA, the author of the C FSK modems, sent us a neat visualization of our test packet:

You can see the 0x55 bytes in the header, the unique word, then a sequence of 0x0 too 0xff, sent LSB first, with the RS232 start (0) and stop (1) bits.

Brady created that image using a screen capture of this:

xxd -g 10 -c 10 -s 2 115.bin | tr '1' '*' | tr '0' ' '


Measuring SDR Noise Figure

Horus 14 – Tux in (near) Space

5 thoughts on “High Speed Balloon Data Link”

  1. Just to throw another stick in the spokes, I was wondering about the dongles PPM adjustment. When I run my ‘rtl_test -p’ I get a cumulative 62 PPM error. So when I run my reciver I usually inclide the 62 in the rtl_sdr command line.

    To be honest though, I’m not a real dongle expert.

    1. Frequency shift (as a PPM offset in the RTLSDR would result in) won’t really affect this system, as it’ll just result in an offset of the FSK signal within the receiver passband. No symbol rate offset would occur.

      I guess the main issue would be if the RTLSDR’s offset pushes the desired signal towards the filter skirts. Still, that’s why there’s a tuning slider :-)

  2. I looked at the WAV file in Audacity and was surprised to find 3-tones (0, and +/- 600 Hz). Is the no-FSK tone used for sync?

      1. I think it was that 2 kHz tone every second that got my attention. It sort of reminded me of a sync tone I guess.

        Interesting project!

Comments are closed.