This post presents a project idea and plan. The project hasn't started yet. I hope to post updates as it progresses.
Larry's recent post about GNU radio rekindled my interest in sound-card-based SDR. The idea is that you use 2 analog DC receivers, with a 90 degree phase shift between the VFO signals, to convert the RF signal down into two audio signals, which also then have a 90 degree phase shift. In other words, you now have two audio signals, one which we can arbitrarily define to be in-phase with the incoming signal (the I channel) and the other one which is 90 degrees delayed with respect to the I signal (the Q, or quadrature channel). We feed these I and Q audio signals into a normal PC sound card with stereo microphone input, and then we can use DSP on both channels to do various things, including image rejection, meaning we can differentiate between signals above and below the LO frequency.
A good PC sound card might have a 192 kHz sample rate, which then can then digitize signals up to 96 kHz. By using both the I and the Q channels, we can then recover a 192 kHz wide slice of spectrum (96 kHz above the LO, and 96 kHz below the LO) and manipulate it digitally. So you could tune the analog VFO to say 7100 kHz, which will generate two channels of audio (I and Q) from 0-96 kHz, which then can be processed with DSP and can recover the signals in the RF spectrum from 7004 to 7196 kHz. For example, a signal at 7105 kHz mixed with the 7100 kHz LO would generate a 5 kHz pair of IQ signals. At the same time, a signal at 7095 kHz will also mix with the 7100 kHz LO to generate a 5 kHz pair of IQ signals. But thanks to the presence of both I and Q channels, we can digitally remove the unwanted signal (either the signal above the LO, or the signal below the LO) and listen to only the desired signal. So we can independently recover the signal at 7105 kHz, or recover the signal at 7095 kHz. The same logic applies from to all signals from 7100 - 96 kHz up to 7100 + 96 kHz, so we can recover all signals in that slice of RF spectrum (except for those signals very near the LO frequency, which generate audio signals near 0 Hz, which cannot be digitized by the sound card).
For hardware, it should be easy to achieve a narrow-band 90 degree RF phase shift; TinySDR is one example. http://www.qrz.lt/ly1gp/SDR/ There will however be slight amplitude differences between the I and the Q channel. It might be possible to compensate for this in software.
For the software part, GNU Radio should be able to process the I and Q signals and recover a narrow slice of the original RF spectrum around the LO, including image suppression. Then, given the digitized RF spectrum slice, we can further use software filters and demodulators (SSB, AM, FM, etc.) to listen to any part of that spectrum slice.
One limitation of using the PC sound card for this purpose is that PC sound cards are not really designed for this kind of high-precision application (see http://www.wb5rvz.com/usb2sdr/ for some notes). But it should be a cheap and easy way to experiment with the core concepts behind SDR.
I don't know much about GNU Radio yet. This project will be a learning exercise.
The first part of the plan is to build a simple phase-shifting front end like TinySDR, feed in a sine wave, and confirm (with a PC sound card oscilloscope) that the AF outputs are indeed 90 degrees out of phase.
Here are the links where you can listen and compare in real-time the performance of the higher-performance SDRPlay (14 bits ADC) and the lower-performance RTL-SDR (8 bits ADC).
The lower-performance RTL-SDR is using the external AGC circuit described above to dynamically adjust the signal levels coming into the RTL-SDR and make best use of the limited 8-bit dynamic range.
Higher-performance receiver (14 bits), tuned to 7272 kHz: http://websdr1.sdrutah.org:8901/index1a.html?tune=7272lsb . This receiver is described as: "40M -A 'high performance' receiver consisting of an SDRPlay RSP1a with custom drivers. This receiver operated at 768 kHz and is centered on 7125 kHz, spanning 6741-7509 kHz, covering the entirety of the 40 meter band."
Lower-performance receiver (8 bits), also tuned to 7272 kHz: http://websdr3.sdrutah.org:8903/index1a.html?tune=7272lsb . This receiver is described as: "41-40M - An 'RTL-SDR blog' Ver. 3 dongle operating in 'Direct Sampling' mode centered at 7500 kHz covering from 6732 to 8268 kHz which includes the 41 meter shortwave broadcast band and the entirety of the 40 meter amateur band. This receiver offers redundancy to one of the most heavily-used bands on this WebSDR (40 meters) and can be brought to bear if WebSDR1 goes offline. Using an RTL-SDR dongle, its performance will be somewhat inferior to the main 40 meter receiver, but it should be "good enough" for all but the most demanding application."
I only skimmed it, but the same idea could be useful for applying some degree of AGC to a more modern implementation of an old style direct conversion receiver. That particular ADI chip is somewhat expensive as best I recall.
SDR looks to be the state of the art implementation of direct conversion, and direct conversion looks to be the current state of the art in receiver design, having displaced up conversion superheterodyne designs.
I'm seriously considering a simple direct conversion receiver as my next receiver project, but the traditional drawbacks - no AGC and lack of single signal reception are not acceptable to me.
73,
Win W5JAG
Interesting article by KA7OEI about using a separate, outboard AGC circuit to limit the total signal energy coming into the RTL-SDR and prevent overload (also preventing the spurious signals that happen when overload occurs).
The article provides some links where you can compare, in real-time, the signals received by the RTL-SDR (with the additional outboard AGC circuit) against the same signals received by a more expensive SDR with higher ADC resolution. (I'll post the exact links here later.) The RTL-SDR seems to do okay in this comparison.
Unfortunately the built-in internal hardware AGC (already on the RTL-SDR circuit board itself) seems not to work so well. Some notes are provided in the above article, and also in a separate discussion here: https://community.libre.space/t/is-it-possible-to-use-agc-on-the-rtlsdrs-now-were-using-soapy-sdr/5930/2 .
I'm thinking of trying to write my own simple AGC (using the built-in hardware RF gain control in the RTL-SDR) in GNU Radio. The algorithm would be:
Receive a wide slice of spectrum (1 MHz wide or 2 MHz wide) from the RTL-SDR, using GNU Radio.
Generate a FFT of the received spectrum slice.
Measure the entire signal received power by summing up (integrating) the area under the FFT.
If the received power exceeds a certain user-set level (to be determined experimentally), then reduce the gain to avoid the risk of overload.
In playing with the gain control by hand, it can be seen that exceeding a certain unknown threshold suddenly causes all manner of noise and spurious signals to appear. The problem is how to determine that unknown threshold, and avoid it, in software. I think the "area under the FFT" is one approach.
This approach -- controlling the internal gain of the RTL-SDR -- will not be as performant as KA7OEI's approach of controlling the gain of an external AGC stage; according to the discussion linked above, it seems maybe the dynamic range of the RTL-SDR may decrease when adjusting the internal gain levels. Nevertheless, it will be easier to implement (requiring no additional hardware) and should provide some degree of automatic protection against overload, which could be useful if making unattended hours-long spectrum recordings.
Here's a GNU Radio flow graph to demodulate FM signals in real-time off the air (not from a pre-recorded file) from my RTL-SDR.
I had to install on my Linux machine the package "gr-osmosdr", which then installs the "osmocom Source" block that can read data in real time from the RTL-SDR hardware. The RF gain and IF gain -- which control the hardware gain settings in the RTL-SDR dongle -- have to be set pretty high in the "osmocom Source" block, or else the hardware will be too insensitive and will hear nothing. The gain option (which means automatic gain) should be turned off, to allow the manual gain setting.
You can also set the RTL-SDR hardware sample rate, and hardware reception frequency. I set the sample rate to 2 Mbps, i.e. 2 million IQ samples per second. For the reception frequency, I just tried receiving some local FM stations on the RTL-SDR around 80 MHz.
I noticed that with the above flow graph, I was getting choppy audio. I think the bottleneck is the Rational Resampler block, which changes the sample rate from 200k to 160k, to generate a 160kHz signal as input to the WBFM Receive block.
I tried reducing various settings, but could never reduce the choppy audio inside of GNU Radio itself. But there is an audio setting that can be made in the Linux OS to improve choppy audio, as described here: https://www.funwithelectronics.com/?id=167 . I added the following into the file ~/.gnuradio/config.conf:
[audio_alsa] nperiods = 16
Then I could get smooth audio. Nevertheless, I may be running close to the limits of my PC's processing power.
Here's a quick video of reception. There is no antenna connected to the RTL-SDR. Nevertheless, the FM signal is clearly, if weakly, audible in the start of the video. In the middle of the video, I put my hand near the RTL-SDR, and my body then serves as an antenna and the signal becomes much clearer. At the end of the video I again remove my hand, and the signal becomes weak again.
So, we have learned that:
GNU Radio, with some configuration settings, on a fairly old PC, is able to receive data in real-time at a 2 Mbps sample rate from the RTL-SDR, and can demodulate a WBFM signal into a 16 kHz audio stream. At the same time, my PC is also displaying the waterfall display showing the entire 2 MHz reception bandwidth.
The RTL-SDR, without any physical shielding like a metal case, is prone to pick up strong local FM stations. Even when tuned to far-away frequencies, these strong signals can desensitize the receiver and make weak-signal reception more difficult, so shielding and bandpass filtering are important.
So all the basic hardware (RTL-SDR) and software (GNU Radio) is working.
Next, for shortwave reception, I need to implement shielding and bandpass filtering for the HF upconverter, which I already built some years ago. At the same time, it may be worthwhile to implement a LNA.
Here's a quick video of the GNU Radio flow graph processing the IQ file linked above.
I wrote above:
Actually, that bit about images isn't true. Multiplying the complex signals is really all you need to do, to implement a frequency shift in DSP.
I'm a little rusty on how this works mathematically under the hood, but to test this, I made a simple testbed in GNU Radio with a sinusoidal signal at 5000 Hz, multiplied by another sinusoidal signal (the LO signal), and graphed the result in the frequency domain as an FFT. Here's the GNU Radio flow graph. All signal multiplication is done with complex numbers.
Running this flow graph gives the following result. As we change the LO frequency, we only get one output signal resulting from the mixing (multiplication), which at a frequency given by the sum of the signal frequency and the LO frequency. The LO frequency can also be positive or negative, which then is summed with the original frequency, allowing us to move the original signal upwards or downwards in frequency. We do not get any image signals as a result of the mixing (multiplication) of the complex sinusoids.
Now on the other hand, things look drastically different if we do the multiplication using only real numbers and discard the imaginary part of the complex numbers, as done in the following flow graph.
Now when we run this flow graph, as shown in the below video, we immediately see right from the start (even with the LO set to 0 Hz) that the original signal "exists" at two locations in the frequency domain -- at +5000 Hz and at - 5000 Hz, above and below "zero beat" as it were. Furthermore, as we adjust the LO, we see that we get two mixing products: both the sum and difference frequencies. Furthermore, those two mixing products (sum and difference) exist both "above" zero Hz as positive frequencies, and "below" zero Hz as negative frequencies.
Here's another nice summary article about using wideband spectrum recordings with a portable SDR for later listening and DXing.
The dynamic range of the RTL-SDR is limited to a quite low value of only around 40 dB, caused by the only 8 bits available in the analog-to-digital converter, so RTL-SDR is not the best hardware device for making spectrum recordings because strong signals will desensitize the receiver and make weak signal reception impossible. This can be mitigated by using good bandpass filters to knock down strong AM BCB and FM BCB stations and focus only on the band of interest.
Amazing. Looking forward to following the progress on this.
73,
Win W5JAG
After several hours of reading documentation and experimenting, I have a functional SDR working in GNU Radio, reading from a sample IQ file.
For the input file, I download the 40 meter IQ recording file here: https://sdrplay.com/resources/IQ/40m.zip .
Inside of that ZIP file, there is a WAV file with filename SDRuno_20200912_004330Z_7150kHz.wav . This indicates that the LO was set to 7150 kHz during the recording. This means that:
0 Hz in the IQ file corresponds to 7150 kHz
+1 kHz in the IQ file corresponds to 7151 kHz
-1 kHz in the IQ file corresponds to 7149 kHz
and so forth. Because this is IQ data, we can differentiate between signals above and below the LO.
The next question was sample rate of the file. This was not specified on the download page (https://www.sdrplay.com/iq-demo-files/). However, inside of the above ZIP file, there is a screenshot image file from the software used to generate this file, and at the bottom of the screenshot it says "SR: 333333 Hz", meaning a sample rate of 333,333 Hz. Checking the WAV file information on my PC also indicates the sample rate is 333,333 Hz. So this file is a 333.333 kHz slice of RF spectrum centered on 7150 kHz.
To play this back in GNU Radio, I created the following flow graph:
In the upper-left, there is a variable "samp_rate", set to 333333 Hz, the sample rate of the input IQ file. The Wav_File_Source block then reads this file. The file outputs two float channels, which represent the complex signal data (I channel and Q channel), so we use a "Float to Complex" block to convert the 2 floating point data streams into a single complex (I and Q) data stream.
The original data is a 333.333 kHz slice of spectrum that has been downconverted from 7150 kHz, the original LO frequency. So if we want to listen to a signal at 7250 kHz, that signal will be located at 100 kHz in the data file (LO + 100 kHz = 7150 + 100 kHz = 7250 kHz).
Then, to listen to a signal at 100 kHz in the IQ file, we further need to downconvert it to baseband. There seem to be several ways to do this. My first experiment was the old-school way: A mixer is nothing but a multiplier, so we can just multiply the entire spectrum by a 100 kHz sine wave, using a signal source block and a multiplier block. That actually worked! But of course it generates images as part of the mixing process. Rather than dealing with the math of mixing and image canceling directly, I figured there must be some more convenient way to do downmixing in GNU Radio, and indeed there is.
It seems the recommended way to downconvert a part of the digitised spectrum is to use the Frequency Xlating FIR Filter block, described on the GNU Radio wiki here: https://wiki.gnuradio.org/index.php?title=Frequency_Xlating_FIR_Filter
This block translates the whole spectrum to be centered on the frequency you specify, which in the above example would be 100 kHz, so that we can listen to the signal at 100 kHz. By controlling the center frequency with a GUI slider (all easily accessible from the GNU Radio Companion menu with drag-and-drop operations), we can control the amount of spectrum downshifting -- in other words, we can tune the radio by controlling the center frequency of this block.
Furthermore, this block applies a final decimation step, which basically discards a specified proportion of the data. I specified a decimation of 10, meaning that the final data stream will contain 1/10th of the original data volume; in other words, after decimation by 10, the sample rate is divided by 10. So our original 333.333 kHz stream has now been reduced to a 33.333 kHz stream.
Reducing the data volume at this early stage in the flow graph is important to ensure good performance of the following processing blocks. If we fed in the whole 333,333 Hz stream into all the downstream blocks, they would have to process a very large amount of data, and the whole application could become slow and unresponsive, with audio delays and gaps.
Next, the signal is fed into three blocks simultaneously:
The unfiltered signal is fed into input port 0 of a selector, which is like a multi-position analog switch.
The unfiltered signal is also fed into a 10 kHz bandpass filter with real taps, and the filtered signal is then fed into port 1 of the selector.
The unfiltered signal is also fed into a 10 kHz bandpass filter with complex taps, and the filtered signal is then fed into port 2 of the selector.
By trial and error I discovered that the difference between the real taps filter and the complex taps filter is that with real taps, the filter does not remove the image, so a 10 kHz filter will allow signals from -5 kHz to 5 kHz to pass. On the other hand, if we use complex taps, then a 10 kHz filter will only allow signals from 1 Hz (a user-specified lower bound) to 5 kHz, but will eliminate the signals below the LO from -5 kHz to -1 Hz. This is one way to implement image rejection. Some explanation is given here: https://pysdr.org/content/filters.html .
A combobox on the GUI allows selecting which of the above 3 signals then gets processed further.
After the selector, the signal is multiplied by a constant, to serve as a volume control.
The multiplied signal gets fed into two separate paths simultaneously:
A QT GUI Sink, which displays the data graphically either in the time domain (oscilloscope) or the frequency domain (waterfall display).
A fractional resampler with a resampling ratio of 0.960, to change the incoming 33.333 kHz data into 32.000 kHz data. The 32.000 kHz data is then converted from complex data back into floating point data, and is fed into the 32 kHz sound card output.
I noticed that the resampling stage can be quite slow. That's why it's important to limit the amount of data that comes into it.
Then, pressing the play button, the application runs, you can hear the audio, and you can control the tuning by altering the center frequency of the Frequency Xlating block. The file contains several 40m SSB and CW signals.
The screenshot below shows the waterfall display of the application, when switching between the three filters.
In the top one-third of the waterfall display, you can see the unfiltered 33.333 kHz spectrum (although I am only displaying 16 kHz, from -8 kHz to +8 kHz). The unfiltered spectrum extends across (and indeed, beyond) the entire -8 KHz to +8 kHz frequency range of the waterfall display.
In the middle third of the waterfall display, you can see the spectrum when filtered with a 10 kHz bandpass filter using real taps. The 10 kHz bandwidth extends from -5 kHz to +5 kHz. The image signals are not eliminated; CW signals are audible both above and below zero-beat.
In the bottom third of the waterfall display, you can see the spectrum when filtered with a 10 kHz bandpass filter using complex taps. Again, the 10 kHz bandwidth extends from -5 kHz to +5 kHz, but this time the image frequencies above 0 Hz have been eliminated. CW signals are audible only below zero-beat. So using this digital bandpass filter is one way -- but certainly not the only way -- to eliminate the image signals.
The bandpass filter with complex taps can pass either the lower sideband or the upper sideband. To pass the lower sideband, a passband with negative frequencies is specified (from -10000 Hz to -1 Hz). To pass the upper sideband, a passband with positive frequencies is specified (from 1 Hz to 10000 Hz).
Even when applying the filters, you can see that the filters are not perfect and some signals outside of the filter bandwidth are still barely visible on the waterfall display. I am sure that the digital filters allow many parameters to be set, to improve the filtering to any degree desired, at the cost of processing power and time.
It's fairly intuitive to hook together the processing blocks, and it was quite a thrill when I first was able to correctly hear the demodulated signals. It's really not that different than analog radio engineering -- you chose and configure your mixers and filters, and decide what processing you want to do at each frequency, before finally converting down to baseband. And it is satisfying to be able to easily drag-and-drop the various signal processing components together, and hear the result. It feels satisfying in a way quite similar to building analog radio or filter circuits -- there's a certain immediate and direct connection between cause and effect,, so you can tweak some parameter or reroute the signal processing flow in GNU Radio, and then instantly hear the result and see it on the waterfall display.
So... at some point I will want to build my own hardware (like TinySDR, linked above) to create IQ files with my PC soundcard. I mentioned in a previous post that a simple analog phase-shift network, like TinySDR uses, will not have uniform phase shift, because the phase (or at least the amplitude) will change slightly with frequency. This is a standard problem with analog phase shift networks, and interestingly, there is already a GNU Radio block to deal with that, the so-called "Freq. Selective IQ Correction" block. The documentation is supposed to be at https://wiki.gnuradio.org/index.php/Freq._Selective_IQ_Correction , but there's no documentation yet. There's a tiny bit of discussion about this block here: https://lists.gnu.org/archive/html/discuss-gnuradio/2021-03/msg00088.html .
Putting aside custom hardware for the moment, I'm pretty sure that there is a GNU Radio block that can directly get IQ data directly from the RTL-SDR dongle which I already have. That would be a faster way to experiment.
Though it takes a lot of disk space, it could also be interesting to make hours-long wideband spectrum recordings for later listening. For example, I sometimes wonder what shortwave signals I am missing at 4am in the morning. Then, when later listening to these recordings, digging out weak signals becomes a matter of understanding and tweaking the SDR and DSP parameters. Here's one guy's neat setup for portable spectrum capturing.
Without reading any documentation, and after clicking around for about 15 minutes, I managed to put together the following flow graph in GNU Radio Companion. A noise source and a sine wave source are fed into a signal adder, which then feeds the resulting signal into an audio sink (i.e. the PC's audio output). Pressing the "play" icon in the toolbar results in the PC speaker playing back a sine wave with noise.
So far, so good! There is also a submenu with "File Operators", under which is located a "File Source", which can read data from a file. Next I will try to find some IQ data files -- I can probably create some myself from my RTL-SDR hardware dongle -- and figure out what processing blocks I need to use in GNU Radio to demodulate them.
Here's a page explaining how to play IQ files in GNU Radio: https://www.pe0sat.vgnet.nl/sdr/sdr-software/using-iq-files/ .
For input data, I'll try using the sample IQ data from here: https://www.sdrplay.com/iq-demo-files/ .
On my Linux machine, installing the "gnuradio" package makes the command "gnuradio-companion" available. Running that then gives this screen.
I'm guessing that there should be some sample IQ data files available for testing, so I'm hoping that as a start I can just use some pre-existing test data file, tell GNU Radio to read the data from that file, and then try to demodulate the IQ data down to audio by combining some GNU Radio DSP blocks.
Once that works, then I can figure out how to actually create my own IQ data, feed it into the stereo microphone, and get GNU Radio to read the data from the stereo microphone.
I'm seriously considering a ham band only, sideband cancelling DC receiver as my next RF project, and am starring to acquire the parts for it.
i don't know anything about SDR or GNU Radio, but one of the reasons that I bought the Red Pitaya as a piece of test equipment is that it can be used to make a highy capable SDR radio. They make a 16 bit variant that is tailored for SDR use, but the 14 bit variant like I have will also work.
I'm not sure if the 10 bit variant is SDR capable.
Red Pitaya - Swiss Army Knife For Engineers
73,
Win W5JAG