Hacking, HAM Radio (EA1IYR), DSP, physics and more


SigDigger 0.2 - Using suscli

As the latest SigDigger 0.2 release included lots of new features that are difficult to summarize in GitHub’s release notes, I will write a series of posts about typical use cases for this features. It will not have a regular schedule (I am still writing down my master thesis, plus other duties far from my computer).

This first post will be dedicated to suscli, a command-line front-end for Suscan that does not depend on a graphical environment.

Introducing suscli

Suscli was born out of necessity during the C Band experiments in 4 GHz I perfomed last saturday, with the aim of receiving the synchrotron radiation of Cygnus A. The project has some increased difficulty as the synchrotron emission of Cygnus A is incoherent and therefore I can only rely on the amplitude of the signal. I needed an application that, departing from an already defined source profile, opened a channel and measured the root mean squared value (RMS) of the noise, which should proportional to the band-limited noise + additional contributions.

The result was suscli. suscli is a command line application with multiple subcommands that accept parameters in the form of key=value. You generally invoke suscli like this:

% suscli subcommand param1=value1 param2=value2 ...

The number of subcommands is not fixed and it is expected to grow in time. This post is simply a comprehensive description of each subcommand.

Listing profiles

One of the first things you may want to do is to list the available source profiles in your configuration directory. This is something you can do with suscli profiles:

% suscli profiles
(potential debug messages from SoapySDR drivers)
[  1] "Default source"
[  2] "C-Band experiments"
[  3] "HF with AirSpy"

Profiles are enumerated by order of creation and have a name. Suscli encloses the name with double quotes just in case a profile with an empty name exists. Other subcommands accept profiles as a parameter that can be either specified by an index number (as displayed by suscli profiles) or their name. This subcommand tells you which is which.

NB: there is a profile that is not listed as it is not in the sources.xml file in Suscan’s configuration directory. This is the UI profile (the one loaded by SigDigger at startup) and has always index 0. It is usually the default profile when no profile index is provided.

Examining profiles

Other interesting subcommand from the perspective of profile management is suscli profinfo, which prints a brief summary of a source profile. It accepts an optional parameter (profile) which expects a profile index or a profile name (both work).

Subcommands that interact with devices need to probe them at startup. Depending on the underlying SoapySDR driver, they may produce quite verbose debug messages that can be mixed with the true command’s output. Fortunately, most of these messages are printed to the standard error output, and can be suppressed with 2> /dev/null.

If no profile is specified, it defaults to 0 (the UI profile):

% suscli profinfo 2> /dev/null 
linux; GNU C++ version 6.2.0 20161103; Boost_106200; UHD_003.009.005-0-unknown

Profile:     "UI profile"
Frequency:   179100000 Hz
LNB:         0 Hz
Sample rate: 250000 sps
Decimation:  1
Type:        file
Format:      Automatic
Path:        /home/waldo/Documents/Radio/Examples/gmsk-250ksps.raw
Loop:        yes
% suscli profinfo profile=4 2> /dev/null
linux; GNU C++ version 6.2.0 20161103; Boost_106200; UHD_003.009.005-0-unknown

Profile:     "lime (Remote [TCP])"
Frequency:   433000000 Hz
LNB:         0 Hz
Sample rate: 100000 sps
Decimation:  1
Type:        real-time
Device:      lime (Remote [TCP])
Channel:     0
Bandwidth:   100000 Hz
Antenna:     (none)
I/Q Balance: no

Probing devices

And, if we want to know how many devices were deteced by Suscan and whether they are available or not for reading, we can use suscli devices:

% suscli devices 2> /dev/null
linux; GNU C++ version 6.2.0 20161103; Boost_106200; UHD_003.009.005-0-unknown

 ndx Device name                              Driver   Interface Availability 
[ 0] Dummy device                             null     local     available
[ 1] Audio input (hw:HDA Intel PCH,0)         audio    local     unavailable
[ 2] Audio input (default)                    audio    local     available
[ 3] lime (Remote [TCP])                      lime     local     available
[ 4] Audio input (hw:HDA Intel PCH,0)         audio    local     available
[ 5] airspy (AIRSPY [26a464dc:28621d93])      airspy   local     unavailable

Devices listed as unavailable are devices that were found in existing profiles, but may not be currently plugged to the computer.

Column Interface tells whether the device refers to some hardware device plugged to the host computer, or whether it is accessed remotely by a network interface. By default, only local devices are listed, but this behavior can be adjusted by setting environment variables. More on this below.

Automatically creating profiles from devices

Sometimes, suscli is installed in a headless computer to run as a device server. In these cases, we need to create profiles by hand for each device we want to expose. Most of this work can be done automatically by suscli makeprof, which creates default profiles from detected devices.

suscli makeprof accepts a variety of parameters:

Parameter Type Description Default
prefix String String prefix to prepend to profile names (Empty string)
device Integer Device index (as in suscli devices) -1
ask Boolean Ask before creating multiple profiles True
freq Double Profile frequency (in Hz) 433000000
unavailable Boolean Create profiles for unavailable devices too False

If no device index is provided, a profile will be created for all available devices (or, if unavailable is passed, for all devices regardless of their availability). It is in general a good idea to run suscli devices to be sure that all devices are plugged and properly detected before running suscli makeprof.

The created profiles (all in ~/.suscan/config/sources.xml) can be manually adjusted according to the user requirements with a simple text editor.

Listening to analog radio

The first truly useful subcommand is suscli radio, which allows you to listen to analog radio from the command line, exactly as you would do from SigDigger’s audio preview. The following parameters control the behavior of suscli radio:

Parameter Type Description Default
profile Integer / String Source profile index or name 0
demod String Audio demodulator (fm, am, lsb, usb) fm
volume Float Volume (in dB, 0 is 100%) 0
frequency Double Channel frequency (in Hz) Profile’s center frequency
samp_rate Integer Audio sample rate (in Hz) 44100
cutoff Float Audio low pass filter cut-off frequency (Hz) Half of audio sample rate
squelch Boolean Enable squelch False
squelch_level Float Squelch level (RMS, linear) 0.5
buffering_ms Integer Buffering audio (in milliseconds) 100

Upon successful execution, suscli radio starts demodulating audio to the default audio device and prints a brief summay of the current parameters:

% suscli radio frequency=97900000 volume=-10 2> /dev/null
linux; GNU C++ version 6.2.0 20161103; Boost_106200; UHD_003.009.005-0-unknown

Demodulator summary:
  Profile:       UI profile
  Device:        Dummy device
  Frequency:     97.900000 MHz
  Demodulator:   FM
  Cutoff:        22.050 kHz
  Squelch:       No
  Squelch level: 0.5
  Sample rate:   44100 sp/s
  Volume:        -10 dB

Additionally, the user can switch frequencies and demodulators interactively with the keyboard:

Measuring (band-limited) power

The original purpose for suscli was to perform power measurements (in arbitrary power units) and store them to a file or deliver them through the network. This is implemented by suscli rms.

As I progressed in my experiments, I discovered I needed to augment the power-measuring features of suscli to perform real-time power measurements without having to look continuously to a screen that could be meters away. That’s why it also features an audio output that beeps in different ways according to the measured signal power.

Regardless of the output type, suscli rms accepts the following parameters:

Parameter Type Description Default
profile Integer / String Source profile index or name 0
rms_interval Float RMS measurement interval (in milliseconds) 50
disp_interval Float Measure display interval (in milliseconds) 500
audio Boolean Enable beeper (audio output) False
tcp Boolean Forward TCP measures via TCP False
matlab Boolean Store measures to a Matlab’s .mat file False

What suscli rms actually calculates

In any case, suscli rms will run an analyzer on the specified source profile and open a channel centered in a frequency ($f_0$) that depends on the sample rate setting of the source ($f_s$) and the tuner (device) frequency $f_t$ as:


This is, the channel is opened on a center frequency that is 1/12 the sample rate below the device frequency (the one you configure in SigDigger’s frequency LCD display).

The channel bandwidth is chosen so that it does not overlap the DC component of the radio. As the maximum bandwidth of such channel (assuming that is $f_s/12$ Hz away from the DC) is $f_s/6$, I chose a slightly smaller bandwidth, $f_s/6.3$.

The resulting channel has much smaller sample rate, let’s say $f_s’\ll f_s$. This channel is then further filtered to match the exact bandwidth demanded by suscli rms. Then, it reads the source in batches of $N$ samples, where $N$ is derived from the RMS interval (in milliseconds) by:

\[N=10^{-3}\times f'_s\times\mathtt{rms\_interval}\]

And, for each sample batch, computes an approximation of the channel power by:


With $x^*[n]$ the complex conjugate of $x[n]$. Note that $x[n]x^*[n]=\lVert x[n]\rVert^2$. Since power is measured after every $N$ samples, a channel with a sample rate of $f’_s$ will produce power measurements at a rate of $f’_s/N$.

Displaying RMS measures periodically

In the simplest case, we just want to print RMS measures in the screen. We just run:

% suscli rms profile=0
linux; GNU C++ version 6.2.0 20161103; Boost_106200; UHD_003.009.005-0-unknown

(lots of debug messages from device libraries)

Tone generator parameter summary:
  Profile: UI profile
  RMS update interval: 50 ms
  Display interval: 500 ms
  Audio: OFF
Inspector opened!
  Inspector ID: 0x00000000
  Request ID:   0x000c1009
  Handle:       0x00000000
  EquivFS:      125000 sps
  Ft:            179100000 Hz
  BW:           79376.2 Hz
  LO:           -41666.7 Hz
[1626619312.732329] RMS = -92.458 dB

Data file case: storing measures in a Matlab file

If we want to store data to a file, we must specify mat5 in the parameter list. This parameter tells suscli rms to store all measurements (at the rate they are generated!) to a binary Matlab’s Mat5 file:

% suscli rms mat5

This Mat5 file can be loaded from Matlab or Octave and contains a series of arrays with the contents of the measurements:

% octave                            
GNU Octave, version 5.2.0
Copyright (C) 2020 John W. Eaton and others.
This is free software; see the source code for copying conditions.
FITNESS FOR A PARTICULAR PURPOSE.  For details, type 'warranty'.

Octave was configured for "x86_64-pc-linux-gnu".

Additional information about Octave is available at

Please contribute if you find this software useful.
For more information, visit

Read to learn how to submit bug reports.
For information about changes from previous versions, type 'news'.

octave:1> load('capture_20210718_145111.mat')
octave:2> whos
Variables in the current scope:

   Attr Name        Size                     Bytes  Class
   ==== ====        ====                     =====  ===== 
        X           4x98                      1568  single
        XT0         1x1                          4  single

Total is 393 elements using 1572 bytes

By default, suscli rms names capture files as capture_DATE_UTCTIME.mat, easing data classifiction. A scalar and a float matrix are generated. XT0 contains the Unix timestamp (in seconds) of the first measurement. X is a $4\times M$ matrix that contains data of the $M$ power measurements:

Graphical case: redirecting measures to RMSViewer

suscli rms can also forward measures via IP to certain consumer. This is done by specifying tcp in the parameter list. Additionally, you have to specify:

Parameter Type Description Default
tcp-host String Destination host localhost
tcp-port Integer Destination port 9999
tcp-desc String Optional description string suscli@client IP (PID)

Data is delivered in plain text to ease its exploitation by scripting languages. The TCP stream consists of message lines delimited by a regular line break (\n). Currently, only 3 messge types exist:

The most typical consumer is RMSViewer, a subtool of SigDigger that can be spawned with:

% SigDigger -t RMSViewer

RMSViewer is a basic graphical tool that opens a TCP server and expects connections by suscli rms. Once a connection is opened and data is received, measures are plotted in an interactive window in real time:

RMSViewer in action

The beeper feature

The beeper feature translates power measurements to different combinations of tones played in the default soundcard. This feature can be enbled by passing audio to the parameter list.

In any case, we need to known the dB range we want to map. We can do that experimentally by running suscli rms, reading the different measures and setting db_min and db_max accordingly. Less critically, we may want to adjust other parameters:

Parameter Type Description Default
mode String Beeper mode (tone, 2tones or beeper) tone
volume Float Tone volume, as a percentage 12.5
db_min Float Lower bound of the power range, in dB -70
db_max Float Upper bound of the power range, in dB -10
freq_min Float Lower bound of the audio freq. range, in Hz 220
freq_max Float Upper bound of the audio freq. range, in Hz 1760
beep_short Float Shortest tone duration in milliseconds 1000
beep_long Float Tone spacing in milliseconds 1000
scale Float Scale dB measures by a given factor 1

Currently, three tone configurations are accepted:

A typical beeper invocation would look like this:

% suscli rms audio db_min=-90 db_max=-80 mode=beeper profile=2 

Remote analyzers

Finally, the subcommand suscli devserv will spawn the device server, which is used by the remote analyzer feature. The device server publishes profiles in the network via multicast that can be later detected and used by SigDigger. When SigDigger uses one of these profiles, offloads all analysis features to the device server, enabling headless operation of SDR devices at a (generally) low data rate.

This feature is stil in experimental phase, many aspects of it are not complete (like proper protocol security) and can change in any later version. For that reason, automatic device discovery is disabled by default, although can be enabled from the command line by setting an environment variable. However, this feature deserves a post on its own, which I plan to publish soon.

Stay tuned!