NBFM Transceiver with Pluto SDR and GNU Radio

The first step consists of installing GNU Radio and the interface to Adalm-Pluto or PlutoSDR on an Orange Pi One Plus running under Armbian. Then as an example, we will study the realization of a transceiver or an NBFM transponder.

Hardware Configuration

Orange Pi One Plus

The Orange PI One Plus is a powerful development board offering many possibilities with its 64-bit 4-core processor (H6). For the installation of the operating system, see the following article: https://f1atb.fr/index.php/2020/09/01/orange-pi-one-plus-setup/

The Adalm-Pluto or Pluto SDR is an interesting software radio to create a transceiver operating in duplex.

Pluto SDR

The Pluto interfaces with the USB port which behaves like an ethernet port. It should not be powered by the Orange PI’s USB port, because there are breaks in the connection. In addition add an external 5V2A power supply. The Pluto has a micro USB input to power it. Put a USB port hub to connect a mouse, a keyboard necessary for development and correct a bug on the USB bus (see below). Connect your Orange Pi to ethernet as well as a video monitor to the HDMI or use VLC to view the screen in graphic mode necessary for GNU Radio Companion.

GNU Radio 3.7 installation

GNU Radio Companion is a graphical tool allowing you to build radio processing chains very easily without writing a line of code.

apt-get install gnuradio

Adalm-Pluto interface installation

Check that the following modules are present with:
lsmod. They are absent with some versions of Armbian.

  • cdc_acm,cdc_ether
  • rndis_host
  • rndis_wlan
  • usbnet

If a module is missing type:
modprobe “module name”

modprobe adds the modules with their dependencies, so by adding for example cdc_ether, usbnet will also be added. After each installation make an lsmod to check.

As recommended on the Analog Device website, add in the folder
the rules file: 53-adi-plutosdr-usb.rules given below.

# allow "plugdev" group read/write access to ADI PlutoSDR devices
# DFU Device
SUBSYSTEM=="usb", ATTRS{idVendor}=="0456", ATTRS{idProduct}=="b674", MODE="0664", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="2fa2", ATTRS{idProduct}=="5a32", MODE="0664", GROUP="plugdev"
# SDR Device
SUBSYSTEM=="usb", ATTRS{idVendor}=="0456", ATTRS{idProduct}=="b673", MODE="0664", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="2fa2", ATTRS{idProduct}=="5a02", MODE="0664", GROUP="plugdev"
# tell the ModemManager (part of the NetworkManager suite) that the device is not a modem, 
# and don't send AT commands to it
SUBSYSTEM=="usb", ATTRS{idVendor}=="0456", ATTRS{idProduct}=="b673", ENV{ID_MM_DEVICE_IGNORE}="1"
SUBSYSTEM=="usb", ATTRS{idVendor}=="2fa2", ATTRS{idProduct}=="5a02", ENV{ID_MM_DEVICE_IGNORE}="1"

If while testing with lsusb you do not see the Pluto and dmesg gives you for the port concerned unable to enumerate USB device, in this case add a USB hub (not necessarily powered) and it should be okay. Do not ask me why.

To make Adalm-Pluto work with GNU Radio, you need to install the following packages:

  • apt-get install gr-iio
  • apt-get install libiio-utils
  • apt-get install gqrx-sdr

SSH Access

The Pluto has a Linux operating system accessible in ssh at the IP address:

  • user: root
  • password: analog

Note on USB2

USB 2.0 is a 480 Mb / s half-duplex serial protocol. Assuming 100% usage, 480Mb / s would equate to 60MB / s.
Due to the communication protocol between the card and the device, it is not possible to exceed ~ 45MB / s.
Since this is a half duplex, this is ~ 22.5MB / s for transmission and ~ 22.5MB / s for reception.
Since each sample is two bytes (12-bit samples), a maximum of ~ 11 MSPS (Mega Samples / s) can be requested. Knowing that there is an I sample and a Q sample, this makes a maximum of 5.5 MHz sampling frequency. But in practice with the hub and the other peripherals on the USB, it will be even lower to be sure to have a smooth connection.

Note on the Local Oscillator

The local oscillator of the PlutoSDR serving as a reference for the processing runs at 40,000 MHz. It has a frequency stability of ± 25 ppm (voltage, temperature, drift plus initial precision) which is not very efficient.

You might think this is really bad (and it is), but:

it can be corrected digitally by programming the XO frequency. If you notice that it is 39.987654 MHz (up to Hz resolution), you can tell the system, and the LO frequency and sample rates will be updated to reflect this. Once stabilized in temperature, make the correction by accessing in ssh and setting the environment variable xo_correction:

fw_setenv xo_correction 39987654

By monitoring this frequency offset, it can be updated on the fly. It should be noted that there will always be random phase shifts between LO Tx and Rx, but they should be exactly the same frequency.

GNU Radio-PlutoSDR – interface blocks

Pluto Source (receiver)

It contains the basic parameters, namely the central frequency, the sampling frequency, the processing band. Note that these values are integers and not floating point numbers.

Details of the blocks can be found on the Analog device wiki https://wiki.analog.com/resources/tools-software/linux-software/gnuradio

Pluto Sink (transmitter)

Likewise for the transmission module, it is necessary to define the central frequency, the sampling frequency and the processing band.

Note on Sampling

For the reception channel, the minimum Analog / DigitalADC conversion rate is 25 MSPS. Baseband rates less than 2.083 MSPS (25 MSPS / 12) require definition of FIR decimation / interpolation. In other words, the FIR filter must be configured and activated. The minimum baseband rate with the FIR filter (decimation by 4) enabled is: 25MSPS / (4 * 12) = 520.83 kSPS.
Ditto for the transmission chain, the minimum ADC rate is 25 MSPS. Baseband rates less than 2.083 MSPS (25 MSPS / 12) require definition of FIR decimation / interpolation. In other words, the FIR filter must be configured and activated. The minimum baseband rate with the FIR filter (decimation by 4) enabled is: 25MSPS / (4 * 12) = 520.83 kSPS.

NBFM Transmitter – Receiver

As a simple example, it is easy to set up a small narrowband FM (NBFM) transceiver that can operate as a duplex relay or as a 144 MHz to 432 MHz transponder. This diagram can be reproduced for other working frequencies knowing that the basic Pluto covers the 325 MHz to 3800 MHz band. But it is possible to extend the band from 70MHz to 6000 MHz as described in this article : https://f1atb.fr/index.php/2021/03/09/frequency-extension-of-pluto-sdr/

NBFM Transmitter – Receiver

Receiver chain

Open a new project in GNU Radio. In the Option block, choose the WX GUI graphical interface. In the Variable block, samp_rate set the sampling value to 600000 (600kHz).

Put a slider block (WX GUI Slider) and position the desired receiver frequency band.

Put the important block ‘PlutoSDR Source’ which describes the data input interface of the Pluto. The sampling being at 600kHz, we limit the band to 500 kHz (+/- 250kHz) At the output connect a low pass filter to limit the band to +/- 7 kHz. Decimate the sampling by 15 to arrive at 40kHz at the input of the NBFM detector which will provide audio at 10kHz. For this audio, sampling at only 10 kHz is sufficient. We are dealing with the voice not exceeding 4 kHz and not the HIFI requiring sampling at 48 kHz. This makes it possible to limit the output flow.

Audio output on the network.

The processing format inside GNU Radio is 32 bit float. We will limit ourselves to 16 bits integer. Knowing that the audio is framed by floating between + and -1, we pass in full by multiplying by 16000. This audio is not listened to locally but sent in streaming on the network to be listened to by VLC on a remote PC ( IP address: 192.168 ……, port 9001). See the procedure here: https://f1atb.fr/index.php/2021/03/15/gnu-radio-output-to-vlc/

Go to the VLC folder in windows and type the command:

vlc --demux=rawaud --rawaud-channels=1 --rawaud-samplerate=10000 udp://@:9001

This receiver is as simplified as possible. In practice it would be necessary to add other functions such as gain control, squelch, audio filter, etc.

Transmitter chain

To put it simply, we will position an audio generator whose amplitude and sine frequency will be adjustable with 2 WX GUI Sliders.

The 10 kHz sampled audio source drives an NBFM modulator which generates a complex 40 kHz signal. Which is interpolated to reach 600 kHz (Pluto needs samples at 520kHz minimum). The radio transmission frequency is positioned in the 144 or 432 MHz band or ..

NBFM Transmitter

Position a radio receiver (SDR key or other) next to the Pluto and listen to your broadcast at low level.

Transponder relay

It is very easy to convert this system into a transponder relay by connecting the audio output of the receiver to the audio input of the transmitter whose generator has been inhibited.

Radio relay


The GNU Radio Companion file ( *.grc) of the source code described above is available here: https://f1atb.fr/wp-content/uploads/2021/03/NBFM_TX_RX_Pluto.zip

Calculation load balance

With this transceiver configuration it is interesting to see the computational load imposed on the Orange Pi as well as the input / output rates. To do this in terminal mode, type: htop, application which gives a report in a single view.

Processing load

The computational load (in green) is approximately 14% = 100 * 0.57 / 4. The max is 4 because of the Quad-Core. There is still something to add functionality to our transceiver.

The output Ethernet (Eth0 in red) with 26KB / s matches well the audio sampled at 10k / s over 2 bytes plus the bitrate of my screen display.

The Ethernet / USB of the Pluto (Eth1 in yellow) with 2.7MB / s in each direction corresponds to the sampling at 600kHz on 2 channels (I and Q) on 2 bytes each.

Posts about Adalm – Pluto SDR

Posts about GNU – Radio