Horus 37 – High Speed SSTV Images

Today I was part of the AREG team that flew Horus 37 – a High Altitude Balloon flight. The payload included hardware sending Slow Scan TV (SSTV) images at 115 kbit/s, based on the work Mark and I documented in this blog post from earlier this year.

It worked! Using just 50mW of transmit power and open source software we managed to receive SSTV images at bit rates of up to 115 kbit/s:

More images here.

Here is a screen shot of the Python dashboard for the FSK demodulator that Mark and Brady have developed. It gives us some visibility into the demod state and signal quality:

(View-Image on your browser to get a larger version)

The Eb/No plot shows the signal strength moving up and down over time, probably due to motion of our car. The Tone Frequency Estimate shows a solid lock on the two FSK frequencies. The centre of the Eye Diagram looks good in this snapshot.

Octave and C LDPC Library

There were some errors in received packets, which appear as stripes in the images:

On the next flight we plan to add a LDPC FEC code to protect against these errors and allow the system to operate at signal levels about 8dB lower (more than doubling our range).

Bill, VK5DSP, has developed a rate 0.8 LDPC code designed for the packet length of our SSTV software (2064 bits/packet including checksum). This runs with the CML library – C software designed to be called from Matlab via the MEX file interface. I previously showed how the CML library can be used in GNU Octave.

I like to develop modem algorithms in GNU Octave, then port to C for real time operation. So I have put some time into developing Octave/C software to simulate the LDPC encoded FSK modem in Octave, then easily port exactly the same LDPC code to C. For example the write_code_to_C_include_file() Octave function generates a C header file with the code matrices and test vectors. There are test functions that use an Octave encoder and C decoder and compare the results to an Octave decoder. It’s carefully tested and bit exact to 64-bit double precision! Still a work in progress, but has been checked into codec2-dev SVN:

ldpc_fsk_lib.m Library of Octave functions to support LDPC over FSK modems
test_ldpc_fsk_lib.m Test and demo functions for Octave and C library code
mpdecode_core.c CML MpDecode.c LDPC decoder functions re-factored
H2064_516_sparse.h Sample C include file that describes Bill’s rate 0.8 code
ldpc_enc.c Command line LDPC encoder
ldpc_dec.c Command line LDPC decoder
drs232_ldpc.c Command line SSTV deframer and LDPC decoder

This software might be useful for others who want to use LDPC codes in their Matlab/Octave work, then run them in real time in C. With the (2064,512) code, the decoder runs at about 500 kbit/s on one core of my old laptop. I would also like to explore the use of these powerful codes in my HF Digital Voice work.

SSTV Hardware and Software

Mark did a fine job putting the system together and building the payload hardware and it’s enclosure:

It uses a Raspberry Pi, with a FSK modulator we drive from the Pi’s serial port. The camera aperture is just visible at the front. Mark has published the software here. The tx side is handled by a single Python script. Here is the impressive command line used to start the rx side running:

#!/bin/bash
# 
#	Start RX using a rtlsdr. 
# 
python rx_gui.py & 
rtl_sdr -s 1000000 -f 441000000 -g 35 - | csdr convert_u8_f | csdr bandpass_fir_fft_cc 0.1 0.4 0.05 | csdr fractional_decimator_ff 1.08331 | csdr realpart_cf | csdr convert_f_s16 | ./fsk_demod 2XS 8 923096 115387 - - S 2> >(python fskdemodgui.py --wide) | ./drs232_ldpc - - | python rx_ssdv.py --partialupdate 16

We have piped together a bunch of command line utilities on the Linux command line. A hardware analogy is a bunch of electronic boards on a work bench connected via coaxial jumper leads. It works quite well and allows us to easily prototype SDR radio systems on Linux machines from a laptop to a RPi. However down the track we need to get it all “in one box” – a single, cross platform executable anyone can run.

Next Steps

We did some initial tests with the LDPC decoder today but hit integration issues that flat lined our CPU. Next steps will be to investigate these issues and try LDPC encoded SSTV on the next flight, which is currently scheduled for the end of October. We would love to have some help with this work, e.g. optimizing and testing the software. Please let us know if you would like to help!

Links
Mark’s blog post on the flight
AREG blog post detailing the entire flight, including set up and recovery
High Speed Balloon Data Link – Development and Testing of the SSTV over FSK system
All your Modems are belong to Us – The origin of the “ideal” FSK demod used for this work.
FreeDV 2400A – The C version of this modem developed by Brady and used for VHF Digital Voice
LDPC using Octave and CML – using the CML library LDPC decoder in GNU Octave

SM2000 – Part 8 – Gippstech 2016 Presentation

Justin, VK7TW, has published a video of my SM2000 presentation at Gippstech, which was held in July 2016.

Brady O’Brien, KC9TPA, visited me in June. Together we brought the SM2000 up to the point where it is decoding FreeDV 2400A waveforms at 10.7MHz IF, which we demonstrate in this video. I’m currently busy with another project but will get back to the SM2000 (and other FreeDV projects) later this year.

Thanks Justin and Brady!

FreeDV and this video was also mentioned on this interesting Reddit post/debate from Gary KN4AQ on VHF/UHF Digital Voice – a peek into the future

SM2000 Part 7 – Prototype Ready for Manufacture

Rick, KA8BMA, has been working steadily on the CAD work for the SM2000 VHF Radio and the Rev A (prototype) PCB layout is now complete and ready for manufacture. Neil, VK5KA, an experienced RF Engineer, has been working with Rick on the PCB layout to ensure RF integrity. Thank you both for your fine work!

Here is the top layer of Rev A, which is 160mm x 160mm:

It’s a modular design, if you zoom in you can see the names of each module.

Edwin at Dragino is kindly assembling some prototypes for us, and I hope to start bringing up the board in early June.

Links

SM2000 Part 1 – Introducing the SM2000 project

SM2000 SVN – CAD Files for the project

Project Whack a Mole Part 2

I’ve been steadily working on this project so here is an update. You might like to review Part 1 which describes how this direction finding system works.

The good news is it works with real off-air radio signals! I could detect repeatable phase angles using two antennas with an RF signal, first in my office using a signal generator, then with a real signal from a local repeater. However the experimental set up was delicate and the software slow and cumbersome. So I’ve put some time into making the system easier to use and more robust.

New RF Head

I’ve built a new RF Head based on a NE602 active mixer:


The 32 kHz LO is on the RHS of the photo. Here is the saga of getting the 32kHz oscillator to run.

The mixer has an impedance of about 3000 ohms across it’s balanced inputs and outputs so I’ve coupled the 50 ohm signals with a single turn loop to make some sort of impedance match. The tuned circuits also give some selectivity. This is important as I am afraid the untuned HackRF front end will collapse with overload when I poke a real antenna up above the Adelaide Plains and it can see every signal on the VHF and UHF spectrum.

Antenna 1 (A1) is coupled using a tapped tuned circuit, and with the mixer output forms a 3 winding transformer. Overall gain for the A1 and A2 signals is about -6dB which is OK. The carrier feed through from the A2 mixer is 14dB down. Need to make sure this carrier feed through stays well down on A1 which is on the same frequency. Otherwise the DSP breaks – it assumes there is no carrier feed through. In practice the levels of A1 and A2 will bob about due to multipath, so some attenuation of A2 relative to A1 is a good idea.

Real Time-ish Software

I refactored the df_mixer.m Octave code to make it run faster and make repeated system calls to hackrf_transfer. So now it runs real time (ish); grabs a second of samples, does the DSP foo, plots, then repeats about once every 2 seconds. Much easier to see whats going on now, here it is working with a FM signal:

You can “view image” on your browser for a larger image. I really like my “propeller plot”. It’s a polar histogram of the angles the DSP comes up with. It has two “blades” due to the 180 degree ambiguity of the system. The propellor gets fatter with low SNR as there is more uncertainty, and thinner with higher SNR. It simultaneously tells me the angle and the quality of the angle. I think that’s a neat innovation.

Note the “Rx signal at SDR Input” plot. The signals we want are centered on 48kHz (A1), 16 and 80kHz (A2 mixer products). Above 80kHz you can see the higher order mixer products, more on that below.

Reflections

As per Part 1 the first step is a bench test. I used my sig gen to supply a test signal which I split and fed into A1 and A2. By adding a small length of transmission line (38mm of SMA adapters screwed together), I could induce known amounts of phase shift.

Only I was getting dud results, 10 degrees one way then 30 the other when I swapped the 38mm segment from A1 to A2. It should be symmetrical, same phase difference but opposite.

I thought about the A1 and A2 ports. It’s unlikely they are 50 ohms with my crude matching system. Maybe this is causing some mysterious reflections that are messing up the phase at each port? Wild guess but I inserted some 10dB SMA attenuators into A1 and A2 and it started working! I measured +/- 30 +/-1 degrees as I swapped the 38mm segment. Plugging 38mm into my spreadsheet the expected phase shift is 30.03 degrees. Yayyyyyyy…..

So I need to add some built-in termination impedance for each port, like a 6dB “pad”. Why are they called “pads” BTW?

The near-real time software and propeller plot made it really easy to see what was going on and I could see and avoid any silly errors. Visualisation helps.

Potential Problems

I can see some potential problems with this mixer based method for direction finding:

  1. If the spectrum is “busy” and other nearby channels are in use the mixer will plonk them right on top of our signals. Oh dear.
  2. The mixer has high order output products – at multiples of the LO (32, 64, 96 ….. kHz) away from the input frequency. So any strong signal some distance away could potentially be mixed into our pass band. A strong BPF and resonant antennas might help. Yet to see if this is a real problem.

Next Steps

Anyway, onward and upwards. I’ll add some “pads” to A1 and A2, then assemble the RF head with a couple of antennas so I can mount the whole thing outdoors on a mast.

Mark has given me a small beacon transmitter that I will use for local testing, before trying it on a repeater. If I get repeatable repeater-bearings (lol) I will take the system to mountain overlooking the city and see if it blows up with strong signals. Gold star if I can pull bearings off the repeater input as that’s where our elusive mole lives.

Making my 32kHz Crystal Oscillator Actually Oscillate

For Project Whack a Mole I need a 32.768kHz crystal oscillator. I found this circuits on the Interwebs and gave it a try:

It wouldn’t go. I messed about changing component values for while, then decided to actually try to understand the circuit. Now for an oscillator to work, we need an amplifier with a gain of greater than 1, and a phase shift of 360 degrees to get positive feedback.

The circuit above is an amplifier, with the crystal network connected between the collector output and base input. We get half of the 360 degree phase shift by using a common emitter topology, which is an inverting amplifier. So the crystal network must provide the other 180 degrees. On a good day. If it’s working.

First problem – the transistor was saturated, with Vc stuck near 0V. For an oscillator to start noise gets amplified, filtered by the crystal, amplified again etc. I reasoned that if the amplifier wasn’t biased to be linear, the oscillations couldn’t build up. So I reduced the collector resistor to 6.8k, and changed the the base bias resistor to 1.8M to get the collector voltage into a linear region. So now we have Vc=3.2V with a 5V supply.

But it still wouldn’t go. On a whim I adjusted the supply voltage up and then down and found it would start with a supply voltage beneath 3V, but not any higher. Huh?

Much fiddling with pencil and paper followed. Time for a LT Spice simulation of the “AC model” of the circuit:

I’ve “opened the loop”, to model the collector driving the crystal network which then drives the base impedance. On the left is a voltage source and 6.8k resistor that represents the collector driving the 330k resistor and an equivalent model of the crystal.

The values Lm, Cm, Rm, are the “motional” parameters. They are what the mechanical properties of the crystal look like to this circuit. The values are amazing, unrealizable if you are used to regular electronic parts. I found Cm = 1fF (1E-15 Farads, or 0.001 pF) in a 32kHz crystal data sheet, then solved f=1/(2*pi*sqrt(LC)) for Lm to get the remarkable value of 24,000 Henrys. Wow.

Phase Shift

With Vcc=5V, we have Vc=3.2V, so a collector current Ic = (5-3.2)/6800 = 0.265mA. I’m using a small signal transistor model, with the emitter resistance re=26/Ic = 26/0.265 = 100 ohms. The effective impedance looking into the base rb=beta*re = 100*100 = 10k ohms (2N3904’s have a minimum beta of 100).

OK, so here is the phase response near 32kHz:

Well it looks about right, a phase shift of 170 degrees, which is close to the target of 180 degrees.

Now, can we explain why the oscillator starts with a reduced supply voltage? Well, reducing Vcc would reduce Ic and hence increase rb, the base impedance the crystal network is driving. So lets double rb to 20k and see what happens to the phase:

It gets closer to 180 degrees! Wow, that means it is more likely to oscillate. Just like the actual circuit.

So – can I induce it to oscillate on a 5V supply? Setting rb back to 10k, I messed about with C1 and C2. Increasing them to 82pF moved the phase shift to just on 180 degrees. I soldered 82pF capacitors into the circuit and it started on a 5V rail. Yayyyyy. Go Spice simulations.

Loop Gain

But what about the loop gain? Well here is the magnitude plot near 32kHz:

The maximum gain is -22dB at series resonance, followed by a minimum gain at parallel resonance. We need a net gain around the loop of 1 or 0dB. So the gain of the amplifier must be at least +22dB to get a net gain of 0dB around the loop.

A net gain of 0dB is enough to sustain oscillation, but to get it started we need a gain of greater than 0dB to amplify internal noise up to the point where we have a useful output voltage. This paper suggests a gain margin of 5 or 14dB.

The gain of a common emitter amplifier is Rc/re = 20*log10(6800/100) = 36dB, which is just the 14dB gain margin we need. At the reduced supply voltage lets say Ic is halved, so re doubles. This would reduce the loop gain to 30dB. However rb=beta*re would also double to 20k. Spice tells me the maximum gain of the crystal network is now -16dB, as rb=20k loads the circuit less. So once again we have our 14dB gain margin, which predicts the oscillator will start – which is what happens in the real hardware.

Increasing C1 and C2 to 82pF produced a crystal network gain of -24dB. With a 5V supply the amplifier gain is 36dB so we have a little less margin (12db) than we would like, but still close enough and well above 0dB. It takes about 10 seconds for the oscillations on the collector to hit the supply rails.

Start Up Time

I did some reading on this. At start up, we can model the oscillator as as a noise source being band pass filtered by the crystal, then amplified. This is then fed back to the input of the circuit and the cycles repeats, the “band pass noise” getting larger every time.

It’s humbling to think that our magically stable, low phase noise crystal oscillators are really just band pass noise that has been amplified. An oscillator is a narrow band noise source.

Every resistor generates thermal noise. The biggest resistor I can see is the 330k in series with the input. A useful rule of thumb is every 50 ohm generates 1nVrms of noise per 1 Hz of bandwidth at room temperature. So that’s our initial noise source. It’s value probably affects start up time.

OK, so what is the bandwidth (BW) of the crystal “band pass filter”. Well for a resonant circuit Q = f/BW = Xl/R. With a little manipulation and plugging the crystal motional parameters I get BW = Rm/(2*pi*Lm) = 0.225 Hz. That’s pretty narrow, which is what we would expect from a crystal I guess.

The bandwidth of a filter affects it’s delay. It takes some time for the band pass noise energy to pass through the crystal, get amplified, then be fed back once again for another lap. That sounds like exponential growth to me. We can describe the delay in terms of the filter time constant, Tau. Given the bandwidth BW we can find Tau = 1/(2*pi*BW) = 0.707 seconds. I suspect Tau would be affected by the filter shape factor so it’s an approximation for the crystal BPF. But engineers like approximations, as long as the rockets don’t blow up and bridges don’t fall down.

So we start with noise from (mainly) the 330k resistor in a 0.225Hz bandwidth. If 50 ohms gives us 1nV in 1Hz bandwidth, then 330k gives us an initial input voltage V1 = (330E3/50)*0.225*1E-9 = 1.48uVrms. Lets say the final voltage is V2 = 1Vrms (2.8Vpp) before the amplifier starts to clip and it settles down to a steady state output voltage.

The voltage grows exponentially from the initial resistor noise V1 to the final voltage V2. Plugging this into a formula for exponential growth we have V2 = V1*g*exp(t/Tau), where g is the voltage gain of 5 (14dB), and t is the start up time. Messing with logs I get t = (ln(V2) – ln(V1) – ln(g))*Tau = 8.3s

Whooo! Which is about the start up time of the real circuit.

Before I couldn’t even speel Ingineer. Now I are one.

Crystal Power

Matt, VK5ZM, suggested the function of the 330k resistor is to limit the power through the crystal. These tiny crystals are rated at just 1uW maximum power. With 1Vrms AC drive, Spice measured a current of 7.2uA through the crystal series resistance Rm=35k at the resonant frequency, which is a power of 35E3*(7.2E-6)^2 = 1.8uW. Oops, a bit much. However I think increasing the 330k resistor might reduce the loop gain. And I have a big bag of spare crystals.

Matt, and Erich, VK5HSE also pointed out there are some parasitic capacitors from the transistor that should be included in the model. The values for these capacitors is difficult to determine. My best guess from the 2N3904 data sheet and reading about transistors is Ccb=4pF (between collector and base), and Cbe=15pF (between base and emitter). Cbe could be absorbed into C1 which will add a little more phase shift, perhaps explaining why my phase plots above are just shy of 180 degrees. Ccb would be across the entire crystal network. It’s impedance at 32kHz is Xc=1/(2*pi*32E3*4E-12)=1.2M so it probably doesn’t have much effect.

Here is the final circuit that works on 5V:

John’s Solution

John has suggested the original circuit may have a wiring error. He used the circuit at the top of this post (R1=3M3, R2=68k), but connecting R1 between the base and collector, rather than base and Vcc. See Johns comments below.

Links

Open Loop LT Spice simulation of the crystal oscillator network.

FreeDV 2400A

Brady O’Brien, KC9TPA, has been working hard on two new FreeDV modes for VHF/UHF radio. To the existing Codec 2 1300 bit/s mode, he has added framing/sync logic and our high performance 4FSK modem. This mode is designed to be “readability 5” at -132dBm, which is 10dB beyond the point where analog FM and 1st generation DV systems stop working.

Brady tested the system by setting up a low power transmitter using a HackRF connected directly to an antenna (tx power about 20mW). A GNU Radio system was used to play FreeDV 2400A and analog FM signals at the same transmit power:

He then went for a drive and found a spot 2.5km away where the signal was weak, but still decodable.

Here is a FM sample and DV sample for comparison. At the same power even SSB would be a scratchy 6dB SNR copy (noise measured in a 3000Hz bandwidth).

Here is a spectogram of the two signals, FM/2400A/FM/2400A.

SDR radios are required to reach the performance goals for this mode. FreeDV 2400A is not designed to be run on legacy FM radios, even those with data ports. The RF bandwidth is 5kHz, too wide for SSB radios. This represents a complete departure from “FM” friendly VHF DV modes – DStar/C4FM/DMR which pass through an analog FM modem, and suffer performance degradation because of it. The mode has been designed without compromise in the modem and to explore new ground. It is also completely open source – especially the codec.

However we are also developing FreeDV 2400B – which is designed to run though any FM radio, even a $40 HT. Some test results on that soon.

FreeDV 2400A is available now in the FreeDV API and can be tested using the FreeDV command line utilities, for example:

./freedv_tx 2400A ../../raw/ve9qrp_10s.raw - | ./freedv_rx 2400A - - | play -t raw -r 8000 -s -2 -

It requires a 48kHz interface to the SDR.

Some information on the FreeDV 2400A mode:

Bit Rate 2400 bit/s
RF Bandwidth 5 kHz
Suggested Channel Spacing 6.25 kHz
Modulation 4FSK with non coherent demodulation
Symbol Rate 1200 symbols/s
Tone Spacing 1200 Hz
Frame Period 40ms
Bits/Frame 96
Unique Word 16 bits/frame
Codec 2 1300 52 bits/frame
Spare Bits 28 bits/frame

The spare bits are currently undefined but could be used for data, routing information, or FEC. It’s early days but this is an important first step – well done Brady!

SM2000 Part 6 – PCB Layout

Since the last post in this series Rick, KA8BMA, has been working steadily on the CAD work for the SM2000 VHF Radio. We now have the SM2000 schematic and 80% of the PCB layout is complete. Rick has taken a modular approach, laying out each building block that I prototyped last year.

Here is the current state of the PCB layout, which is 160mm x 160mm

On the waveform side, Brady, KC9TPA, has done a fine job porting a 4FSK modem to C and developing two new VHF FreeDV modes. ModeA is an “optimal” 4FSK mode that runs at 2400 bit/s, has a 5kHz RF bandwidth and a MDS of -132dBm. ModeB use Manchester-encoded 2FSK at 2400 bit/s and will run over any FM radio, even $40 HTs.

Brady’s modem is also being used for our high speed balloon telemetry work.

There is plenty of software work (e.g. STM32F4 micro-controller code) to be done for the SM2000. Help wanted!

Links

SM2000 Part 1 – Introducing the project

SM2000 SVN – CAD Files for the project

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?

Testing

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' ' '

Links

Measuring SDR Noise Figure

Horus 14 – Tux in (near) Space

Measuring SDR Noise Figure

Last night Mark and I were working on a 115 kbit/s FSK modem link for balloons that uses SDR receivers and FSK modem software.

We connected the transmitter to the SDR rx via a switched attenuator, calibrated with the spec-an, and measured a Minimum Detectable Signal (MDS) of about -75dBm. Based on an Eb/No of 15dB for 2FSK (to get a BER of 1E-5) I was expecting:

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

So we are way off expected performance at the moment, and are testing the various components one by one.

One number I wanted to know was the Noise Figure (NF) of the SDR. Mark has a bunch of SDRs so we got on a roll and checked out the NF on all of them.

Now there are a lot of people playing with SDRs, but very few tutorials on HowTo engineer radio systems. For example, how to answer questions like “can I send this many bit/s over X km with SDR hardware Y?” So I thought it might be useful to explain how we measured Noise Figure (NF) and present the results for a bunch of SDRs.

From the Wikipedia article on Noise Figure:

The Noise Figure is the difference in decibels (dB) between the noise output of the actual receiver to the noise output of an “ideal” receiver.

An ideal receiver has an output noise power of:

 
Nout_dB = 10log10(B) - 174 + G_dB

The -174 dBm/Hz figure is the thermal noise density at 25C. For every 1Hz of bandwidth you will get -174dBm of noise power. It’s the lower limit set by the laws of physics. G_dB is the Rx gain. The 10log10(B) term takes into account the bandwidth of the Rx. A wider bandwidth means more total noise power.

So if you have a 1Hz bandwidth, and a gain of 100dB, you would expect Nout_NdB = 0 – 174 + 100 = -74dBm at the Rx output with no signal. If you have a 1000Hz bandwidth receiver you would have NdB_out = 10*log10(1000) – 174 + 100 = 30 – 174 + 100 = -44dBm of noise power at the output.

That’s for an ideal receiver. A real receiver has an output noise power of:

 
Nout_dB = 10log10(B) - 174 + G_dB + NF_dB

It’s NF_dB worse than an ideal receiver.

To determine Noise Figure we compare the output noise for our receiver (Rx) to an ideal receiver using these steps:

  1. Sample the Rx output first with an input test signal of known power and then with noise only.
  2. Find the Rx gain by comparing the Rx output power to the test signal input power.
  3. Find the noise output power, then using the gain we can find the noise input power.
  4. Normalise the noise input power to 1Hz noise bandwidth (so it’s units are also dBm/Hz) and compare to the thermal noise floor.

Here is the GNU Octave script nf_from_gr.m we used, and here are the results we obtained:

octave:17> nf_from_gr
    HackRF: Pin: -100.0  Pout: 38.1  G: 138.1  NF: 8.9 dB
   RTL-SDR: Pin: -100.0  Pout: 45.8  G: 145.8  NF: 6.7 dB
    AirSpy: Pin: -100.0  Pout: 42.0  G: 142.0  NF: 7.3 dB
FunCube PP: Pin: -100.0  Pout: 31.0  G: 131.0  NF: 3.9 dB

GNU Radio was used to collect a few seconds of samples and save them to a file for processing by Octave. For the test signal I used a calibrated signal generator set to -100dBm. All tests were performed on a chunk of spectrum around 440MHz.

These results are not definitive – there are so many “knobs and sliders” on the SDRs it’s hard to say if we had them adjusted right. More gain in front of the ADC tends to reduce NF. The results seem reasonable though, no huge or negative NFs.

A good way to check our script would be to use a pre-amp with a known NF in front of the SDR, but we haven’t tried that yet.

It’s important to sample a chunk of noise without too many birdies (and SDRs seem full of them!). So the script asks you for a start “st” and end “en” range of frequencies. Here is a sample spectrum of the SDR output with the test signal (top) and just noise (bottom):

Links

At the end of SM2000 Part 1 there is a section on measuring Noise Figure using a spectrum analyser.

SNR and Eb/No Worked Example explains how I work between SNR and Eb/No.

Project Whack a Mole Part 1

As a side project I’ve been working on a Direction Finding (DF) system. Although it relies on phase it’s very different to Doppler. It uses a mixer to frequency multiplex signals from two antennas into a SDR. Some maths works out the phase difference between the antennas, which can be used to compute a bearing.

The use case is tracking down a troll who is annoying us on our local repeater. He pops up for a few seconds at a time, like the game of Whack a Mole. It’s also fun to work on a new(ish) type of DF system, and play with RF.

I’ve got the system measuring phase angles between two antennas on the bench, so thought I better come up for air and blog on my progress so far.

Hardware

Here is a block diagram of the hardware:

The trick is to get signals from two antennas into the SDR, in such a way that the phase difference can be measured. One approach is to phase lock two or more SDRs. My approach is to frequency shift the a2 signal, which is then summed with a1 and sent to the SDR. I used a Minicircuits ADE-1 mixer (left) and home made hybrid combiner (centre):

For testing on the bench I use a sig-gen and a splitter (right) to generate the a1 and a2 signals. I can vary the phase by varying the cable lengths.

Here is a spec-an plot showing a1 in the centre and the a2 “sidebands”, at +/- 32kHz:

The LO frequency of 32kHz was chosen as it (i) greater than the 16kHz bandwidth of FM signals and (ii) means we can use a modest sampling rate of 192kHz to capture the 3 signals, (iii) we can use a common “watch” crystal to generate it. The LO input on the mixer is rated down to 500kHz but works OK with a conversion loss of 9dB.

Signal Processing Design

OK so we have the two signals a1 and a2 present at each antenna. Theta is an arbitrary phase offset that both signals experience due to propagation time from the transmitter, and other phase shifts common to both signals, like the SDRs signal processing. Phi is the phase difference between a1 and a2, this is what we want to compute. Alpha is the phase offset of the local oscillator. Only a2 experiences this phase shift as it passes through the mixer. Omega-l is the local oscillator frequency, and omega is the carrier frequency. The summed signal presented to the SDR input is called r, which we can derive:

Note we assume the two signals a1 and a2 are complex, but the mixer is real (double sided). So there are a total of three signals at the SDR input. Now lets mess about with the phase terms of the three signals that make up r:

So the output is 2 times phi, the phase difference between the two antennas. Yayyyyyy. The 2phi output also implies an ambiguity of 180 degrees, which is what we would expect with just 2 antennas. I’ll worry about that later, e.g. with a third channel or mounting the hardware on the edge of our city such that bearings are only expected from one hemisphere.

There are several ways to implement the signal processing. I like the sample by sample approach:

It’s all implemented in df_mixer.m. This can run with a simulated signal or input from a HackRF SDR.

Walk Through and Results

Lets look at the algorithm in action with a1 and a2 generated on the bench using a splitter and two lengths of coax to set the phase difference. The signal generator was set to 439.048MHz and -30dBm. We sample about 1 second using the HackRF SDR, the run the Octave script:
$ hackrf_transfer -r df1.iq -f 439000000 -n 10000000 -l 20 -g 40
% octave:25> df_mixer.m

Here is the input signal, the wanted signals are at 48kHz (a1), 16kHz and 80kHz (a2).

We pass that through these Band Pass Filters (BPFs):

To get the three signals:

After the signal processing magic we can plot the output for each sample on the complex plane. Its like a scatter plot, and gives us a feel for how reliable the phase estimates are:

We can also find the angle for each sample and plot a histogram. The tighter this histogram is the more confidence we have:

Testing with Cables

So how to test? I ended up inserting short lengths of transmission line, using adapters and attenuators. I guessed the velocity as 2/3 the speed of light. This spreadsheet summarises the results:

When I insert adapters in the opposite antenna line the phase angle reduces. I inserted a 10dB attenuator and the phase angle changed roughly in proportion to the attenuator length. It worked just fine despite the amplitude difference. So it’s doing something sensible. Wow!

Discussion

The central carrier and two “sidebands” looks a lot like an AM signal. I initially thought I could demodulate it using envelope detection. However that was a flop, so I got the paper and pencil out and worked out the math. This was challenging but I do enjoy a good engineering puzzle. After a few goes over several days I came up with the math above, and tested it using a simulation.

Note we don’t really care what sort of modulation the signal has. It could be a carrier, FM, or SSB. We just look at the phase so it’s insensitive to amplitude differences in the two signals. Any frequency and phase modulation is present on both a1 and a2 and is removed by the signal processing, leaving just the phase difference term. So the algorithm essentially strips modulation.

This means “processing gain” is possible. We can make phase estimates on every sample over say 1 second. We can then average the phase estimates. This may lead to a good phase estimate at SNRs lower than we can demodulate the signal. Plucking DF bearings out of the noise. Just like the FFT of a weak sine wave in noise creates a nice sharp line if you sample the signal long enough.

This system is phase based so will be affected by multipath signals. Mounting the system with a direct line of site to the transmitter is a good idea. The histogram gives us a confidence measure, and may be useful in detecting multipath or multiple bearings. Presenting this histogram information visually on a 3D or intensity map would be a useful area to explore.

The absolute phase estimates are sensitive to frequency offset, for reasons I haven’t worked out yet. The HackRF is about 4kHz off my sig-gen at 439MHz, which shifts the phase estimates. So it might need tuning or re-calibration to a known bearing.

I haven’t worked out where the “noise” in the scatter diagram comes from. The phase is the product of several non-linearities so we expect it to jump around a bit. Given we are just interested in phase, perhaps a limiter or three could be included at some point in the processing.

Off Line Direction Finding

One neat possibility with this approach is off line DF. Imagine every time the squelch opens, we log the SDR baseband Fs=192kHz signal onto a hard disk. A 1 Tbyte disk would store 720 hours at Fs=192kHz (2 byte IQ samples). We can then then use a sound editor to jump to the position where our Mole appears for a few seconds, and run the DF signal processing on that segment. We can tweak parameters, even run it a few times, to improve the bearing. We can compare this to the same signal received at different sites across town, to get a cross bearing.

We can do this off line DF-ing days later, or download the samples and process at a location remote to the DF site. It also provides a documented record for ACMA, should evidence be required for prosecution.

Further Work

My next step is to configure the HackRF for high gain so I can try some off-air signals. The repeater output is about -70dBm inside my home office so that will do for a start. If that works I will try DF-ing repeater input signals, perhaps with the hardware mounted on a mast outside. I have a UHF BPF I will insert to prevent overload from out of band signals.

I’m hoping it will be as accurate as Doppler systems, e.g. capable of resolving say 16 different bearings on a “ring of LEDs” or similar virtual display. I bet there are many issues I need to sort out and perhaps a show stopper lurking somewhere. We shall see! It’s good to experiment. Failure is an option.

We could simplify the hardware significantly. Other mixers could be tried. The circuit is insensitive to levels so the combining could be very simple, we don’t need a hybrid. Just connect the two signals to the same node. If the mixer has poor RF-IF isolation (carrier feed-through) there could be a problem. This could be alleviated by ensuring a1 is > 10dB above the a2 carrier feed-through. A very simple approach would be using a UHF transistor for the 32kHz clock oscillator, and injecting a2 into the emitter or base.

The 32kHz transistor clock oscillator I built was hard to start. Here is the saga of getting the 32kHz oscillator to run.

More

Project Whack a Mole Part 2

Latex Source

Have to put this somewhere in case I need it again. I used HostMath to build up the equations and Rogers Online Equations to render it to a PNG.

\begin{array}{lcl}
a_{1} & = & e^{j(\omega t+\phi +\theta)} \\
a_{2} & = & e^{j(\omega t+\theta)} \\
r & = & a_{1}+a_{2}cos(w_{l}t+\alpha ) \\
& = & e^{j(\omega t+\phi +\theta)})+\frac{1}{2}e^{j((\omega+\omega_{l}) t+\alpha +\theta)}+\frac{1}{2}e^{j((\omega-\omega_{l}) t-\alpha +\theta}
\end{array}

\begin{array}{lcl}

phase_{1} & = & \omega t + \phi +\theta \\
phase_{2} & = & (\omega+\omega_{l})t+\alpha +\theta \\
phase_{3} & = & (\omega-\omega_{l})t-\alpha +\theta \\
phase_{2}+phase_{3} & = & \omega t + \omega_{l}t+\alpha +\theta + \omega t - \omega_{l}t -\alpha + \theta \\
& = & 2\omega t + 2\theta \\
2phase_{1} - (phase_{2}+phase_{3}) & = & 2\omega t + 2\phi + 2\theta -2\omega t - 2\theta \\
& = & 2\phi
\end{array}