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.
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:
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.
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: