Minimalist VHF Software Defined Radio Part 1

I think the future of radio hardware is a piece of wire connected to a GPIO pin.

The rest of the radio will be “gcc compilable” free software running on commodity CPU horsepower. I spoke about this at length in my recent linux.conf.au 2015 talk.

For the last two weeks I’ve been developing a simple radio architecture that is moving in that direction. The motivation is hardware to test our VHF FreeDV ideas. I’ve got to the point where I can tune 146 MHz VHF radio signals. The performance largely meets my design specs. The radio consists of about 20 off the shelf parts and a STM32F4 Discovery board with a Bill of Materials (BOM) cost of a few $. With another design pass it will be capable of good RF performance and also run FreeDV (or the mode of your choice). Completely stand alone – no PC.

Boo Baseband IQ, Chip-sets and FPGAs

I’m not a fan of baseband IQ designs, due to issues with phase and amplitude balance, and carrier feed through. This means development time and engineering pain. IQ signals should live only in software. Nor am I a fan of semi-closed chip-sets, FPGAs, or fixed point. More pain, development time, inaccessible tools, complex hardware designs, multilayer PCBs (even for prototypes), vendor lock-in, non-portable and proprietary issues.

I’m using the STM32F4, NE602 mixer, and Si5351 LO as that’s what I had laying about. However I’m not hung up on any of them. Please free free to subsitute your favourites. What I do care about is radio architectures that minimise hardware and maximise free software.

No chip-sets or lock-in here. The hardware is very simple so major changes can be made in minutes, and prototyped by anyone who can hold a soldering iron next to a piece of blank PCB.

Design Walk Through

I prototyped the radio on a few square inches of blank PCB:

In the foreground is the Open Radio that I’m using for the Si5351 LO.

High Q filters and MacGyver Filter Tuning

It took me a few days to get a decent 10.5MHz Band Pass Filter (BPF) working. Learned all about loaded and unload Q of various inductors, filters, and rigged up a way to sweep filters using some Si5351 code:

  float f;
  unsigned long long f_ull;
  
  si5351.init(SI5351_CRYSTAL_LOAD_8PF,25000000);
 
  while(1) {
    for (f=8.0; f<12; f += 0.1) {
      f_ull = f*100000000ULL;
      si5351.set_freq(f_ull, 0, SI5351_CLK0);
      delay(1000);
    }
  }

Using my oscilloscope’s FFT function with infinite persistence selected on the display I can get a good feel for the filter performance:

I needed a pretty high Q for the BPF so I tested several inductors in a parallel 10MHz LC tuned circuit. I swept the circuit with the Si5351 and measured the insertion loss at resonance. At resonance the only impedance is the effective resistance of the inductor Rl. This forms a voltage divider with the source impedance (1500 ohms in my case).

Inductor Insertion Loss (dB) Rl Xl Qu
6T 6mm air core 200nH 16 281 12.5 22.5
FT37-61 3T 1uH 4 2565 60 43
Jaycar moulded inductor 1uH 3 1500 60 85

I eventually settled on a T50-2 toroid, which could achieve an unloaded Q of over 100 at 10MHz. A two stage coupled resonator BPF gets 40dB attenuation at 10.5 +/- 1MHz. I’m still climbing the RF learning curve but this testing was fun and useful for me. A crystal filter designed for FM radios (16 kHz bandwidth) would also do the job.

Band pass Sampling

We are using the neat trick of band pass sampling. This is a bit confusing – how do we sample a 10.5MHz signal with a sample rate of 2MHz?

OK, say you want to sample a signal at frequency f with an ADC having a sample rate Fs. Turns out the ADC can’t tell the difference between between f, Fs+f, 2Fs+f etc.

Here’s an example of a f1 = 5 Hz and f2 = 105 Hz signal sampled at Fs = 100 Hz. Note how the sampled signal is exactly the same!

That’s why we usually put a low pass filter in front of the ADC, to limit the “images” that the ADC would otherwise sample. By using a band pass filter, we can intentionally select one of the images.

So the sample and hold of the ADC can also perform a frequency translation step, saving us the need for a mixer and second local oscillator. In practice, the ADC tends to be less sensitive when sampling higher frequencies. In the case of the STM32F4 the sample and hold is a RC circuit with a -3dB point of 7MHz. As a simple RC filter rolls off slowly it still has plenty of gain at 10.5MHz.

Software IIR Tuner

The big challenge with this architecture is how to handle 2 MS/s from the ADC on a uC that is only clocked at 168 MHz. That’s only 84 instructions per sample at 100% CPU load. In this small budget we need to “tune” the 500 kHz signal so that other adjacent signals are filtered out. Then re-sample down to 44 or even 8 kHz, hopefully with enough MIPs left over to run the FreeDV stack (a GMSK modem and Codec 2).

Here is the block diagram of the tuner, the C source code is in iir_tuner.c

The ADC sees our 10.5 MHz signal as a 500 kHz signal. We use an Infinite Impulse response (IIR) bandpass filter to stomp on everything else except the signal centred on 500 kHz. IIR just means it’s recursive (uses previous outputs). This filter is the exact DSP equivalent of a LC tuned circuit, as used in the analog BPF. Once filtered, we can then safely decimate the signal (reduce the sample rate) by a factor of 45 so our poor little uC can start breathing again. Much easier to process the signal at a sampling rate of 44.4 kHz (ish) than 2 MHz.

The IIR filter is implemented in C like this:

  y[n] = x[n] - 2*sqrt(beta1)*cos(w)*y[n-1] - beta1*y[n-2]

y[n] is the latest output, x[n] the input. The w is the centre frequency of the filter in radians (w = 2*pi*f/Fs) and beta1 is the “Q” of the filter, i.e. sets how sharp it is. If you set beta1 = 0.999 you get the filter we are using. Make beta1 = 1 you get an oscillator. If you make beta1 > 1 you get overflow errors.

As we are MIPs-shy we set w=pi/2, which is one quarter of the sampling frequency of 2 MHz, or 500 kHz. This makes cos(w) = 0 and the the whole filter reduces to:

   y[n] = x[n] - beta1*y[n-2]

This executes in about 12% of the STM32F4 without any particular effort in optimisation. Good enough.

The IIR filter does make the spectrum of the signal a little spikey in the middle so we use an equaliser to flatten it out again. This is a simple Finite Impulse Response (FIR) filter that is the exact inverse of the IIR filter, but scaled for the lower sampling rate:

   y[n] = x[n] + beta2*x[n-2]

I started by simulating the tuner in Octave (adcres.m), which produced these fine plots:

I set a spec of 40dB rejection of adjacent signals, which is a function of the IIR tuner and the analog 10.5 MHz BPF.

In the plots above there are 4 signals. First the “wanted” signals at f+8 and f-7kHz (6dB down), at the edges of the desired bandwidth we need for nasty old legacy analog FM. Then I popped in an interferer f-207kHz away. If we don’t filter well enough the interferer will get aliased into the pass band. You can see that in the lower plot – the f-207kHz signal now appears about 30dB down in the pass band. Hopefully the analog BPF will push it down a bit more in practice.

The fourth signal is an impulse that effectively has energy at all frequencies, and neatly shows us the shape of the filters that implement the tuner. That’s the continuous line in each plot (0dB on top plot). I set the level of this broadband signal to 40dB less than the f+8kHz pass band signal.

Results

Here’s an example output for a 146.0025 MHz CW signal at -30dBm and -60dBm:

These are FFTs of 10 seconds of output samples. The x axis spans about 4 kHz, and the y axis is in dB, but not relative to any reference level. The central line is at about 2 kHz, so we have down converted by 146.005MHz from the input.

There is no gain apart from the mixer. Still, we can see at the -30dBm level we have about 60dB between the wanted signal and the highest spurious lines. At the -60dBm level the signal drops 30dB as expected.

Even at -30dBm the ADC is only being driven at about 10% of it’s maximum level, so we have another 20dB of headroom available there. Some gain would let us detect signals down to an appropriate MDS.

The spurious spurs appear to be 500Hz (ish) apart, which is the ADC interrupt service routine frequency. This is probably some power supply noise which we can clean up, as I did in the SM1000 development. The current prototype construction is pretty rough, so there are bound to be some issues in a VHF plus high speed digital system.

I wrote a FM demodulator in C and ran it on the STM32F4, sampling the results. Here is a strong local signal and here is a sample of Mark, VK5QI from a repeater.

The sample from the repeater is a scratchy. The periodic noise I think is at the rate buffers are transferred up to the Host PC I used for collecting samples. However please bear in mind this is not a finished radio, there is currently only about 10dB gain in total, and no input BPF! Off air reception at this early stage was just a long shot I thought I’d try for fun. Gain is cheap, we can add that in the next pass.

The real innovation here is the extreme simplicity of the hardware.

Being an on-chip ADC I’m not expecting sparkling performance. However it might be “good enough” – especially given it comes for free and the low SNR requirements (about 6dB) we need for GMSK. We shall see.

I measured the adjacent channel rejection as -30dB at 1 MHz and -40dB at a 25 kHz offset. The 25 kHz figure is exactly as designed (40dB). The 1MHz offset figure is 10dB worse than designed for. This could be due to the ADC input impedance loading the BPF and reducing the Q.

For a real radio these figures need to be much better, so another design pass is required. However I don’t think there is any risk here, just engineering effort. This first pass has shown that the architecture works.

Next Steps

  1. Replace the NE602 mixer with one that can deliver good strong signal performance.
  2. Have another design pass to meet a reasonable spec, like MDS of -120dBm for 1200 bit/s GMSK, adjacent channel rejection of -60dB, 100dB blocking of signals at +/- 1MHz. Rationalise the sampling rates (e.g. uC clock, ADC clock) so we get exactly Fs=48kHz at the output of the tuner.
  3. Put a proper 144-148MHz BPF on the input of the mixer.
  4. See if we can tune 70cm signals as well, e.g. with a harmonic of the LO. The mixer is good to 500 MHz.
  5. Determine if the Si5351 is OK in terms of phase noise, spurious lines. We could just about use a crystal oscillator, and tune chunks of the 2M band using banks of BPFs and IIR tuner software. The ADC sample clock might also be causing problems, e.g. spectral lines or phase noise. We can test that by measuring the implementation loss of the demodulator for a given receiver input C/No.
  6. Work out a clever way to transmit a 1W constant envelope signal at VHF. Perhaps a similar architecture operating in reverse, i.e. DAC running at 2MHz, tune to the 10.5 MHz image, up convert that to VHF. However as linearity is not required, the mixer could be a XOR logic gate.
  7. With a different BPF ahead of the ADC can we tune HF signals directly (i.e. delete the NE602)? What sort of performance will it have? Will the ADC dynamic range limit adjacent signal rejection?

Codec 2 and GMSK over VHF Radio Part 1

In the previous post comparing GMSK modem algorithms, I had some results suggesting we can build a Codec 2 VHF “mode” that outperforms legacy analog FM by 10dB (that’s a factor of 10 in power). It seemed to good too be true. So for the past few weeks I’ve been working with Daniel, VA7DRM, to . . . → Read More: Codec 2 and GMSK over VHF Radio Part 1

SM1000 Part 10 – First Over the Air Tests

Last night I visited Matt, VK5ZM, with a SM1000 Beta. He configured the SM1000 to interface to his IC706 using the CN12 connector patch socket. This allowed an RJ45 cable from the SM1000 to connect to the RJ45 mic/audio connector on the IC706. A few level adjustments and he was using FreeDV to . . . → Read More: SM1000 Part 10 – First Over the Air Tests

GMSK Modem Simulation

Modems are an interface between theoretical physics and what can actually be built. The laws of physics set the limits of modem performance, and ultimately the amount of power you need for a certain bit error rate at a receiver. With the right algorithm, we can reach the limits of modem performance.

I think that’s kind . . . → Read More: GMSK Modem Simulation

FSK over FM

I’m interested in developing a VHF mode for FreeDV. One intriguing possibility is to connect a modem to legacy analog FM radios, which would allow them to be re-purposed for digital voice. One candidate is FSK at 1200 bit/s, which is often used over FM for APRS. This operates through FM radios using . . . → Read More: FSK over FM

SM1000 Part 9 – First Betas

Edwin and his team at Dragino have hand assembled the first two SM1000 Beta units in Shenzhen. I’m working with him to perform some initial tests while we wait a few days for the prototype enclosures to be made. Then Rick and I will both get a SM1000 shipped to us for testing. . . . → Read More: SM1000 Part 9 – First Betas

SM1000 Part 8 – Video and Beta CAD work

Over the last few months Rick KA8BMA has been working steadily on the schematic, PCB, and enclosure CAD work for the SM1000 Beta. This is now complete, the Beta PCBs have been made, and the first 2 Beta units are being hand assembled by Edwin at Dragino. Rick and I will test these, then . . . → Read More: SM1000 Part 8 – Video and Beta CAD work

OpenRadio Part 3 – Filters

Over the past week I’ve built my own OpenRadio prototype, using the construction notes Mark has put together as a guide.

To help others I measured a few DC voltages and recorded them. I found one small bug in my assembly: one of the flip-flop pins was not soldered correctly, leading to erratic signals. After . . . → Read More: OpenRadio Part 3 – Filters

Robust FreeDV Part 1

I’m working on increasing the robustness of FreeDV over HF radio channels, in particular compared to analog SSB.

Why HF Digital Voice so Hard

HF radio channels are bad news for digital data. Here is a plot of the Bit Error Rate (BER) versus Eb/No for two different modems (DQPSK and QPSK) and two different channels (AWGN and . . . → Read More: Robust FreeDV Part 1

OpenRadio Part 2 – Prototype Works!

Since the first post on the OpenRadio project Mark has been moving ahead and leaps and bounds. In just a few late nights work he has assembled and tested the radio, managed to receive off air signals, and even tested the PSK31 transmitter! Fine business Mark.

Mark writes:

Hooked it up to a real antenna tonight:

That’s . . . → Read More: OpenRadio Part 2 – Prototype Works!