ik1xpv hamradio software & hardware

Some variations of ExtIO_sddc.dll architecture

During Summer holidays I experimented about decimation scheme of BreadBoard RF103.

The ExtIO_sddc.dll processes the ADC real signal stream. The sampling rate is 64 MHz.
The output is a decimated I&Q complex signal stream at 16 MHz, 8MHz, 4MHz or 2MHz.
Filtering and tuning are integrated.


The dll uses CyAPI library to connect BBRF103 hardware via USB3.0.
A USBthreadProc thread uses 16 buffers queue to receive data chunk of 65536 samples (short).
One buffer’s time duration is about 1 ms at 64 MHz.
I configured USBthreadProc to run at high priority to be responsive to hardware timing.
The USBthreadProc output buffer is processed by the class RFddc that has an own buffer array of 16 elements.
The time of a circular turn of 16 buffers queue allows the digital down conversion algorithm of each chunk to complete on a separate thread.
The previously computed output vector is returned while the signal processing of the buffer is started. A priority for these threads below normal seems good enough.
Frequency domain signal processing is used. An overlap and add FFT scheme processes the buffer 65536 sample frame and overlap and save scheme glues the buffers together.

The following diagram represents the processing of one buffer frame and it is implemented in every thread of the RFddc pool of 16.



1) It is the input sample array of short. It is a real signal. The frame buffer is a sequence of 65536 samples (it can be seen as a sequence of 64 *1024 slice).

2) The last 1024 slice in the past is copied at the beginning of the array to form a frame of 65 *1024 = 66560 samples. This is the overlap and save scheme.

3) A complex array 66560 samples long is obtained from (2) adding a zero imaginary component.

4) Starting from 0 the array is divided into slices of 768 samples to implement override and add (Overlap and add method)  with an overlap of 256 and a fast Fourier transform (FFT) of 1024 sample frame.

5) Every 768 slice is copied into a 1024 one adding a tail of 256 sample zero filled.
85 slice of 1024 complex samples.

6) A FFT forward is applied to the every 1024 slice. 85 slices in frequency domain are computed.

7) For every slide a circular shift of the FFT’s bins is used to implement tuning to the IQ carrier frequency.
The resolution is 64000000/1024 = 62500 Hz. This coarse step is good enough for HDSDR tuning that uses its own fine adjustment. A phase adjustment is required depending on the tuning bin position.

8) A low pass filter of the signal is implemented as fast convolution (https://en.wikipedia.org/wiki/Convolution#Fast_convolution_algorithms) multiplying the FFT bins by the complex conjugate (https://en.wikipedia.org/wiki/Complex_conjugate) frequency response of the filter (Hw*). To use the fast convolution approach the length of the time filter response ht is limited to (1024 -768) +1 = 257 samples.

9) Decimation in frequency is used. The implemented output lengths are 256,128,64,32 that obtains output rate of 16MHz, 8MHz, 4MHz, 2MHz. It is made just copying the decimated FFT bins chunk near zero frequency.

10) The resulting output is a sequence of decimated FFT ( 256,…) bins. Steps (7) (8) (9) are implemented together in a copy and modify loop.

11) The 85 slices of decimated FFT.

12) The FFT inverse is computed.

13) The time output is computed with overlap and add of the 85 slices. The first 256 samples and the latest 512 are dropped using overlap and save (Overlap save method)  of the 64 * decimated FFTN samples frames.
The function has an array of 65536 samples input and returns an array of 16.384 samples at 16MHz, 8.192 at 8MHz, 4.096 at 4MHz, 2.048 at 2MHz.
A separate thread processes the signal from each one buffer.


CPU use of HDSDR and ExtIO_sddc, V0.95 ADC 64MHz, IQ 16Msps ; 60 s plot

I made some debug measuring the time jitter of USBthreadProc 16 buffer cycle.
The theoretical time is 16 * 1.024 ms = 16.384 ms.
Here after a plot of the measured duration time - 16.384 ms.
The plot shows that the peak jitter is within +/- 3mS.



USBthreadProc 16 buffer circle timing jitter running at 64 MHz in 16MHz sampling output, 60 s plot.

I named this release version 0.95 and I save it in a separate GitHub repository at:


I switched to the integrated Visual studio Git and it was simpler to me to keep it separate from other BBRF103 project components.


To be continued.

BreadBoard RF103

These are exciting times for homemade construction of Software Designed Radio (SDR).  Our laptop and desktop have more computing power. Better compilers simplify multi thread programming. Computer interfaces run at higher throughput rate. 

I designed the breadboard BBRF103 to learn how to use and to test the following components :

  • FX3 SuperSpeed Explorer Kit USB3.0 transfers the ADC sample stream to the PC.
  • ADC (LTC2217) samples the real data at 16 bit up to 105 Msps.
  • 0-30MHz input, attenuator (0,-10,-20 dB) and LPF transfer antenna signal to the ADC.
  • Tuner ( R820T2 ) down converts signals in the 30-1800 MHz range to the ADC.
  • Clock generator ( Si5351A ) outputs the clocks to the ADC and the R820T2.



In other words the idea is to avoid the Digital Down Converter (DDC)  Custom or FPGA chip in between ADC and PC. The full HF radio spectrum is processed by the host computer connected via an USB3.0 port.

BBRF103 is placed in series between Antenna and Computer. A modern pc (I5-I7 CPU or higher) equipped with USB 3.0 is required.

The R820T2 chip has been added to look at its performance with a 16 bit ADC and wide bandwidth. 



The hardware uses two separate antenna connectors  0-30MHz  and  30MHz-1.8GHz

I made the schematic using cut and paste of the main components test circuits. 

The HF input (0-30 MHz) is routed to a multiplexer circuit. Some resistors  implement a step attenuator with value 0, -10 , -20 dB. The attenuator's output goes to a low pass filter and then to the ADC input via a balancing transformer. The ADC parallel output bus is routed to the FX3 SuperSpeed Explorer Kit using the kit IO connectors. The Cypress kit uses some GPIOs as control of multiplexer and ADC while a I2C bus is used to program the Si5351a clock generator and the R820T2 tuner.

The input multiplexer other than the HF input selects the R820T2 tuner output. 

The R820T2 uses an indipendent input (30MHz - 1.8GHz) connector.  The Si5351a tuner generates by the tuner reference clock; the first software prototype setup uses a 32 MHz. The software may program different reference frequency to move out of band spur signals.

The Si5351a generates also the ADC clock .  The pcb previews an optional backup alternative with a fixed frequency oscillator. 

The Si5351a's reference Xtal is 27.000MHz. Another frequency may be used. This is the only frequency reference of all the hardware. The software will be able to compensate the accuracy of this xtal with a correction coefficient. 

The clock is coupled to the ADC LTC2217 using a rf balancing transformer.  




An extruded aluminum box of 100 * 76 * 35 mm is large enough to accommodate the FX3 SuperSpeed Explorer kit and board PCB.

The size of the PCB is about 100x70 mm. Two 40x2 headers connect the FX3 SuperSpeed Explorer kit.


The PCB board contains the main components on the underside. The ADC has a copper radiator on the top. It taps the aluminum box to dissipate part of the ADC heat.

The two RF input connectors are SMA.


On the upper side there are the power regulator, pin connectors and two jumper cables in coaxial cable for the R820T2 clock and the IF signal.


The final assembly of the prototype shows the FX3 kit at the top of the BBRF103 board. 


The prototype has a 5 volt Auxiliary Power Connector that was used during the first tests.  It is not necessary because the required current is less than 800mA and can be supplied by the standard USB3.0 connection.

The hardware scheme and pcb layout at https://github.com/ik1xpv/BBRF103/tree/master/HARDWARE .


The FX3 firmware is a modification of Cypress streaming examples. Some Vendor commands have been added to control I2C bus and to control GPIO e PWM output.

SDK comes with the Cypress Eclipse development enviroment. It's a nice exercise to learn how to use FX3.

BBRF103 uses the Cypress USB driver that comes with FX3 Kit.

The firmware source repository is  https://github.com/ik1xpv/BBRF103/tree/master/FX3Firmware



The prototype has been tested with the HDSDR application that i like a lot (THANKS to Mario Taeubel and Alberto di Bene).

I designed an ExtIO_sddc.dll. The name stands for ExtIO software digital down convertion. The dll task is to tune and to downconvert the SDR real samples, generating a IQ complex downsampled stream that is processed by the HDSDR application.

The software source repository is  https://github.com/ik1xpv/BBRF103/tree/master/ExtIO_sddc .

Here a video of BBRF103 prototype with a 1 meter wire antenna receiving local FM band in Turin. The PC used is a I5-3350P CPU @3.10GHz desktop




 I prepared a portable setup for summer holidays using a Laptop  i7-7500U CPU @2.70 GHZ  2.90 GHz




 To be continued.


BB60c and HDSDR

The Signal Hound BB60C Real-Time Spectrum Analyser and RF Recorder is a 9 kHz to 6 GHz Spectrum Analyser and RF Recorder with an instantaneous bandwidth up to 27 MHz. 



It is a state of the art device. Signal Hound (SH) provides documentation and software applications. Googling around you can see some inner pictures 


and review TSP #52 - Review & Experiments with Signal Hound BB60C ...

A friend of mine phoned me its appreciation for the performance of the unit and the possibility to use it as high performance receiver. Other than the powerful Spike application Signal Hound provides the ExtIO_BB60.dll for use with HDSDR.

This ExtIO_BB60.dll  http://www.signalhound.com/sigdownloads/Other/HDSDR-SignalHound.zip runs with the I/Q sampling fixed to 5Msps allowing a real time bandwidth of 8 MHz.

I decided to dig into the BB60c API manual and ExtIO_BB60.dll source code looking for higher sampling rate. A real time signal demodulation in a wider I/Q bandwidth.
My ExtIO_BB60c.dll version runs up to 40Msps sampling rate and shows 27 MHz bandwidth.  I named it ExtIO_BB60c.dll. It allows the selection of sampling rate, up to 40Msps.


Input sampling rate selection under Bandwidth button


HDSDR + ExtIO_BB60c running in real time at 40Msps.

HDSDR (version 275 or 270) can record the RF spectrum as a filename.wav.
The recording at 10Msps is fine. Nevertheless at 20Msps or 40Msps the recording shows some discontinuities every second.
Hereafter a 10Msps playback loop video example. 


 10Msps video playback loop. See HD video link or press YouTube.


I plan to make some better programming in the future if I will have the possibility to use a BB60c locally in my radio shack.



Source code of ExtIO_BB60c.dll at https://github.com/ik1xpv/ExtIO_BB60c

A compiled win32 ExtIO_BB60c.dll is at http://www.steila.com/test/ExtIO_BB60c.dll

The extio_bb60c.dll v0.8 MD5 is:

SHA-1 is
61c230eaa17013063514206c41c0bba930954e36 .

The required bb_api.dll may be downloaded from Signal Hound at: https://signalhound.com/products/bb60c/

https://signalhound.com/support/product-downloads/bb60c-bb60a-downloads/ (see API License)

While HDSDR site is
http://www.hdsdr.de/ (see License)

3radio project - Part 5

 Linear-feedback_shift_register ( LFSR ) is a shift register whose input bit is a linear function of its previous state.  A well-chosen feedback function can produce a sequence of bits that appears random and has a very long cycle ( en.wikipedia.org )

In 3radio a LFSR is used to generate a pseudo noise whitening sequence that shows a sharp auto correlation function .  

The Pseudo Random Noise (PRN) generator is implemented into an AT90USB162 uP.  

I used a 31 stages long LFSR with 2 taps: [31, 28] in Fibonacci configuration. The generator output bits are computed in 8 bit burst and sent to the SPI serializer at a clock rate that can be selected between 2, 1, 0.5, 0.25, 0.125 Mbps. Some clock phase skewing is caused by the USB routine interrupts but it seems not affecting the resulting randomness. In the following the clock was set at 1 MHz.


The output sequence period is 2^31 -1 clocks = 2.147.483.647 microseconds = 2.147 seconds = 35 minutes

31 bit LFSR fits into a 32 bit integer and output period is long enough to easily cover the latency delay in between the tre RTL-SDR USB receivers.

The uP output signal is as follows:


The signal frequency shape (sinx/x)^2 depends on the rectangular bit shape with clk 1uS that has a spectrum with minimums at 1MHz division.

The measure shown in 3radio project - part 4 are repeated with different receiver frequency. It computes the cross correlation between sequences of 100000 samples.


Center frequency 69 MHz sampling 2.048 Msps

The pseudo randomness of the sequence improves the cross correlation results versus the previous test. Side lobes are low and the time latency between different RTL-SDR is within the 100000 bit analysis span used. 


Center frequency 101.800 MHz sampling 2.048 Msps


Center frequency 144.000 MHz sampling 2.048 Msps

This measure shows the presence of a constant pattern that generates the triangular shape on the image on the left while  on the right one it causes the minimum value offset.

I think the reason can be the presence of the 28.800 MHz x 5 = 144 MHz harmonic spur that it's synchronous and quite strong. 

The following measure shows the results at 142000 MHz where there are lower spurs.

undefined Center frequency 142.000 MHz sampling 2.048 Msps


Center frequency 500.000 MHz sampling 2.048 Msps

The correlation measure at 500 MHz shows that this frequency without a pulse shaping is the limit of the usable range and the peak value is  40 dB lower (100 times) than in VHF tests.

Possibly the use of a shape pulse circuit flattens the spectrum and increases the energy at higher frequency.

3radio project - Part 4

3radio project - Part 3

3radio project - Part 2

3radio project - Part 1

3radio project - Part 4

Here some test results to evaluate the hardware performance and the use of a pseudo random binary sequence as reference to cross correlate the streams received from the 3radio, a radio composed by  multiple RTL-SDR hardware.

The 3radio has been tuned to 69 MHz center frequency and a sampling rate of 2048000 Hz has been chosen.  3 streams of 100000 IQ sample have been recorded using librtlsdr . The real time length is half a second.

The reference signal was a pseudo noise digital stream at 2 MHz shift rate.

The same signal was routed via separated switching diodes to all the RTL-SDR receivers.

Sequences of  about 3 ms or 6000 bits have been generated. A delay of some hundred of ms separates the different bursts. The reason was to be able to recognize some sync reference just looking to signals in time.


The previous figure shows the IQ streams in time, a chunk of about 6200 samples at 2048000 sampling is selected.

A script in python was written to compute the cross correlation. Here after the script:

# ik1xpv oscar steila 2016
# complex cross correlation of N files with 8 bit rawIQ data (RTL-SDR)

import math
import cmath
import matplotlib.pyplot as plt
import numpy as np
from scipy import signal

signals = [] #array of processed signals

# data raw IQ files [howmany required]
rawfiles = ["testX1", "testX2", "testX3"]

# The raw, captured IQ data is 8 bit unsigned data.
# Each I and Q value varies from 0 to 255.
# To get from the unsigned (0 to 255) range we need to subtract 127.5
# from each I and Q value, which results in a new range from -127.5 to +127.5.
# The complex data is y = I + jQ and we subtract 127.5 +127.5j

for filename in rawfiles:
y = np.fromfile(filename, dtype=np.dtype("u1"))
y = y.astype(np.float32).view(np.complex64)
y -= (127.5 + 127.5j)

ncorr = len(signals)
chunk_length = len(signals[0])
print(str(ncorr) + " sample vectors of " +str( chunk_length) +" samples length" )
for i in range(ncorr):
sig1 = signals[i]
ix = i+1
if ix == ncorr:
ix = 0
sig2 = signals[ix]
print("cross correlation",i,"<->",ix)
ccorr = signal.fftconvolve(sig1, np.conj(sig2[::-1]))
mod = np.linalg.norm(sig1)*np.linalg.norm(sig2[::-1])
print("mod", mod)
print("ccorr lenth", len(ccorr))
peakat = np.argmax(np.abs(ccorr))
print ("max position:", peakat)
print ("ccorr peak value:", cmath.polar(ccorr[peakat]))
print ("normalized value:", cmath.polar(ccorr[peakat])/mod,"\n" )
zcorr = ccorr[peakat - 500: peakat + 500]/mod
ss = "Correlation "+str(i)+"-"+str(ix)

plt.figure("normalized zoom near maximum")
plt.xlabel('note: signals are aligned with the max in position 500')


The cross correlation was computed over the whole streams length of 1000000 samples.

I got the following results and plots:

========= RESTART: C:\Users\Oscar\Documents\Python_code\Correla1.py =========
3 sample vectors of 1000000 samples length
filenames: ['testX1', 'testX2', 'testX3']
cross correlation 0 <-> 1
mod 1.43562e+08
ccorr lenth 1999999
max position: 1003874
ccorr peak value: (87426948.37116447, -3.0573868558433284)
normalized value: [ 6.08982555e-01 -2.12965829e-08]

cross correlation 1 <-> 2
mod 1.71879e+08
ccorr lenth 1999999
max position: 1002975
ccorr peak value: (124230240.98693986, 1.4627621167409313)
normalized value: [ 7.22777073e-01 8.51041512e-09]

cross correlation 2 <-> 0
mod 1.92693e+08
ccorr lenth 1999999
max position: 993148
ccorr peak value: (131838258.19245286, 1.598828000018114)
normalized value: [ 6.84189098e-01 8.29729322e-09] .


The results look quite good nevertheless the reference signal was far from perfect as you can notice from the cross correlation side lobes.

The time differences of the max positions define the time skewing between the streams. This time depends on the USB latency, on the different starting time of the software application trigger. I hope that the hardware clock skewing is solved with the synchronization.


3radio project - Part 3

3radio project - Part 2

3radio project - Part 1

3radio project - Part 3

The programmable 2-PLL VCXO clock synthesizer  CDCE925 from TI is configured to generate 12 MHz and 16 MHz clocks synchronous to the 28.8 MHz clock reference.

The 3radio prototype has been modified following the scheme:


TI ClockPro(TM) application is used to made the configuration file of CDCE925 while an I2C programmer (an Arduino board) is required to program it. 


Other than the 12 MHz and 16 MHz clocks used for the HUB FE1.1s IC and the AT90USB162 uP a 10 MHz synchronous clock is generated for comparison to lab frequency standard.

The 28.8 MHz buffered output goes to a two xtal filter made with the 28.8 MHz xtals de-soldered from the RTL-SDR. This filter is used to obtain the sinusoidal output signal that synchronizes the RTL-SDR dongles.


The FFT analysis shows a 40 dB attenuation of high harmonics. 

The CDCE925 has been mounted with dead-bug style and the cable used for the rtl-sdr 28.8MHz is RG174.  The cables have the same length, while for 12 MHz and 16 MHz a twisted wire pair has been used.


The 28.8 MHz TCXO and the 28.8 MHz xtal filter are on the top while the cdce925 is on the bottom side of the PCB. The black cables feed the clock to the RTL-SDR dongles. The grey twin wires on the left are the 12 and 16 MHz clocks.

3radio project - Part 2

3radio project - Part 1

Home ← Older posts