I wanted to use my USRP Software Defined Radio to monitor the whole 23cm EME band activity especially during moon bounce contests.
MAP65 expects IQ data in 96000 samples per second (sps) using a stereo audio device as input. This input device can be a virtual audio cable and this is what will be used below.
GNU-RADIO is used for rate conversion and streaming.
The USRP has a programmable data rate and its minimum is 250k so it cannot reach 96k without rate conversion. Conversion can be done multiplying first x 3 and then diving by 8 since 256*3/8= 96
After rate conversion there are 2 ways to send data to MAP65.
The easy way (“Solution 1”) is to just send IQ data to a virtual audio device within GNU-RADIO. This works but sometimes there are some audio gaps and clicks
There is also another way (“Solution 2”) One could send the IQ data over UDP datagrams. A python script outside of GNU-RADIO can take the UDP data stream and send it to the virtual audio device. The second way resulted in clearly better audio
If you want to find out how install GNU-RADIO on Windows follow the link below.
Below both solutions will be described:
SOLUTION 1 : STREAM DIRECTLY TO THE VIRTUAL AUDIO DEVICE (EASY)
Put the following flow graph together, assign the Virtual Audio Cable to be the default sound device in Windows , leave the Device Name blank in Audio Sink and you are done !
Note: Forgot to add a low pass filter between USRP and rational resampler. This is needed to avoid aliasing . Need to update picture below
SOLUTION 2 : STREAM OVER UDP AND USE A PYTHON SCRIPT TO SEND SAMPLES TO THE VIRTUAL AUDIO DEVICE
As in Solution 1 above, after some low -pass filtering, rate is converted to 96k. Then it is being sent over UDP.
Some code was written (see below) in python to get the IQ data from the UDP stream and send it to a virtual audio device. MAP65 uses this virtual audio card as the input device.
As mentioned above, direct streaming to the virtual audio device within GNU-RADIO did not result in very clean audio but it was good enough for successful JT65 decodes.
On the other hand Solution 2 , resulted in clean FFT plots and there were no issues with gaps and clicks anymore.
Python script for Solution 2 can be found at the end of this page. Obviously, there must be a virtual audio cable installed for these solutions to work and referring to the code below the output_device_index should be set accordingly.
IMPORTANT : JT65 RECEPTION REQUIRES A TCXO , BUT USRP1 COMES WITH A SIMPLE DRIFTING CRYSTAL OSCILLATOR
I had to replace the 64 MHz oscillator in the USRP with a suitable 64 MHz TCXO. Luckily I found one on ebay (click here)
Michael Margaras, SV1CAL
#Written by Michael Margaras-SV1CAL
from struct import *
p = pyaudio.PyAudio()
count = p.get_device_count()
devices = 
for i in range(count):
for i, dev in enumerate(devices):
print “%d – %s” % (i, dev[‘name’])
dst = p.open(format = FORMAT,channels = CHANNELS,rate = RATE,output = True,output_device_index = output_device_index,frames_per_buffer = CHUNK)
UDP_IP = “127.0.0.1”
UDP_PORT = 50024
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
data, addr = sock.recvfrom(CHUNK)