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.


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.

Organic Potato Chips Scam

I don’t keep much junk food in my pantry, as I don’t like my kids eating too much high calorie food. Also if I know it’s there I will invariably eat it and get fat. Fortunately, I’m generally too lazy to go shopping when an urge to eat junk food hits. So if it’s not here at home I won’t do anything about it.

Instead, every Tuesday at my house is “Junk Food Night”. My kids get to have anything they want, and I will go out and buy it. My 17 year old will choose something like a family size meat-lovers pizza with BBQ sauce. My 10 year old usually wants a “slushie”, frozen coke sugar laden thing, so last Tuesday off we went to the local all-night petrol (gas) station.

It was there I spied some “Organic” potato chips. My skeptical “spidey senses” started to tingle…….

Lets break it down from the information on the pack:

OK so they are made from organic grains. This means they are chemically and nutritionally equivalent to scientifically farmed grains but we need to cut down twice as much rain forest to grow them and they cost more. There is no scientifically proven health advantage to organic food. Just a profit advantage if you happen to sell it.

There is nothing wrong with Gluten. Nothing at all. It makes our bread have a nice texture. Humans have been consuming it from the dawn of agriculture. Like most marketing, the Gluten fad is just a way to make us feel bad and choose more expensive options.

And soy is suddenly evil? Please. Likewise dairy is a choice, not a question of nutrition. I’ve never met a cow I didn’t like. Especially served medium rare.

Whole grain is good, if the micro-nutrients survive deep frying in boiling oil.

There is nothing wrong with GMO. Another scam where scientifically proven benefits are being held back by fear, uncertainty, and doubt. We have been modifying the genetic material in everything we eat for centuries through selection.

Kosher is a religious choice and has nothing to do with nutrition.

Speaking of nutrition, lets compare the nutritional content per 100g to a Big Mac:

Item Big Mac Organic Chips
Energy 1030 kJ 1996 kJ
Protein 12.5 g 12.5 g
Carbohydrates 17.6 g 66 g
Fat 13.5 g 22.4 g
Sodium 427 mg 343 mg

This is very high energy food. It is exactly this sort of food that is responsible for first world health problems like cardio-vascular disease and diabetes. The link between high calorie snack food and harm is proven – unlike the perceived benefits of organic food. The organic label on these chips is dangerous, irresponsible marketing hype to make us pay more and encourage consumption of food that will hurt us.


Give Us Our Daily Bread – A visit to a modern wheat farm.

Energy Equivalents of a Krispy Kreme Factory – How many homes can you run on a donut?

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.


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!


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?


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

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):


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.

Codec 2 Masking Model Part 4

This post describes how the masking model frequency/amplitude pairs are quantised.

This work is very new. There are so many different areas to pursue. However I decided “release early and often” – push a first pass right through the quantisation process. That way I can write about it, publish the results, and get some feedback. This post presents a first pass including samples at 700 and 1000 bit/s.


Quantisation takes a floating point value (a real number) and represents it with a small number of bits. In this case we have 4 frequencies, and 4 amplitudes. Eight numbers in total that we must send over the channel. If we sent the floating point values that would be 8×32 = 256 bits/frame. With a 40ms frame update rate that is 256/0.04 = 6400 bit/s. Too high. So we need to come up with efficient quantisers to minimise the number of bits flowing over the channel, while keeping a reasonable speech quality. Speech coding is the art of what can I throw away?

There are a few tricks we can use. The dynamic range (maximum and minimum) values tend to be limited. A good way to look at the range is using a histogram of each value. I ran samples of 10 speakers through the simulations and logged the frequency and amplitudes to generate some histograms.

Here are the frequencies and differences between each frequency. The frequencies were first sorted into ascending order.

Here are the amplitudes, with the mean (frame energy) removed:

Voiced speech tends to have a “low pass” spectral slope – more energy at low frequencies than high frequencies. Unvoiced speech tends to be “high pass”. As discussed in the first post the ear is not very sensitive to fixed “filtering” of speech, ie the absolute value of the formant amplitudes. You can have a gentle band pass filter, some high pass or low pass filtering, and it all sounds fine.

So I reasoned I could fit a straight line the amplitudes, like this:

The first plot is the time domain speech, it’s a frame of Mark saying “five”. The second plot shows the spectral amplitudes Am (red) and the mask (purple) we have fit to them. The mask is described by just four frequencies/amplitude points. The frequencies are labelled by the black crosses.

The last plot shows the four frequency/amplitude points (red), and a straight line fit to them (blue line). The error in the straight line fit to each red point is also shown.

So keeping this straight line fit in mind, lets get back to the histograms. Here are the histograms of the amplitudes, followed by the histograms of the amplitude errors after the straight line fit:

Note how narrow the 2nd plot’s histograms are compared to the first? This makes the values “easier” to represent with a small number of bits. In statistics, we would say the variance of these variables is smaller.

OK, but now we need to send the parameters that describe the straight line. That would be the gradient and y-intercept, here are the histograms:

Notice the mean of the gradient is skewed to negative values? Speech contains more voiced (vowels) than unvoiced speech (constants), and voiced speech is “low pass” (a negative gradient).

The y-intercept is a fancy way of saying the “frame energy”. It goes up and down with the level of the speech.

Quantisation of Frequencies

The frequencies are found in random order by the AbyS algorithm. We can also transmit them in any order, and reconstruct the same spectral envelope at the decoder. For convenience we sort them into ascending order. This reduces the distance between each frequency sample, and lets us delta code the frequencies. You can see above that the histograms of the last 3 delta frequencies cover about the same range.

I used 3 bits for each frequency, giving a total of 12 bit/s frame.

Quantisation of Amplitudes

I used the straight line fit method for the amplitudes. I used 3 bits for the gradient, and 3 bits for the errors in 5dB steps over the range of -15 to 15 dB. I assumed the y intercept would require as many bits as the frame energy (5 bits/frame) that is used for the existing Codec 2 modes.

Bit Allocation

The quantisation work leads us to a simulation of quantised 1000 and 700 bit/s codecs with the following bit allocations. In the 700 bit/s mode, we don’t transmit the straight line fit errors.

Parameter Bits/frame (High Rate) Bits/frame (Low Rate)
Pitch (Wo) 7 7
Voicing 1 1
Energy 5 5
Mask freqs 12 12
Mask amp gradient 3 3
Mask amp errors 12 0
Bits/frame 40 28
Frame period (s) 0.04 0.04
Bits/s 1000 700


Here are some samples of the first pass 700 and 1000 bit/s codecs. Also provided are the samples from Part 3, the (unquantised AbyS, and Codec 2 700B and 1300). The synthetic phase spectra is derived from the decoded amplitude spectrum. “newamp” is the name for the simulations using the masking model.

Sample 700B 1300 newamp AbyS newamp AbyS 700 newamp AbyS 1000
ve9qrp_10s Listen Listen Listen Listen Listen
mmt1 Listen Listen Listen Listen Listen
vkqi Listen Listen Listen Listen Listen

I can notice some “tinkles”, “running water” types sounds on the quantised newamp samples. This could be chunks of spectrum coming and going quickly. Also some roughness on long vowels, like “five” in the vk5qi samples.

I feel the newamp 700 samples are better than 700B, which is the direction I want to be heading. Please tell me what you think.

Command Lines
codec2-dev SVN revision 2716
octave:49> newamp_batch("../build_linux/src/vk5qi","../build_linux/src/vk5qi_am.out", "../build_linux/src/vk5qi_aw.out")
~/codec2-dev/build_linux/src$ ./c2sim ../../wav/vk5qi.wav --amread vk5qi_am.out --awread vk5qi_aw.out --phase0 --postfilter -o - | play -t raw -r 8000 -s -2 -

Further Work

A bunch of ideas that come to mind:

  • The roughness in long vowels could be frame to frame amplitude variations. It would be interesting to explore these errors, for example plotting them.
  • Try delta-time approach. This might help with gentle evolution of the parameters and frame-frame noise. A gentle evolution of the slope of the straight line might sound better than the current scheme – as there will be less frame to frame noise.
  • Plotting trajectories of the parameters over time would give us some more insight into quantisation, and help us determine if we can use Trellis Decoding for additional robustness.
  • It may be possible to weight certain errors on the AbyS loop, for example steer it away from outlier amplitude points that have a poor straight line fit.
  • Can we choose a set of amplitudes that fit exactly to a straight line but still sound OK? Can we modify the model in a way that doesn’t affect the speech quality but helps us quantisate to a compact set of bits?
  • Look for quantiser overload – values outside of the quantiser range.
  • Take another look at what the AbyS loop is doing, track down some problem frames.
  • Try a higher and lower (e.g. 3) number of frequency/amplitude points.
  • Frequencies don’t have to be on the harmonic amplitude mWo grid.
  • Experiment with the shape of the masking functions.
  • Try Vector Quantisation.
  • The parameters are all quite orthogonal, which lets us modify them independently. For example we could move the amplitudes a little to aid quantisation, but keep the frequencies the same. Compressing the frame energy will leave intelligibility unchanged.
  • Get something a little better than what we have here and put it on the air and get some real tests over real conversations.
  • Samples like vk5qi have a lot of low pass energy. We might be wasting bits coding that. The 4th freq frequency histogram has a mean of 3.2kHz. This is very high and it could be argued we don’t need this sample, or it could be coded with low resolution.


Codec 2 Masking Model Part 1
Codec 2 Masking Model Part 2
Codec 2 Masking Model Part 3

Torturing the Clutch in my EV

My 17 year old son recently been given a drivers license, and has, like his sister before him, taken over my EV. Free driving (Dad pays the electricity bills) is kind of irresistible. And also like his sister before him – I was full of fear and angst. You see my EV is something of a prototype, and likes to be babied by it’s Creator. Lots of traps for the unwary. If you want an EV fit for general consumption talk to Tesla.

Sure enough, just 4 weeks later, I get “the phone call” from my son. The EV has died. Motor running but making nasty sounds and won’t move. Fortunately, it stopped a few blocks from home. I attended the scene, and all I could hear was a grating sound from the front. We pushed it home and I consulted my motor vehicle brains trusts (friends Kyle and Scott) who pronounced a likely transmission failure.

I prepared to drop the motor and gearbox, something I haven’t done since I blew up the armature 6 years ago. Looking forward to the project, as doing something mechanical is a welcome change in my lifestyle. Feeling determined as well, my EV must be kept running!

I was talking about the problem on the local repeater when Gary, VK5FGRY popped up and said he might be able to help. Gary has a fully equipped workshop and years of experience with car repairs. He also has the most important resource of all – time. Gary came around this morning at 9:30am to assess the situation. He suggested we make a start, so we could at least work out what the problem was.

Within a few hours the gearbox was on the ground and the problem found – a stripped spline in the hub of the clutch plate. The noise I could hear was the stripped spline being filed away by the (somewhat harder) gearbox input shaft. Gary also discovered a few minor issues with stripped or missing gearbox mounting bolts. Note the filings on the inside of the hub, and splines mostly gone:

This was a lucky escape – I thought I was up for a new gearbox ($500 second hand). We guessed the torque of the electric motor (200Nm, about twice that of the original infernal combustion engine) had caused the fault. Well it’s been Electric for 8 years and 50,000km, so I guess I can’t complain.

We headed out and bought a new clutch plate ($100), some bolts, and transmission oil. After a nice lunch of home made bread and condiments, we picked up the tools again and by 6pm my little EV was on the road! Yayyyyyyy. Thank you so much Gary!

Here is the clutch (purple) re-assembled and attached to the electric motor, just before the gearbox was re-installed. Silver metal is the adapter plate. Lots of cables all over the place:

It was a great day. Nice change from my usual keyboard and laptop filled life. Lovely summer day, working outside with the tools, getting a bit dirty (but not oily – this is an electric car so no grease under my bonnet). So much nicer to do it with good company – especially someone as experienced as Gary.

I do live an interesting life. What did you do today Dad? “I worked with a friend to fix a home brew Electric Car!”


My EV page

My EValbum page. Lots of pictures and technical stuff.

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.


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


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.


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.

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}


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