Tuesday, January 29, 2019

Sending Samples to Python from GRC using ZMQ Sink

When we need to process some data generated by an SDR device, the most convenient approach we have currently is saving the data into a file and then reading the files from Python. However, if the requirement is to process data in real-time as they are generated from the SDR device, saving to a file is not the right way. GNURadio Companion software provides a special set of sink blocks which uses ZMQ messaging protocol for such purposes. This post demonstrates how to use one of such sink types in order to deliver raw samples generated by a GRC flow graph into a Python script.

(1) Create the following flow graph on GNURadio Companion. Instead of taking data from a real SDR device, we use two Signal Source blocks to generate two cosine wave signals with 3MHz and 5MHz frequencies. We set the sample rate to 4 MHz. The Throttle block is necessary to regulate the data flow through the flow graph since we are not using a real SDR hardware. Most importantly, we are using a ZMQ Push Sink block. Notice that we have given the localhost IP address and an arbitrarily selected port number as the destination of the data.



(2) Now, in order to capture the data, we need a Python script which implements a ZMQ Pull client. Create a Python program with the following content and save it as client.py.


import time
import zmq
import random
import numpy as np
import matplotlib.pyplot as plt

def consumer():
    consumer_id = random.randrange(1,10005)
    print("I am consumer #%s" % (consumer_id))
    context = zmq.Context()
    consumer_receiver = context.socket(zmq.PULL)
    consumer_receiver.connect("tcp://127.0.0.1:5557")
    
    while True:
        buff = consumer_receiver.recv()
        print(time.time())
        data = np.frombuffer(buff, dtype="float32")
        data = data[0::2] + 1j*data[1::2]
        print(type(data))
        print(len(data))
        #plt.figure()
        #plt.psd(data, NFFT=len(data), Fs=4e6, Fc=1e3)
        #plt.savefig("psd.png")
        #time.sleep(0.5)
        #exit()
        
consumer()

(3) We need to start the client Python program first from a terminal.

python client.py

(4) Now, start the GNURadio Companion flow graph. On the terminal where our Python program running, we should be able to see the chunks of data coming now. The number of samples contained in each data set various over time which I'm not exactly sure why. Following screenshot shows the output on the terminal.


(5) If we activate the commented lines, we can save a plot in a PNG file which shows the power spectral density (PSD) of the received signal. As expect, there are two peaks in both sides of the center frequency with a gap of 1 MHz. This is because our sampling rate was 4 MHz while there were two signals with 3MHz and 5MHz in the captured signal. Following figure shows that PSD graph.

The code for the Python script and the GRC flow graph file are kept in a Github repository to try it easily. Cheers!

Useful links:

[1] More reading on PyZMQ library.

[2] A question in StackExchange where somebody had suggested to use ZMQ Sink.

[3] The Github repository with my codes illustrating this work.




1 comment:

  1. Thank you - Took me forever to figure out how to convert the bytes to complex. This helped. Thanks again! :-)

    ReplyDelete