SDR, Software

Python Digital Phosphor Display with DearPyGui

The goal of the Intensity graded FFT project did not initially include a GUI aspect as I felt that the GNURadio Fosphor module provides an amazing spectrum display, but as I was programming I came across an interesting library that claims to provide a simple but powerful python GUI experience.

Previous post on Intensity Graded FFT plots and animations

DearPyGui

The DearPyGui library gets its power comes from its ability to use the computer’s GPU and has over 70 different drop-in widgets that are easy to use and manipulate. you can find more information on their github page below.

DearPyGui Github Repo

This library is an extension of the very popular DearImGui for C++. It currently supports these OS platforms and APIs below.

PlatformRendering API
Windows 10DirectX 11
macOsMetal
LinuxOpenGL 3

Seeing the capabilities of the library I was inticed to build on my intensity graded FFT project and create a simple GUI around it and the RTLSDR as well.

Demo GUIs

DearPyGui has some demo code in their github wiki that shows you how to do rudamentary gui programming and window manipulation. So I grabed a couple snippets and threw them into a Jupyter Notebook to start playing around.

DearPyGui Wiki

To install the library you can use pip, as usual, using the command below.

pip install dearpygui

I started with the basic window with some buttons, text, and sliders. This only requires a couple of lines of code!

from dearpygui import core, simple

def save_callback(sender, data):
    print("Save Clicked")

with simple.window("Example Window"):
    core.add_text("Hello world")
    core.add_button("Save", callback=save_callback)
    core.add_input_text("string")
    core.add_slider_float("float")
    core.add_button("+")

core.start_dearpygui()

I then moved to plots, and wow do they look beautiful and the animation is super smooth. I used another demo snippet to create two plots, one of an animated cosine wave and the other of a static heatmap which will be useful for later.

from dearpygui.core import *
from dearpygui.simple import *
from math import cos

def plot_callback(sender, data):
    # keeping track of frames
    frame_count = get_data("frame_count")
    frame_count += 1
    add_data("frame_count", frame_count)

    # updating plot data
    plot_datax = get_data("plot_datax")
    plot_datay = get_data("plot_datay")
    if len(plot_datax) > 2000:
        frame_count = 0
        plot_datax.clear()
        plot_datay.clear()
    plot_datax.append(3.14 * frame_count / 180)
    plot_datay.append(cos(3 * 3.14 * frame_count / 180))
    add_data("plot_datax", plot_datax)
    add_data("plot_datay", plot_datay)

    # plotting new data
    add_line_series("Plot", "Cos", plot_datax, plot_datay, weight=2)

with window("Tutorial", width=500, height=500):
    add_plot("Plot", height=-1)
    add_data("plot_datax", [])
    add_data("plot_datay", [])
    add_data("frame_count", 0)
    add_input_text("freq")
    with menu_bar("Main Menu Bar"):
        with menu("File"):
            add_menu_item("test")
    set_render_callback(plot_callback)

with window("Heat", width=500, height=500):
    add_plot("HeatPlot", show_color_scale=False, scale_min=0.0, scale_max=6.0, 
                         scale_height=400, no_legend=True, 
                         no_mouse_pos=True, xaxis_lock_min=True, xaxis_lock_max=True, xaxis_no_gridlines=True, xaxis_no_tick_marks=True,
                         yaxis_no_gridlines=True, yaxis_no_tick_marks=True, yaxis_lock_min=True, yaxis_lock_max=True, height=400)
    set_color_map("HeatPlot", 6)
    values = [0.8, 2.4, 2.5, 3.9, 0.0, 4.0, 0.0,
                          2.4, 0.0, 4.0, 1.0, 2.7, 0.0, 0.0,
                          1.1, 2.4, 0.8, 4.3, 1.9, 4.4, 0.0,
                          0.6, 0.0, 0.3, 0.0, 3.1, 0.0, 0.0,
                          0.7, 1.7, 0.6, 2.6, 2.2, 6.2, 0.0,
                          1.3, 1.2, 0.0, 0.0, 0.0, 3.2, 5.1,
                          0.1, 2.0, 0.0, 1.4, 0.0, 1.9, 6.3]
    add_heat_series("HeatPlot", "heat data", values, 7, 7, 0, 6, format='')
    

start_dearpygui()

DearPyGui Demo Jupyter Notebook

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

Intensity Graded FFT GUI

I initially had quite a bit of trouble getting past the demo graphs, as some of the documentation is quite sparse. I had to do a bit of hunting to find the exact options I wanted as well as using the API documentation for most things.

DearPyGui API Documentation

But I was able to perservere by adding one thing at a time. Thankfully some of the code I created for the intensity graded animation was able to translate to the GUI as the spectrum decay works exactly the same.

I was able to replicate the extent of the animation function just with the GUI instead. This allowed me to play a static RTLSDR capture, but I wanted to make the GUI have a few more functions. The first being that it would continuously capture samples off the RTLSDR and the user could dynamically change the center frequency and sampling rate as desired.

To do this I had to learn more about the GUI programming and how to trigger the callbacks. This ended up beign pretty simple as the button elements allow you to set the callback functions. The DearPyGui opperates using a naming system that requires the GUI elements to have unique names but makes referencing them similar to a dictionary reference.

The final GUI application is shown below. The main window shows the intensity graded FFT spectrum. The settings window allows the user to modify parameters concerning the RTLSDR and the spectrum plot.

I created a small video showing the different features that the user can use to investigate the RF spectrum with this GUI and an RTLSDR.

You can get the source code at my Github repo below and start to explore the RF spectrum in your area!

Pyhton Digital Phosphor Display Github Repo

Run the GUI with python, make sure to have Numpy and the python RTLSDR library installed along with DearPyGui.

python py_digital_phosphor.py

Conclusion

This GUI does not have the same flexibility or utility as GNURadio but it also only requires a handful of python libraries to run which could lower the barrier to entry for people getting started in SDR.

The intensity grading that I was able to produce does not have the same level of smoothing as the previous intensity graded fft plots with matplotlib. That is because that interpolation significantly increases the processing time per frame reducing the users ability to see the signals.

I hope to use this as a starting point for developing other GUIs for other SDR and signal and image processing applications.