Nothern Utah WebSDR Logo - A skep with a Yagi
Using "KA9Q-Radio"
as a multi-channel
monitor and logger for 2 meters


What this page is about

The ka9q-radio software - with reasonable computing power - can monitor hundreds of frequencies simultaneously, irrespective of frequency and mode:  All that is required is that your front end device is capable of covering the frequencies of interest - and your computer having enough processing power helps too!

Also included with ka9q-radio is the ability to record multicast streams to .wav files and what this means is that whatever you are monitoring could, if you so-choose, be recorded automatically.

What is described on this page not only allows one to monitor every 2 meter FM channel simultaneously, but also record and log those channels - this using a modestly powerful Intel i5, 8 core processor, an $120 SDRPlay RSP1a, and ka9q-radio.


This document represents an effort on
my part to understand the operation of "ka9q-radio" and is not intended to be authoritative.

As such, this is a work in progress and will certainly contain many "blank spots" and errors.  What it is intended to do is to help the new user along and start to get the "feel" of how the pieces go together.

Please read EVERY document in the /docs directory of the "ka9q-radio" git - and refer back when you see something you don't understand!

For more information about ka9q-radio, go here:

Using KA9Q-Radio - link

This page has much more information about the internal workings of ka9q-radio and other examples of its use.

First, what is "KA9Q-Radio" - and why is it different from other SDR programs/suites?

One of the advantages of SDRs is the capability of receiving multiple signals at the same time - but this is typically exploited only in a limited fashion.  The limit of this capability is a combination of both the bandwidth of the acquisition device (e.g. how much spectrum the device is inhaling) and also the processing capability of the host computer.  Usually it's the latter point that has limited the usefulness/capability of many wide-bandwidth SDRs:  It is typical for each "instance" of a receiver used by a user to have to process data from the high-bandwidth acquisition stream - which may be several megasamples.  Because each per-user instance requires so much processing, this can make a multi-user receiver system "un-scalable" - that is, each user requires a significant amount of CPU processing.

In 2006, an article was published  1  that described what might be considered to be a mathematical "shortcut" when it comes to processing large amounts of data.  Without going into detail, the "traditional" method for producing a single virtual receivers is to crunch the full bandwidth data to yield - at least in an amateur radio application - only a narrow bandwidth - perhaps a few kHz for an SSB or FM signal or even a few 10s of kHz for a waterfall - and if multiple receivers are required, it's necessary to "re-crunch" the large amount of raw input data for each, individual receiver even through that mathematical operation for each receiver is expensive in CPU time and nearly identical.   A far more efficient method - potentially one that is many hundreds of times more efficient, depending on how much "economy of scale" was done - would be to do the "expensive" number crunching just once and then use that already-processed data to synthesize each, individual receiver - and it is this method, generally referred to "Overlap and Save" - that is used by KA9Q-Radio.

As an example of the "former" method:  If the "csdr"  2  utility is used on, say, an RTL-SDR with 2 MHz of bandwidth, a Raspberry Pi4 is capable of only handling 4-8 simultaneous receivers before all available CPU cycles are used:  This is one of the reasons why the open-source "OpenWebRX" server isn't particularly salable to a large number (e.g. dozens) of users.  Conversely, the PA3FWM WebSDR server (which is closed source) likely (unconfirmed!) uses same the techniques as KA9Q-Radio - which are noted in Footnote #1 -to allow hundreds of users on the same hardware platform as an OpenWebRX server that may be only to handle a half-dozen or so.

Using the aforementioned "Overlap and Save" method in reference #1, a Raspberry Pi4 running ka9q-radio can simultaneously decode every FM channel in the same 2 MHz bandwidth
simultaneously with plenty of processing power to spare!

KA9Q-radio is open-source and it may be found here: - and the instructions for compiling it along with a list of dependencies may be found here:

Installing ka9q-radio

Information about the installation of ka9q-radio may be found on the page:  ka9q_radio_installation

Using ka9q-radio with the SDRPlay RSP1a

This page assumes the use of an SDRPlay RSP1a and for information about how that is installed and used, see the Using "KA9Q-Radio" with the SDRPlay RSP1a page.

You are not limited to using the RSP1a, however - this may also be done with the following hardware:
Additionally, some Airspy and Funcube SDR hardware is also supported by ka9q-radio.

Configuring the radio hardware

In this example we will be using the SDRPlay RSP1a.  This hardware is relatively inexpensive - around US$120 at the time of writing - and it has several advantages over the cheaper RTL-SDR dongle:

Let us consider a file called "sdrplayd.conf", reproduced below in its entirety:

description = RSP1a
serial = 2255031F98
samprate = 5000000
lna-state = 1
#if-agc = yes
if-att = 50
iface = lo               ; default loopback interface, avoid wifi don't go on the LAN
status = rsp1a-status.local
data = rsp1a-pcm.local
rf-notch = 1        ; enable FM BCB notch
am-notch = 1        ; enable AM BCB notch
dab-notch = 1;        ; enable DAB notch (160-230 MHz) - because we can
frequency = 145997000       ; locks tuner when manually set

Taking a line at a time:
The above is all that we need to configure our RSP1a to cover all of 2 meters, so we are ready to invoke "sdrplayd" to interface with it and "make data" as follows:

sdrplayd -f <config _file> <configuration>


./sdrplayd -f sdrplayd.conf rsp1a_test &

Looking at this line:

If you get an error:

Pay close attention to the errors that you might get.  Typical causes of errors are:

Once sdrplayd is running:

With sdrplayd running, we need to set up our receivers which are invoked using "radiod" along with a configuration.  "radiod" is the heart of ka9q-radio as it does the work of processing the massive amount of data coming in from our receiver hardware.  Even on a modest processor it is capable of simultaneously demodulated hundreds of individual receive channels in a mix of frequencies, bandwidths, sample rates and modes.

As with the receive hardware itself, a configuration file is used to set things up and here we will use "sdrplay.conf".  (Notice that this is named "sdrplay.conf" not "sdrplayd.conf").

Consider the following:

./radiod radiod@2meters.conf &

The above will invoke "radiod" using a configuration file called "radio@2meters.conf" and if we peer into this we'll see which frequencies are configured - and the various receive mode.  Multiple definitions of receive frequencies and modes may be included in various named sections.  For more detailed information, see:

Our example "radiod@2meters.conf" file:

Our "radiod@2meters.conf" file used by "radiod" is used to define the virtual receiver(s) that we might want.  Let's take a look at a minimum configuration:

The first - and required - section is the "global" section which contains the following:

input = rsp1a-status.local
status = 2m.local

Breaking this down:

This represents the minimal configuration in the [global] section of the "radiod" configuration file, using defaults values for blocktime, overlap, etc. (see the discussion about "radiod" on other pages.)

Let's take a look at the sub-sections located after the [global] section:

[2m RPT output]
mode = pm
data = fmrpt_out-pcm.local
freq = "145m190 145m210 145m230 145m250 145m270 145m290 145m310 145m330 145m350 \
145m370 145m390 145m410 145m430 145m450 145m470 145m490 \
146m620 146m640 146m660 146m680 146m700 146m720 146m740 146m760 146m780 \
146m800 146m820 146m840 146m860 146m880 146m900 146m920 146m940 146m960 146m980 \
147m000 147m020 147m040 147m060 147m080 147m100 147m120 147m140 147m160 \
147m180 147m200 147m220 147m240 147m260 147m280 147m300 147m320 147m340 \
147m360 147m380"

[2m RPT input]
disable = yes
mode = pm
data = fmrpt_in-pcm.local
freq = "144m590 144m610 144m630 144m650 145m670 145m690 145m710 145m730 145m750 \
145m770 145m790 145m810 145m830 145m850 145m870 145m890 \
146m020 146m040 146m060 146m080 146m100 146m120 146m140 146m160 146m180 \
146m200 146m220 146m240 146m260 146m280 146m300 146m320 146m340 146m360 146m380 146m400 \
147m600 147m620 147m640 147m660 147m680 147m700 147m720 147m740 147m760 \
147m780 147m800 147m820 147m840 147m860 147m880 147m900 147m920 147m940 \
147m960 147m980"

Here we have two sections that define a number of frequencies.  In the top section called [2m RPT output] we define the output frequency of every 2 meter repeater pair.  We can also see from the line "mode = pm" we are using the FM demodulator with audio de-emphasis (which is the amateur standard worldwide).  Finally, we see the line "data = fmrpt_out-pcm.local" where this defines the multicast address of the stream that will convey the audio of all of these channels.

In the bottom section - [2m RPT input] - we have a similar listing - this time with the corresponding repeater input frequencies.  In this case we have included the line "disable = yes" to disable every receiver in the [2m RPT input] group as an example as to how to disable entire sections.

Note that in the above, long lines are broken up using the backslash "\" character to make one line - all frequencies being contained in quotes.  Alternately, multiple "frequency" lines could be used, noting that the valid prefixes are "freq", "freq0" (with a zero), freq1, freq2 and so on through freq9.  You can use only one  of these eleven "freq" prefixes in each section.

The above does not include other frequencies of interest, such as those used for simplex operation - but these may be included with additional sections.  Be wary of including frequencies on which packet operation occurs (e.g. APRS, those around 145.01 MHz) unless you really want to listen to (and record) such activity.


I live in an area with 20 kHz channel spacing on 2 meters so the frequencies listed above reflect what is in use.  The above lists should be modified to reflect the frequency use in your area.

A word about ssrc and frequency descriptions:

The "ssrc" (Stream Source Identifier) value - which is used to identify a component of a multicast stream containing pcm data - is automatically derived from the frequency value by removing everything but the digits - but its exact representation will depend on how you defined the frequency in the relevant radiod ".conf" file.

For example, here are some sample frequency descriptions - all for the same frequency of 14.234 MHz - but with DIFFERENT ssrc values:
As you can see, it is imperative that your frequency definitions are consistent.

There are some "gotcha's", however.  Let's presume that you have defined several frequencies with exact kHz boundaries - perhaps a repeater output - but then you find out that there's a repeater running 2.5 kHz deviation on 145.1375 MHz.  Previously, you may have defined frequencies like 146.520 MHz (the U.S. national simplex frequency) as "146m520" which results in an SSRC of "146520". which has six digits.  The possible issue arises when you define the frequency of 145.1375 MHz as "145m1375" which has an SSRC of "1451375" which is seven digits.

The to most obvious options are:

"fftwf_export_wisdom_to_filename" errors when starting radiod

If you see the errors "fftwf_export_wisdom_to_filename" produced by "radiod" when it is starting, that does not mean that it won't work properly, but it likely will not be as CPU-efficient as it could be as the FFT "wisdom" needed to optimize operation of the algorithm is missing.  To help resolve this - and potentially reduce CPU utilization - do the following:  sudo chown <username> /var/lib/ka9q-radio/wisdom - substituting for <username> the name of the user under which you are running ka9q-radio.

Getting audio output (to speakers):

Being able to "hear" the demodulated audio is a quick and easy way to verify that everything is working - even if this isn't likely to be the main purpose to which ka9q-radio would be put.  At this point it is recommended that you place a .wav file on your test system and then use "aplay" to test the speaker:  If your filename were "music.wav", simply do:  play music.wav and if all goes well, you should hear it play:  If not, read the next section, below.

Having verified via "top" or "htop" that sdrplayd and radiod are running, you can test it via a local speaker if you like but note that unless you need an analog audio output of some sort, it is not even necessary to have any audio playback devices on your system - but it's a nice tool to have.  If your computer has a sound card, connect a speaker to it and do the following:  "aplay -l":  You should see a list of available devices such as the following:

**** List of PLAYBACK Hardware Devices ****
card 0: PCH [HDA Intel PCH], device 0: ALC662 rev3 Analog [ALC662 rev3 Analog]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

You may see other devices, particularly if you have an HDMI or similar monitor that can convey audio - but the above is typical of an analog audio output device on a motherboard.

What to do if you see "No audio device" when you try to play your local audio file (e.g. "music.wav")

If you do not see any available sound cards - but you know that one is present (a plug-in card, on the motherboard), it may be that you have been the victim of a quirk recent versions of Linux (e.g. Ubuntu 22.04) where parts of the the sound system seem to "go away" at random - likely after a reboot/update.  To repair this, try the procedure at the very top of this page: to re-load/restart the audio devices once again.

If you get an error like "play WARN alsa: can't encode 0-bit Unknown or not applicable"

This is a vexing problem to many trying to use their sound cards on recent version of Ubuntu and it seems to be related to pulseaudio and/or pipewire.  If you get this error - and audio does not play, try disabling pulseaudio:
systemctl --user stop pulseaudio.socket
systemctl --user stop pulseaudio.service
After doing the above, try playing the audio file again:  It may work now, even if you still get the "can't encode 0-bit Unknown" error.

If you get an error related to pipewire and a report that no device is available - despite "aplay -l" showing devices, you may need to uninstall pipewire.  This is done using the following commands:
systemctl --user unmask pulseaudio
systemctl --user --now disable pipewire-media-session.service
systemctl --user --now disable pipewire pipewire-pulse
systemctl --user --now enable pulseaudio.service pulseaudio.socket
sudo apt remove pipewire-audio-client-libraries pipewire

Once you have a working audio path

Once you have verified that an audio device is present and will play the audio file that you have put on the computer, consider the following command:


This will play - to local speakers the audio of every active frequency using the multicast address of "fmrpt_out-pcm.local".  In the example above, these are all of the frequencies in the section beginning with [2m RPT output].

We know from the output to screen when "radiod" started and from the contents of "radiod@sdrplay.conf" from the "[2m RPT output] section that the name of the stream is "fmrpt_out-pcm.local"  represent the multicast for the 2 meter receivers (plural!) and upon this invocation we will see a screen like this:

KA9Q Multicast Audio Monitor: fmrpt_out-pcm.local
                                                                 ------- Activity -------- Play
  dB Pan     SSRC  Tone Notch ID                                 Total   Current      Idle Queue
  +0   0   147120             K7JL Farnworth Peak (SLC)            899       899             121
  +0 -25   147260             AC7O Promontory Pk. (Ogden)          254       254      1:46     0
  +0  25   147180             K7JL Hidden Peak (Alta)              849       849        47     0
  +0 -38   146620             W7SP Farnsworth Peak (SLC)            91        91      2:08     0
  +0  13   147040             K7DAV Antelope Island (Farming         0         0     53:54     0
  +0 -13   147300             N7DAV (North Salt Lake)               22        22      3:18     0
  +0  38   146840             N7PCE Jordan Valley Hosp. (Wes        45        45      7:38     0
  +0 -44   146880             KD0J Salt Lake Comm. College (         3         3     44:10     0
  +0   6   145490             K7JL Promontory Point (Ogden)         15        15     29:57     0
  +0 -19   146980             W7EO Delle Peak (Tooele)              10        10      3:34     0
  +0  31   145390                                                   23        23             103
  +0 -31   145450             WB7TSQ Butterfield Peak (SLC)         11        11     25:58     0
  +0  19   146900             KE7EGG (Ogden)                        12        12   1:13:41     0
  +0  -6   146700             KC7IIB Ensign Peak (SLC)               5         5     22:24     0
  +0  44   145290             K7UB Brigham City                      0         0     22:27     0
  +0 -47   146760             W7SP Lake Mountain (Orem)             23        23      8:18     0
  +0   3   146780             K7UVA Lake Mountain (Orem)            22        22      1:37     0
  +0 -22   145370                                                    1         1      2:35     0
  +0  28   147340             K7UCS West Mountain (Payson)          19        19      1:28     0
  +0 -34   147220             K7UB Riverside (Tremonton)            32        32        58     0
  +0  16   147280             K7UCS Lake Mountain (Provo)           20        20      1:26     0
  +0  -9   145430             K7UB (ATK)                             7         7      1:03     0

The columns, in order:


If all goes right, you should hear audio from the speaker from EVERY frequency that is active.  In other words, if there are a dozen different repeaters active and being received, you will hear a dozen different audio sources.  Fortunately, you can control chaos so from within the monitor program, press the "h" key to get a list of options - the most relevant for the current discussion shown below:
In other words, you can move up/down between receivers to select that on which the controls (keys) will operate.

When you first do this, it's recommended that you hit the "M" key (uppercase) to mute ALL receivers - and then use the up/down arrow to select which one(s) you wish to hear and then hit the "u" (lowercase) key to unmute that receiver.  You can then use the plus and minus keys to adjust the volume, left/right arrows to pan (move between speakers), etc.

To exit monitor hit "CTRL-C".

The "id.txt" file

Note:  Unlike other configuration files, this resides in the same directory from which "radiod" is called.

This file contains a list of frequencies or more precisely, a list of SSRC values with an accompanying description in the format on each line - and this is how we populate the ID column seen in the display produced by the monitor program, above. 

# <your comment here>
<ssrc>   <description>

The format couldn't be simpler!  
  Comment lines begin with a hash (#).

The possible "gotcha" is the ssrc values.  As noted above, it helps to be consistent!

Antenna/signal level considerations

As with any receiver, the gain must be set properly and when you have a wideband device that is inhaling a fairly large chunk of spectrum, this is even more important as it is not just one signal that could overload the receiver, causing distortion and intermodulation products but the total signal power of ALL signals that fall with the passband of the receiver.

In our example of sdrplayd.conf above we set the bandwidth to 5 Msps - which will automatically cause the selection of the 5 MHz filter in the SDRPlay which means that all signals +/- 2.5 MHz from the center frequency will reach the analog-to-digital converter.  

For example, consider the settings of lna-state and if-att in the sdrplayd.conf file we discussed earlier:
Here are a few considerations when setting gain and lna parameters:

Determining/monitoring signal levels

The control program - while primarily intended to allow adjustment of the virtual receivers in terms frequency, bandwidth, mode, gain, bandwidth, etc. it also provides useful data about the signal level applied to the A/D converter and may be used to determine the appropriate gain in the antenna signal path to prevent/minimize overload.

This program may be invoked as follows:

control <pcm multicast name> -s <ssrc>

As in:

control 2m.local -s 146620

When invoking this program you can select any ssrc that exists within the .conf file to see the statistics of the A/D converter even if that frequency is not active - but if that frequency is active, you'll see information specific to it.

Take this screen shot as an example:

control - 146620 example

Near the top and center there is a column labeled RSP1a (this is the "name" field in sdrplayd.conf) and below it the gain is shown as being 50 dB, which is also our if-att selection as well.  The line below this - "A/D  -6.3 dBFS" - tells us that our A/D converter is a bit more than 6 dB below full scale and is likely to be experiencing occasional overloads.

A bit below this is the line "Input  -59.1 dB" which actually refers to the amount of signal our virtual receiver is seeing from the in-frequency signal.  It is possible - if AGC is disabled and the RF signal path parameters affecting the level ("lna-stata" and "if-att" in the case of the "sdrplayd.conf" file) to correlate this value with the absolute power level of that signal in dBm.

For more information about the control program see the page
ka9q-radio command overviewlink.

Making recordings automatically

With multiple receiver operating concurrently it is possible to make recordings (logs) of everything that is received using the pcmrecord utility.

Consider the following command line:

./pcmrecord -v -s -m 0.25 -t 20 -d ~/recordings/2m fmrpt_out-pcm.local &

Breaking it down:
What will happen

Whenever a signal appears on one of the frequencies belonging to the multicast data stream, a recording will be created.  This file will be written in the ~/recordings/2m/<ssrc> directory with the filename with the ssrc and time in UTC embedded in the form of <ssrc>k<yyyy>-<mm>-<dd>-<hh>T<mm>:<ss.s>Z.wav

For example, if a receiver monitoring 146.620 MHz detects a signal at 0045:39.5 UTC on June 18, 2023, the resulting file would be:  ~/recordings/2m/146620/146620k2023-06-18T00:45:39.5Z.wav

This file will be a 1 channel, 16 bit, 12 ksps .wav file.


It is entirely up to the user to devise a means by which the number of .wav recordings is limited as pcmrecord will continue until your drive space is full.  As such it is recommended that recordings be placed on a different device than the operating system to prevent the system from crashing should its drive space be consumed.


By putting together several pieces in ka9q-radio it is possible to not only monitor multiple frequencies at the same time.  Additionally, a recorded (audio) log of all of these frequencies can be automatically made.  If desired, it is possible to configure a system where every FM channel on one or more band is recorded and logged when there is activity.

I'll leave it up to you to figure out why you might want to do this.

For more information about ka9q-radio, go here:

Using KA9Q-Radio - link

This page has much more information about the internal workings of ka9q-radio and other examples of its use.


Additional information:
 Back to the Northern Utah WebSDR landing page