Northern
Utah WebSDR Receiving on multiple bands with the SDRPlay RSP1a and "csdr" and stream splitting
Preliminary Version
What is this?
There may be instances where it is desirable to recieve on multiple
bands at once using a single SDR receiver - and what is described here
is a fairly simple way to accomplish this.
For this example, we will be using an SDRPlay RSP1a and HA7ILM's "csdr" software (See: https://github.com/ha7ilm/csdr ) .
Also, we will be using a modified version of the "sdrplayalsa"
utility developed by the Northern Utah WebSDR folks that has been
tweaked to allow any
arbitrary sample rate. If you are interested in any bit of
software feel free to make contact using the information found at the
bottom of this page. We will also use the "fplay" utility - a
version of "aplay" modified to remove sample rate restrictions - and we
will also use "fastloop", another modified Linux utility.
See
the bottom of this page for links referring to "sdrplayalsa", "fplay",
"fastloop" and configuration for duplicated audio streams.
PLEASE NOTE: This technique may be used for any receiver from which the raw I/Q stream is available in STDOUT and is not limited to just SDRPlay devices!
Example - Receiving both 80 and 60 meters using one receiver:
Let us suppose that we wish to receive both the 80 and 60 meter band on
the same receiver. The useful frequencies on these bands are
3500-4000 kHz for 80 meters and 5200-5500 kHz for 60 - the precise
frequencies are unimportant. To make this work, we need to pick a
frequency that is approximately midway
between these two bands, so a nice, even frequency of 4500 kHz was used
as this is (4500-3500)= 1 MHz above the bottom of 80 meters.
Similarly, if we presume 5500 kHz to be comfortably above all of
the 60 meter frequencies, being (5500-4500)= 1 MHz above the center
frequency.
Sample rate and filter selection:
Normally, we would pick a sample rate that would comfortably cover both
frequency ranges. According to the SDRPlay RSP1a data, the lowest
sample rate allowed is 2 MSP. For reasons of CPU utilization in the decimation process we
should pick a sample frequency that is an integer multiple of our sample rate
- and for this, let's pick the highest rate that an unmodified ALSA
kernel on modern Ubuntu can support - 768 kHz - which means that we
could use 2304 kHz, which is exactly three times our output sample rate.
Except that we can't!
Looking at the RSP specifications, we see that we have several choices
of filters built into the hardware - namely 200, 300, 600, 1536,
5000, 6000, 7000 and 8000 kHz.
Because the bottom of 80 meters and top of 60 meters are about 2
MHz apart, we can't use the 1536 kHz filter as that would cut off too much of the desired frequency range.
Conversely, if we pick the the next-wider filter, 5000
kHz, we will be too
wide for a 2304 kHz sample rate and we'll end up with aliasing/images across our receive bandwidth (e.g. signals where they shouldn't be!)
which means that we must set our sample rate higher than that of the
filter bandwidth so that we can remove these unwanted signals via software
filtering.
What this means is that we will pick a sample rate higher than 5000 kHz, so we'll use (768 * 7) = 5376
kHz - which is exactly 7 times the 768 sample rate that we ultimately
need: This will put the image/aliases comfortably outside our
hardware bandwidth so that we can remove them in software later on.
Converting to 80 meters:
We now know that we can tune our receiver to 4500 kHz, select a
hardware filter bandwidth to 5000 kHz and a sample rate of 5376 kHz -
covering approximately 2000-7000 kHz, wholly including the 80 and 60
meter bands.
For this, we'll use "sdrplayalsa" which can output the raw I/Q samples
from the RSP1a and SDRPlay's API
to STDOUT which we can then pipe to "csdr" for frequency conversion and
decimation/filtering - again, any software that will output raw I/Q
data from an SDR to STDOUT will work. The "csdr" utility can be
used with a number of data formats from floating point to signed or
unsigned 8, 16 and 24 bit sources making it usable with a wide variety
of data sources.
Consider the following line which yields 80
meters, a bandwidth of about 768 kHz, centered at 3700 kHz:
./sdrplayalsa/sdrplayalsa -i 1897 -r 5376000 -f 4500000 -B 5000 -g 30 -l 2 -q -R 0 - This invokes a receiver - using "sdrplayalsa" - with a serial number ending with "1897" (useful if there are several receivers on a system) and selects a sample rate of 5376 kHz (-r 5376000) which is tuned to 4500 kHz (-f 4500000) with a 5000 kHz wide filter (-B 5000). Additionaly, the "gain reduction" is set to 30 (-g 30) and the "lnastate" is set to 2 (-l 2).
The "-q" parameter was added, allowing arbitrary sample rates to
be selected rather than just those acceptable to ALSA and the WebSDR
software (e.g. 24000, 48000, 96000, 192000, 384000 and 768000).
The "-R" parameter sets the decimation exponent within the RSP
driver - and selecting an exponent of 0 means that the decimation value
is 1, which means that the RSP's actual sample rate is the same as what we selected - 5376 kHz. (Comment: When a value of 768 kHz is selected, a decimation value of 4 is used by the SDRPlay API and the actual sample rate from the RSP device is 3072 kHz, being reduced to 768 by the API.)
csdr convert_s16_f - This portion converts the signed 16 bit raw I/Q data to floating point, which is what csdr needs.
csdr shift_addition_cc 0.148809523
- This does a frequency conversion as follows based on the fact that
our receiver hardware is tuned to 4500 kHz and our sample rate is 5376
kHz
Using the forumla (rx_center_frequency - desired_center_frequency)/sample rate we calculate the conversion factor as: (4500 - 3700) / 5376 = 0.148809523
This will yield an I/Q output with 3700 kHz now being at the center.
csdr fir_decimate_cc 7 0.1 HAMMING
- This decimates the 5376 kHz I/Q stream by 7 to 768 kHz - which is
what we need. Prior to the down-sampling/decimation, the input
stream is filtered - and the (optional) parameter that follows the
decimation rate can specify how steep this filtering could be. In
this case, we chose a value of of 0.1 (and a HAMMING window - which specifies a type of filtering)
which is some rather relaxed filtering compared to the default - but
this reduces the CPU loading: By choosing this value carefully
you can reduce CPU utilization and still provide enough filtering to
keep images/alaises out of the amateur band - but permit them to exist
beyond the edges. If you have CPU capacity to burn, you can leave
this parameter off - or specify even "stronger" filtering (e.g. a smaller number.)
Comment: It has been noted several times that the decimation is best done using integer factors, but csdr does have a different decimator that can operate on a fractional basis "fractional_decimator_ff". This decimation takes more CPU horsepower and may
result in more artifacts, depending on the configuration. If the
trade-off of using this decimator is worth it this reduces the
restrictions of available sample rates in that integer-multiples of the
post-decimation rate may be used.
csdr convert_f_s16 - This converts the floating point back to 16 bit signed raw I/Q data.
./fplay -c 2 -D plug:rx_ch1 -r 768000 -f s16_le --disable-softvol -B 40000 &
- This invokes the "fplay" utility to take the STDOUT stream and put it
into a virtual ALSA device called "rx_ch1" with 40000 usec (40 milliseconds)
of added buffering. It is the "other end" of this virtual device
that the WebSDR uses as its source of 80 meter I/Q signal data.
The "&" at the end allows it to run in the background.
Converting to 60 meters:
The following line will take our raw I/Q samples and convert to a center frequency of 5300 kHz:
Looking carefully you'll noticed that the only difference is this statement: csdr shift_addition_cc -0.148809523 which is now negative to yield a center frequency of 5300 using the same formula as above:
(4500 - 5300) / 5376 = -0.148809523
Instead of converting down in frequency, we are converting up
by the same proportion as the center frequency of 5300 kHz is the same
distance from our receiver center frequency of 4500 as the 3700 kHz
center frequency of our 80 meter receiver, hence the difference being
the sign. Everything else is the same.
Receiving two bands at once:
Above we showed how to produce 80 meters and 60 meters - but not at the
same time - but you probably noticed that the center frequency of the
receiver (4500 kHz) and the sample rate (5376 kHz) was the same for both examples. This was purposely done as we could use the same raw I/Q output from our receiver to yield both bands by splitting the STDOUT stream. Fortunately, there is a utility called "pee" (yes, the name is intentional!) that
is designed to take a stream like this and split it into as many instances
as you like. This utility is not native to Linux, but is
contained in the "moreutils" package that may be installed (e.g. "sudo apt install moreutils").
With "moreutils" installed, you can invoke it as follows to spawn two
separate conversions - one to 80 and the other to 60 meters - as
follows:
Note also that immediately after the "sdrplayalsa" portion, we have moved the statement "csdr convert_s16_f"
- which converts the raw samples to floating point - so that is followed by the use of the "pee" utility: Because we need
floating point for all instances of csdr, we can convert the STDOUT
stream to floating point first and thensplit
the stream - which now conveys floating point - with "pee", saving a
reasonable amount of CPU power by
having only one instance where we convert from S16 to float.
Following the "pee" utility, you can see the two separate csdr
and fplay instances, each one contained within single quotes ( ' ).
Finally, looking carefully and you'll also notice that for the first invocation which gives us 80 meters (with the "csdr shift_addition_cc 0.148809523" statement) the "fplay" is output to a device called "rx_ch0" while the second invocation (with the "csdr shift_addition_cc 0.148809523" statement) which gives us 60 meters goes to a different device called "rx_ch1".
CPU Utilization:
While this is purely subjective, knowing the relative CPU utilization
of the various aspects of the signal processing can give a general idea
as to how much CPU "power" each tasks take. The system in
question is an Intel i7-7700 (3.6 GHz) with eight cores. The
values below are from "htop" which can be somewhat inscrutible in terms
of how things are calculated as the total may span multiple cores and
the percentages may exceed 100%, but they are useful in the sense of
relative usage.
Examples of relative utilization:
SDRPlay API service - 165% (six RSP receivers)
websdr - 75% (7 receivers, six running at 768 kHz BW, one at 384 kHz)
csdr shift_addition_cc - 28% (This does the frequency conversion/shift within the 5376 kSPS stream)
csdr fir_decimate_cc - 25% (This decimates from 5376 kSPS to 768 kHz)
csdr convert_s16_f - 25% (This converts from signed 16 bit to floating point - which is why we wish to do this just once!)
sdrplayalsa - 22% (one for each receiver)
fplay - 14% (takes the 768 kHz output and puts it into ALSA)
csdr convert_f_s16 - 6% (This converts the floating point back to signed 16 bit)
Comments and warnings:
Because a single receiver is used for both bands, you are
obviously relying on one source for the raw I/Q data for these same
bands meaning that you have a single point of failure for all of the bands being sourced by it. Also, if
you wish to reconfigure one of the two bands in terms of frequency,
you'll have to interrupt both bands to do it.
If you use AGC, it will affect both bands. As noted in
the article about using the "sdrplayalsa" utility (see the link below), it is capable of
producing a text file with the current AGC value - but it can produce
only one value for one band meaning that unless you have a means of replicating the file for both covered bands (perhaps an alias) you'll have an AGC value for just one band.
Because the bandwidth is much wider to cover both bands (5000 kHz) than it would be if you needed to cover just one band (where one might set the bandwidth at 600 kHz for a 768 kHz wide receiver) this means that the A/D converter will intercept nearly 10 times as much signal energy, making overload more likely by any signal within the 5 MHz input filter range - even those that are not within the 80 or 60 meter bands.
The probablity of overload can be reduced if you have a
filter that is designed to pass just the range of 3.5-5.5 MHz rather
than the 5 MHz swath centered at 4500 kHz (e.g. 2000-7000 kHz)
The RSP1a will operate with 14 bits up to only 6.048 MHz: Keep this in mind if you wish to cover more bandwidth.
If you determine that 12 bits is suitable, you can
operate with a 6912 kHz sample rate - which is 9 times 768 kHz - but be
aware that CPU load increases with the sample rate.
If you were to use a 6912 kHz sample rate with 12 bits
of resolution, you could select the 7000 kHz wide filter to prevent
aliasing. With this configuration you could cover 160, 80, 60 and
40 meters with one RSP device, with the center frequency likely being
somewhere around 4.55 MHz and four instances of "csdr" and "fplay"
using the "pee" utility as described above.
If you were to do this, best results would be obtained with as good RF filtering on the antenna port as you could muster.
Each conversion using the "csdr" utility takes a significant
percentage of CPU bandwidth: Make sure that you don't go
overboard with the number of such conversions. As noted above,
you can adjust the value of the parameter in the "csdr fir_decimate_cc"
statement to reduce CPU utilization at the expense of anti-alias
filtering - but if you do this, you should check the spurious response
on each of the bands with a signal generator to determine if the
filtering is adequate.
IMPORTANT: There is a hardware quirk in the RSP1a that can cause harmonic response. For example, in the above example, FT-8 signals on 20 meters can appear around 3926 kHz on 80 meters.
The cause of this is as follows:
The local oscillator frequency is 4500 kHz.
The third harmonic of 4500 kHz is 13500 kHz
The 20 meter FT-8 frequency is 14074 kHz, which is 574 kHz above 13500 kHz
The spectrally-inverted images on 80 meters at 3926 are 574 kHz below 4500 kHz
While the RSP1a has filtering in it (e.g. when tuned to 4500 kHz, the "2-12 MHz" filter is selected) this filtering isn't very sharp at all and doesn't reduce 14 MHz energy that much.
The "fix" for this would be to add filtering, which could be:
A low-pass filter to cut off above 5.5 MHz. This is the simplest approach and it would remove this spurious response.
A band-pass filter to pass just the desired bands - from 3.5-5.5 MHz.
A special "window" filter that passed 3.5-4.0 and 5.2-5.5 MHz. This would require a custom design (you can email me if interested a diagram - but I won't build one for you!) and it would do the best job of keeping signals other than those desired out of the receiver.
With the same 5376 kHz sample rate, other configurations are
possible with appropriate selection of the center frequency and
appropriate RF filtering at the antenna, such as:
Coverage of 160, 80 and 60 meters with a single receiver device.
Coverage of many adjacent "band pairs", including: 160/80, 60/40, 40/30, 30/20, 20/17, 17/15, 15/12, and 12/10.
Coverage of most or all of 10 meters using several "chunks".
While the "output" of the above examples yield 768 kHz of bandwidth, coverage of smaller portions (say, 8-96 kHz) of various bands for various tasks, including CW skimmer, logging of FT-8, WSPR, propagation is also possible.
Remember:
Coverage of more spectrum with a single receiver not only
increases CPU utilization significantly, but increases the total amount
of signal being input to the A/D converter (due to the wider bandwidth) which can lead to signal overload. As one does this, RF filtering at the antenna input
becomes increasingly important to maintain good receiver performance -
particularly on the higher bands as solar activity increases.
Conclusion:
The fairly-high
sample rate of an inexpensive receiver such as the RSP1a can be easily
used to provide multiple receivers. In the example above, a
"several MHz sample rate" is used to produce two 768 kHz streams to
cover the 80 and 60 meter bands in their entirety - or even other band
combinations. If this is done, CPU utilization naturally
increases as does the likelihood of receiver overload as more total
signal power impinges on the A/D converter.
With the above in mind, it is possible to leverage receiver hardware to
allow multiple "virtual" receivers to provide a wide variety of signal
sources for WebSDRs or other applications.
Links:
You can find out more about many of the utilities mentioned above on this page: http://www.sdrutah.org/info/rx_equipment.html - Specifically, look at the bottom half for details on these topics.
Configuring high-rate audio loopback devices - One of the features of Linux is the ability to configure virtual sound cards. Doing so adds flexibility when sending audio (including raw I/Q streams from the receiver)
from a particular device driver into another program, whether it be a
WebSDR server and/or another application that might use this same
receive stream. This page describes one way of setting up such
loopback devices, and how to build a patched version of the loopback
module that is capable of operating up through at least 768 kHz.
Creating "fplay", a version of the Linux "aplay" utility, but without the speed limit - While more recent versions of Ubuntu (and likely other)
Linux distributions have ALSA kernels capable of sample rates of at
least 768 ksps, many of the related utiilties do not - including
"aplay". This page describes how to create "fplay", a version of
"aplay" that has no such sample rate speed limit - and why this utility
is helpful when implementing a "high rate" 16 bit ALSA device like the
SDRPlay RSP1a.
Getting I/Q data from the receiver - This
page discusses how raw I/Q data may be routed from the receiver and
into ALSA. Specifically, it discusses the "sdrplayalsa" utility -
code written specifically for the RPS1a, and how/why it's built-in AGC
may be used.
Duplicating receiver I/Q data streams using ALSA and asoundrc - Normally, the raw I/Q data from the receiver on a WebSDR goes just ONE
place, but wouldn't it be nice if that data could be replicated and
used elsewhere for things like analysis, reception of digital signals
like FT-8 and WSPR, a CW skimmer, logging or monitoring the health of
the receiver system itself? This page describes how it's possible
to get the raw I/Q data that you already have and duplicate it, making it available for other purposes to leverage the capabilities of your system?
Using CSDR for auxiliary receivers on a WebSDR System -
Dovetailing with the above article, this shows how you can take the raw
I/Q stream from your existing receiver and produce a separate
narrow-bandwidth receiver - or even a more narrow-banded I/Q stream -
to do even more things, such as FT-8 reception and generating an input
to something like a CW skimmer.
Other related pages:
Using the "libmiricsdr" utilities for reception and on a WebSDR System
- As the SDRPlay drivers are not open-source, I looked into using the
"libmiricsdr" utilities - notably "miri_sdr" - instead to interface
with the RSP1a. This article describes how this would be done as
well as a few points relating to (possible) work needing to be done to make the fully usable in this role.
For general information about this WebSDR system -
including contact info - go to the about
page(link).
For the latest news about this system and current issues,
visit the latest news
page (link).
For more information about this server you may contact
Clint, KA7OEI using his callsign at arrl dot net.
For more information about the WebSDR project in general -
including information about other WebSDR servers worldwide and
additional technical information - go to http://www.websdr.org