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


while(1) {
for (f=8.0; f<12; f += 0.1) {
f_ull = f*100000000ULL;
si5351.set_freq(f_ull, 0, SI5351_CLK0);

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


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 worst case 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?

30 thoughts on “Minimalist VHF Software Defined Radio Part 1”

  1. Dave, have you heard of/looked into the Connect Systems CS7000? It will be basically a traditional looking HT with an SDR core. It will support D-Star and DMR,I think, when it comes out. The processor is the same STM32F4 that’s in the Smart Mic. It’s also got an AMBE3000 for all of the modes that use AMBE. The firmware will probably be open source (although I haven’t seen much of it yet) and be modifiable. I think it would be a great target for VHF FreeDV.

  2. Hi Brady,

    The CS7000 sounds like a step in the right direction, especially if they open it up. I’m hoping to develop a completely open VHF radio this year, and it won’t be supporting AMBE :-)

    – David

  3. Interesting article. I know the NE602 is not popular in anything except toy receivers (but toy receivers are the most fun!). I don’t know what to replace it with though. The options are many, and most maybe need too much LO power.

    Anyway, my comment is maybe to direct you to the neat minicircuits site, where you can enter some parameters and it will kick out some possible chips.

    1. For mixers I thing that one quite suite is the ADL5350 (3v 19mA 1Hz – 4GHz), Analog Devices also has other interesting mixers.

  4. Hi David and all,

    WOW!! Most impressive.

    Now about modulation schemes that pass easily through this minimal hardware….

    I have I&Q –> audio ADC –> Linrad –> Fldigi. Works exceptionally well !! So I guess I would include I&Q in your deliberations. FWIW Linrad gives real db measurements which is very useful during design. Many hams think they are reducing their power levels, but measurements don’t concur with their claims. Caveat emptor….

    Also, the website includes a MOST impressive set of measurements on real RF hardware. All done in software. Well worth careful study and adding to your toolset.!

    Some sort of mfsk seems like a natural. Single tone, constant power. A simple multilevel amplitude scheme could be added to up the bit rate. Most filters of the XMTR chain are GONE !! And its basically broadband.

    Lots of fun.


    1. Actually a I/Q at the receiver end don’t give much advantage over non I/Q receiver, through it have some advantages due to lower ADC sample rate for the same bandwidth, but for typical bandwidth of amateur radio this advantage is null even for commercial FM this is also true due to the cheapness of +1Msps ADCs. Also for this basic design supports modulation at the receiver end if it have it enough bandwidth for it.

      In the transmission end the thing changes as a I/Q modulation is pretty well suited as it can be used to generate any modulation scheme, and is when it makes more sense, more if you modulate directly or use a high IF.

      1. correcting:
        Also this basic design supports any modulation at the receiver end if it have it enough bandwidth for it.

    2. Hi John,

      We are targeting very high performance GMSK based Codec 2 (including TDMA and diversity reception) as per the previous blog posts.


  5. Well I revisited some old projects ideas about SDR radios, and definitively an I/Q modulation makes a lot of sense more if you modulate a IF in the GHZ range and then downmix, with this approach the RF filtering is simplified and the image rejection is near perfect.

    One of the ideas was to use components designed to WiFi or other easy obtainable GHZ range ICs, one of the designs used a ADL5350,MAX2870,MAX2835, and using a IF of 3,85ghz, it was able to work from from kHz range up to the 9cm band, it was only a common platform and it needed proper preamplifier and power amplifier for each band. Lamentably I was never able to pass from the design phase due to money constrains and need of equipment.

    The only thing that I was able to built was a test receiver using a IF of 1,2Ghz and it was able to receive continuously from 17khz to 600Mhz, the only limitation was the need of a proper antenna for the lower frequencies.

    1. FB on the radio you have worked on. Well IQ image rejection is never perfect, as you can’t get perfect phase and amplitude matches. 60dB is possible if you’re very careful.

      1. Thanks, but I was speaking of the IF image rejection not the I/Q image rejection, the I/Q modulation was something that I didn’t investigate in profundity as I was mostly centered about the reception. I need to study more about the I/Q modulation as I miss a lot of its theory.

  6. Hi David and all,

    Great Project :) :) !!

    I wonder if a cheap FPGA could do the ADC thing using its differential inputs for the sigma-delta comparison? I guess spectral measurement of a single tone gives a pretty good measure of how clean the ADC system really is? Again, linrad should be a pretty good help there.

    My I&Q rig seems to get about 30-40 db balance out of the box (no special software correction). So the ‘filter’ type of radio beats it in that regard for sure. I use a high freq VCO and a divider to get the phase balance along with diode mixers. The VCO is a PIC stabilized discrete VCO so that could probably be improved as well. And as noted it can go to very high frequencies with no problem other than the obvious ones.


  7. Hi David,

    For the front end mixer I’d be looking at a ring-diode mixer at VHF they are hard to beat, it will however require a fair amount of LO drive. You want your mixer to have a nice strong IP3 if possible, anything over +20dBm is a good start. At the very least swap to using an NE612 or plessy high side mixer (if you can find any) they will romp all over your NE602. Mark at mini-kits has a good range of ring diode mixers, he’s also local.

    With regard to a front end filter then take a look at temwell ( these guys make clones of the now obsolete Toko Helical filters that everyone remembers from the day. Price can be a little steep, but they will at least sell in low qty for hobbyists.

    If possible keep your gain after your mixer, this will help with the NF especially if you select the right mixer. Actually if you want to add more gain pile it on after the filter. These small filters don’t take much power (< 0dBm) so if you pile on too much amplitude before the filter you can have problems.

    Now I know you like food for thought. So with your BPF and crystal filter after the first mixer you might like to consider a diplexer instead. Let the 10.5MHz energy pass through your BPF and into the crystal and dump all of the unwanted energy (using a notch filter) into a known load (ie 50R). Also these small IF filters may not be 50R, to watch that your input and output impedances are correct… they are usually somewhere between 100-400R (typically 300R).

    There are plenty of examples and papers on the net about using a diplexer after your mixer. Ring diode mixers (et al) don't like their output port unterminated at any frequency, strange things happen. If you're wondering why people used to put 6dB attenuators after the first mixer, well I'm sure it's now obvious that they were ensuring that the RL of the output port was "at least 6dB". Unwanted strong signals that get into the mixer that then don't have anywhere to go, well bad things then happen.

    Anyway sounds like your having fun, keep up the good work.


  8. Hi David and all,

    I REALLY like the idea of the absolute minimum radio, transmit and receive.

    The more done in the processor the better!

    Now about that 1KW transmit amplifier :) :).


  9. Any reason why you’re not going with a 10.7 MHz IF?
    From what I recall, there are very nice ceramic and crystal filters ranging from WFM down to at least SSB available on the market, as 10.7 MHz and 455 kHz still are kind of standard for IF strips.
    Just a thought.

    1. Yes that’s why I chose 10.something MHz as the IF. The IIR tuner code would need to be modified, and would be slightly less efficient as the sqrt(beta1)*cos(w) term would re-appear.

      1. Ah. You would have to select the sampling freq so an overtone matches the 10.7 Meg center of a ceramic filter and open up that can of worms and math.
        It was just a thought, having it on a common IF of common radio and homebrew designs so you could add just the IF part with minimal modifications (e.g. high-Z buffer from an IF transformer).
        I’m big on modular designs. :)

        1. Oh, just occured to me, there used to be ceramic filters for analog television sound (e.g 4.5, 5.5, 6 and 6.5 MHz and so on(I have a vague recollection there used to be a decently high sound IF in one standard)), wonder if there are manufacturers or distributors with those ceramics in stock or production?

        2. Oh it wouldn’t be too hard, I could change Fs of the ADC or modify the tuner code. I had a look around for ceramic filters but couldn’t find a source easy to get here in .au, Xtal filters remain an option, as are LC filters.

          1. Hey David, I was playing around with trying to get the filter/downconverter centered around 700kHz. Adding another mul/shift term to the fixed point IIR filter will probably bring it to around the same performance as the unoptimised filter. I’m still trying to figure out what sampling rate/decimation/center freq combination works, but it should still be within the computational budget for the project.

          2. oh, wait — 700kHz is perfectly centered in the 31st harmonic — it’s just frequency reversed when decimated back down

          3. and if you decimate by 55, 700khz is perfectly centered on the 38th harmonic of the nyquist freqyency and there is no frequency domain reversal.

  10. This is great stuff!

    I agree that I/Q baseband (Zero IF) is not ideal – too much hardware, too many calibration issues. Using a single real channel ADC and then doing I/Q processing in digits makes a lot more sense to me.

    I’ve also been experimenting with using the STM32 family to do SDR and had hoped to do it all in software. I found that I had to make major compromises on selectivity and tunability to allow it to fit in the available CPU cycles. Since I’m pretty comfortable with doing DSP in FPGAs I’m working on some experiments to do just the tuning, filtering and decimation operations up front of the STM32. It doesn’t require any fancy FPGA either – it will fit in a $10 Spartan3A part and the resulting data is at a low enough rate that SPI or I2S can be used to ship the data over to the STM32. That also leaves a lot more CPU cycles for the hard stuff like running codecs.

    1. Ok using the FPGA with the STM32F4 is an interesting approach. I’m happy with my tuner MIPs so far. Current work is outside the STM32F4, i.e. mixer, BPF and LO.



    2. I’ve always meant to look into FPGA, and one time actually started downloading all the data and software, after a week or so I think I had everything downloaded, and then I started trying to actually use the software. I think it may be a right brain/left brain thing, and since I could never learn to play the piano properly, I can probably never hold my tongue just right to connect gates together into something useful. For me, it was an expensive waste of time, as shortly thereafter the chip was discontinued, and you then have to regroup. Hoping to get your 5 boards before the chip goes out of production.

  11. I was thinking, for a TDMA basic design, it might be forward thinking to have two LO freqs. For example, a four time slot system could receive data on slot 1 F2, and everyone could receive sync on slot 1 F1. Some GPSDO based course sync generator on a hill, or for out in the boonies, one user can be made master and transmit course sync. Fine sync derived from the data.

Comments are closed.