Open vk4jbe opened 1 year ago
John, let's start from the problem with the bandwidth.
In SoapySDRPlay3 the bandwidth is determined by the sample rate; this is to avoid problems with aliasing if you set the bandwidth wider than the sample rate (because of the Nyquist theorem).
If you look at the function getBwEnumForRate
(https://github.com/pothosware/SoapySDRPlay3/blob/master/Settings.cpp#L996-L1006), you'll see that if the output sample rate (which is the sample rate divided by the decimation factor) is less than 300kHz, then the bandwidth is fixed at 200kHz.
I am not sure what value of sample rate and decimation you are using, but I would suggest to try a quick test with sample rate = 2MHz and decimation = 1 to see if the bandwidth gets set correctly at 1536kHz (instead of 200kHz).
Franco
Franco…..Thanks for the quick reply. I thought you guys would still be in bed!!!
I may have misled you with the term bandwidth……I am actually getting the bandwidth on the spectrum screen that I expect for the given sample rate and decimation combination. What I have is a 200kHz hump in the middle of that bandwidth where the receiver works fine. Outside of that it gets progressively deafer until it hears nothing.
This is what I did to test the software/hardware combination. I fired up GQRX first and the default values are 2Msps, Decimation = None (ie 1) and IFGR = 50 and RFGR = 0. This gives a plot that has a hump about 200kHz wide (at -80dBm) in the middle of the 1MHz spectrum plot (at -120dBm elsewhere). Not the approximately 2MHz of signal across the entire 2MHz displayed on the GQRX screen that I was expecting. Adjusting the RFGR = 4 brings the hump noise floor down to about -100dBm…..The rest stays at -120dBm. Inside the 200kHz it receives fine.
I have played with various combinations of Sample Rates up to 10Msps and down to 500ksps (I think)…..and various Decimations (mostly around 4-16 but some higher). As expected the bandwidth on the 5Msps ~= 5MHz of BW. On 8Msps = 8MHz or BW. All with this 200kHz wide hump in the middle. If I put in 8Msps and Dec = 8 then I get ~1MHz BW with a 200kHz hump in the middle. At low sample rates (ie 125ksps) the hump is not visible and the bandwidth is only 125kHz wide.
All of these tests were done with GQRX 2.15.9. I tried a few similar things in GNURadio using the SoapySDRPlay source with similar results.
Out of interest……Your test of Sample Rate = 2Msps and Dec = 1 (ie none) gives me a bandwidth of 2MHz…..not the 1.536MHz you suggest. Looking at the code I can see where it gets set to 200kHz if the ‘output_sample_rate < 300000’ and works its way through the various combinations up to 8Msps. Basically the setting of the spectrum bandwidth seems to be working. It seems more like a filter on the RF side of things.
One of the things I noted when I do a SoapySDRUtil –probe=”driver=sdrplay” is that the last line after the Sample Rates report is the Filter Bandwidths…..the lowest of these is 0.2 MHz. I cannot see where they are coming from and how they are used. Is there something in this area that may be limiting the RF bandwidth within the displayed spectrum bandwidth?
By the way I have a second RSPdx that does the same thing on linux. They work fine with SDR-Console.
Appreciate you looking in this and offering any help. If I can get it all working my next step is to see if I can get the recipe process working for Ryan Volz’s radioconda.
John – VK4JBE
John, it's about 10:30pm here in Florida, so I am about to go to bed now LOL
Anyway since you are saying the problem happens with GNU Radio too, do you mind attaching here the .grc file you used and the screenshot that shows that hump? This way I can try to reproduce it here with my RSPdx. Also please run these tests with all the antennas disconnected from the RSPdx, so we can rule out any external cause (plus this way my results should be identical to yours).
As per the bandwidth when the sample rate is set to 2MHz, you are 100% correct: it should be 2MHz, not 1536kHz.
Franco K4VZ
Franco.....Here are the files you requested. I have put the .grc file in a .zip file because github did not seem to like that extension. Also attached is a screen dump of my .grc running. You can clearly see the hump in the middle of the passband.
Hope this provides some clues. Meantime I will continue my digging.
John - VK4JBE
Franco....I have been doing a bit more digging in the Settings.cpp file.
I can see that in the Bandwidth API section the setBandwidth() function (L937-L952) calls the sdrPlayGetBwMhzEnum() function (L945). Looking at the code for the sdrPlayGetBwMhzEnum() function I can see that the default if it fails to match an 'output_sample_rate' is to set the return value to 'sdrplay_api_BW_0_200'. I assume this sets the filter bandwidth to 200kHz (but I am only guessing).
The setBandwidth() parameter 'bw_in' is passed straight to the sdrPlayGetBwMhzEnum() function with no validation so that if the setBandwidth() function passed an invalid bandwidth then it would always fail to 200kHz.
I note the sdrPlayGetBwMhzEnum() function and the getBwEnumForRate() function are similar in that they take in a sample_rate and both return the 'sdrplay_api_BW_x_yyy' constant. The getBwEnumForRate() function has advantage that if you put in an invalid value it will select the most appropiate 'sdrplay_api_BW_x_yyy' constant (ie put in 2Msps and it will give 1.5356MHz). I note that is what you originally expected for a 2Msps sample rate. Is that a clue!!!!
All of this leads me to suspect that line 945 of the setBandwidth() function should use the failsafe getBwEnumForRate() rather than the sdrPlayGetBwMhzEnum() which can only deal with valid sample rates.
Is my logic correct? Is this a possible source of the error?
That said .....I think I am feeding it valid sample rates from GQRX and GNURadio so I am not sure why it is failing and I can’t find what feeds the setBandwidth() function to check that out. In GNURadio I did try casting the sample rate value as a float() and an int() but it did not change things.
I might also try and set up a new VM on my VirtualBox machine and make the changes to the code and see what difference it makes. I am not very confident in c++ compiling (or coding) so I may quickly hit the wall of knowledge (or lack of!!!)
One further bit of info is that I recalled that I had a RPi with a PiSDR image on it that supports the SDRPlay devices. I tried the RSPdx in that RPi and fired up GQRX and it did the same thing as my laptop and VM. That image was precompiled so it suggests that the process of compiling the code on my laptop and VM is ok. The other alternative is that both my RSPdx's are the issue. I bought them about 1 year apart so you would think that is not the case....plus one device at least runs ok on SDR-Console on windows. I have not tried the other device.
Hope this provides some clues that may mean more to you.
John – VK4JBE
Excellent detective work John!
I read your comment and looked at the code, and I think you're right that the function setBandwidth()
should be using the failsafe getBwEnumForRate()
instead of sdrPlayGetBwMhzEnum()
.
Unfortunately I have to start work in a few minutes, so perhaps in the meanwhile you could change just that line in Settings.cpp
, rebuild SoapySDRPlay3, and run GNU Radio (and/or gqrx) again to see if the problem goes away.
Tonight after work I'll try the same thing (before and after the change), and if everything looks OK, I'll commit this change in the code.
Franco K4VZ
Franco... Hope you had a productive day at work. I think I see some sense in this now.
I did as you suggested and built a new VM with radioconda and recompiled the SoapySDRPlay3 with the suggested changes. I also have a separate VM with the original SoapSDRPlay3 (without the changes). This makes it easy to compare the new version with the old version.
I initially tested the new version with GQRX and it did not seem to make any changes. I had the default values. Sample Rate = 2Msps Decimation = None (ie =1) and Bandwidth = 0.00000MHz.
In GQRX I had a Display Bandwidth of 2MHz (ie equal to the sample rate) and a RF Signal Bandwidth of 200kHz (the hump). I then set the GQRX bandwidth to 2MHz and got a much wider signal. As it turned out it was the 1.536MHz that was in your mind. I played with a few different settings and combinations and found that it is important to set the Bandwidth in GQRX. If you leave the Bandwidth = 0.000MHz then you get 200kHz. Basically the available bandwidths are those that you get when you run SoapySDRUtil --probe="driver=sdrplay".
I flipped over to the old SoapySDRPlay VM and ran GQRX again. Here I found that if you did not set the Bandwidth to one of the valid RF Bandwidths then you got 200kHz of RF Bandwidth. Playing around with combinations I found that provided you set a valid Bandwidth and you set a Sample Rate that was faster than the Bandwidth and you could get the correct RF bandwidth to display.
It is worthy of note that the GQRX Sample Rate sets the Display Bandwidth and that the Bandwidth sets the RF Bandwidth of the signal within the display.
It is also worthy of note that the SDRPlay sample rates only partially match the RF Bandwidths. Most people would probably set the RF Bandwidth = Sample Rate (aka Display Bandwidth) or leave it at 0.0MHz as I did initially.
SDRPlay Valid Sample Rates (ksps): 62.5, 96, 125, 250, 384, 500, 768, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000 SDRPlay Valid RF Bandwidths (kHz): 200 300 600 1536 5000, 6000, 7000, 8000
The beauty of the change in the new VM is that if you set a non-valid Bandwidth it selects the next lowest valid Bandwidth. That does not help people who leave the GQRX Bandwidth = 0.0Mhz. That will always be set to 200kHz.
I think if you are doing satellite work like I am you want a pass band of about 600kHz or maybe 1.536MHz to see the segment of interest for a satellite with a linear transponder, a CW beacon and telemetry. If you are looking at large chunks of bandwidth then 5-8MHz is the go.
I note that setting the Bandwidth value in the GNURadio Soapy SDRPlay Source also fixes the problem. I had not done that in the .grc I sent you.
I suggest that you deploy the change to make it a little more goose proof. I am not familiar with Wiki's but it may be worthwhile adding a note about this to the SoapySDRPlay3 wiki. I am happy to write the words if you want.
John - VK4JBE
@vk4jbe - thanks for making the change and confirming that it solves the problem.
Tonight I too ran your GNU Radio flowgraph with the original code from the master
branch, and I saw the issue with the IF bandwidth stuck at 200kHz. I then changed the code in the setBandwidth()
function to use getBwEnumForRate()
, and I confirmed that the bandwidth is now set to the right value (1536kHz for a sample rate of 2Msps).
I created a new branch called use-getBwEnumForRate
(https://github.com/pothosware/SoapySDRPlay3/tree/use-getBwEnumForRate) with the new code; I changed just that one line and I removed the function sdrPlayGetBwMhzEnum()
because it is no longer used.
When you have time, try building SoapySDRPlay3 using the code from the new branch use-getBwEnumForRate
to make sure it work for you too; once we are all good with it, I'll merge it into the master
branch.
Finally, if you are doing advanced work in GNU Radio using your RSPdx's, you may want to consider the 'gr-sdrplay3' OOT module that I wrote specifically for the SDRplay RSPs (https://github.com/fventuri/gr-sdrplay3) to use them as native GNU Radio sources. The instructions to run 'gr-sdrplay3' on Windows using conda (or radioconda) are in this message I sent about a year ago to the GNU Radio mailing list: https://lists.gnu.org/archive/html/discuss-gnuradio/2022-03/msg00144.html - if you decide to try 'gr-sdrplay3' let me know if you run into any problems and I'll be happy to help you.
Franco K4VZ
Great information. I have some sdrplay equipment, but hadn’t noticed this before. Once it’s in main I’d like to build it into a deb package and test a deployment upgrade over apt.
Franco......thanks for validating the changes and for all the extra info. I have been doing some family things for the last few days but last night managed to download the new branch and compile it. All ok on my system.
Emboldened by my success at compiling a one line change (LOL) I thought I might have a go at putting in a warning message if the user forgets to set the bandwidth or makes it a value less than 200kHz.
In the getBwEnumforRate() function I changed the first line of the function from this....
if (output_sample_rate < 300000) return sdrplay_api_BW_0_200;
to this.....
if (output_sample_rate < 200000) { SoapySDR_log(SOAPY_SDR_WARNING, "Bandwidth < 200000 is not valid! Setting Bandwidth to 200kHz."); return sdrplay_api_BW_0_200; } else if (output_sample_rate < 300000) return sdrplay_api_BW_0_200;
I tested that and it worked fine.....Whilst not 100% fool proof it at least it points people in the right direction if they get that funny hump in the middle of there spectrum display.
If you feel like some more cosmetic changes I would suggest a minor change to the naming of the getBwEnumforRate(output_sample_rate) and getBwValueFromEnum(bwEnum) functions would make the code a little more readable for us newbies.
These two functions convert a BwEnum to BwValue and vice versa. However, the name getBwEnumforRate() and the input parameter 'output_sample_rate' suggest it is about converting sample rates when in fact it is about converting a bandwidth value. The getBwValueFromEnum(bwEnum) function about converting an enumeration is almost correct. Just a minor name change for consistency.
Can I suggest the following minor name changes..
getBwEnumforRate(output_sample_rate) => getBwEnumforBwValue(bwValue) .......and parameter 'output_sample_rate' => 'bwValue' getBwValueFromEnum(bwEnum) => getBwValueFromBwEnum(bwEnum).......the parameter ‘bwEnum’ is clearly named.
There are some changes in SoapySDRPlay.hpp on L260 and L262 and some changes is the Settings.cpp on L739, L943, L945, L960 and of course the two functions. I have made these changes and they seem to work. If you feel inclined to make these changes in a the new branch I will test them out for you.
I have also written some words to update the wiki. I will post those separately. PS: I must learn how to markup in github.
John - VK4JBE
Franco – Attached is my suggested wording for the SoapySDRPlay3 wiki. I have tried to make it cover the current version and your new branch. Feel free to modify, update, correct as necessary.
I am not familiar enough with the Github system to add that to the wiki so if you are able to update it I would appreciate it.
John – VK4JBE
John, thanks for your feedback and hard work!
Tonight I took a quick look at getBwEnumForRate
, and I see it is called like this (https://github.com/pothosware/SoapySDRPlay3/blob/master/Settings.cpp#L739):
sdrplay_api_Bw_MHzT bwType = getBwEnumForRate(output_sample_rate);
The variable output_sample_rate
is the output sample rate from the RSP + SDRplay API going in to the client application (GNU Radio or gqrx in this case). This sample rate is after decimation, and therefore it can be < 200kHz (for instance a sample rate of 2MHz decimated by 16 becomes an output sample rate of 125kHz, and if it is decimated by 32 it becomes 62.5kHz), so these valid values of the sample rate would trigger the warning you suggested.
If I remember correctly the problem you observed with gqrx was that the application was attempting to set a bandwidth of 0Hz, which is definitely an invalid value. Perhaps we may want to consider to have a similar warning if the argument for getBwEnumForRate
is 0, and return from that function without changing the current bandwidth.
I might not be able to work on this issue for the next couple of days due to my schedule, but Wednesday night I should be able to answer your comments and discuss this with you.
Franco K4VZ
No problems Franco and no rush. I appreciate you bearing with me on this.
I now understand what it going on and what I need to do to get it working on my system. My only reason for pursuing it is so others don’t fall into the same trap.
Thanks for the other info….I have been having a bit of a look at that.
John – VK4JBE
John, this morning I ran gqrx (all my tests were done with GNU Radio so far), and I noticed that if you hover on the bandwidth selection box it says "Analog bandwidth (leave at 0 for default)". I then added a log statement in the setBandwidth()
function, and I saw that gqrx calls it with the bw_in
argument set to 0, which causes the 200kHz bandwidth problem.
Because of the special meaning that gqrx gives to the value 0, I thought that it might be a good idea to change the function setBandwidth()
so that a value of 0 sets the bandwidth to the highest value compatible with the sample rate (for instance in the case of a sample rate of 2Msps it would set it to 1536kHz), which I think is a reasonable default.
I also refactored setBandwidth()
so that now it uses just getBwEnumForRate()
for everything (instead of getBwValueFromEnum()
one way and getBwEnumForRate()
the other), since I think it is more consistent with this approach.
I left temporarily that log statement in setBandwidth()
that shows both the value of the bw_in
argument and the bandwidth value that is actually set by the function (bwType
), so you can run it with gqrx and see the calls it makes to setBandwidth()
.
In the next few days I also want to validate these changes with CubicSDR, to make sure they don't introduce problems or unexpected behavior there; CubicSDR is kind of how the whole SoapySDRPlay3 module started, and I use CubicSDR as the reference SDR client application for SoapySDRPlay3 (I also think there's a significant number of users running CubicSDR).
Please try the latest changes from the use-getBwEnumForRate
branch when you have time, and let me know what you think.
Franco K4VZ
Franco….Interestingly enough I have done some similar things. I actually put log statements in various places in both setSampleRate()
and setBandwidth()
and I noticed some really weird stuff coming out of GQRX.
For some odd reason the setSampleRate()
function in GQRX is always called twice; first with the default Sample Rate of 2Msps and secondly with the actual Sample Rate in the menu (unless it is already 2Msps). This correctly sets the bwEnum
value using the function getBwEnumForRate()
.
The next thing I observed was that if the Bandwidth = 0.0MHz in the menu then setBandwidth()
was called twice, first with a bw_in
value = (SR-(SR/4)) which proceeds to set the wrong bwEnum
value because of the -(SR/4) factor and secondly with the bw_in
value = 0.0. This is not valid and so results in a 200kHz bandwidth. Very strange behaviour. The bw_in=(SR-(SR/4))
is obviously coming from GQRX. It is not observable in GNURadio.
If the Bandwidth value in the menu is a valid value then the setBandwidth()
is only called once and the bwEnum
is set correctly. If the Bandwidth is not a valid value then bwEnum
is set to 200 (ie 200kHz).
I am not sure if you have noticed this behaviour.
GNURadio on the other hand is much simpler. It calls both setSampleRate()
and setBandwidth()
once and sets the value appropriatly. If the Bandwidth = 0.0Mhz it sets the bwEnum
= 200 (ie 200kHz). You can change Sample Rates and Bandwidths on the fly here and it just calls the appropriate function once. I might add I am not sure if that is good practice, but it seems to work fine.
I have played with the Settings.cpp code to make it a bit more foolproof with the only area that is still not resolved in GQRX is the Bandwidth = 0.0MHz. It sets an incorrect value due to the odd calculation of the bw_in
on the first pass.
I will have a look at your refactored code and run it up to see if it does what I expect.
I might also add I have never used CubicSDR, but have heard it mentioned plenty of times. I guess I am used to the tight integration between GQRX and GPredict for satellite work. I actually use SDR-Console on Windows for most of my satellite voice comms. That is a great program. I am trying to develop a setup for digital satellite work and experimentation using Linux…..hence getting the RSPdx working.
Thanks for your efforts on this.
John – VK4JBE
John, whe I ran gqrx this morning I too noticed the call to setBandwidth()
with the bw_in
argument = 75% of the sample rate:
[INFO] setBandwidth() - bw_in=1500000.000000 bwType=600
[INFO] setBandwidth() - bw_in=0.000000 bwType=1536
Since gqrx uses the GNU Radio OOT module gr-osmocom to talk to SoapySDR and therefore to this module SoapySDRplay3, I suspect that that 75% comes from this line (https://github.com/osmocom/gr-osmosdr/blob/master/lib/soapy/soapy_source_c.cc#L326):
set_bandwidth(get_sample_rate() * 0.75, chan); /* select narrower filters to prevent aliasing */
Also since 0 as a bandwidth selection does not make much sense per-se (an ideal filter with a bandwidth = 0Hz wouldn't let any signal through), I think it is OK to accept that that specific value actually means "set the bandwidth to a reasonable default value", as gqrx seems to expect (but I need to double check that other programs like CubicSDR don't make different assumptions for that value).
Franco K4VZ
@Franco I have tested your latest new branch and it is giving the bandwidth settings you would expect in both GNURadio and GQRX for all combinations of sample rate and bandwidth. Perfect. Thank you.
I had played with trying to use the existing bwEnum
setting when the bandwidth = 0.0MHz (ie don’t update bwEnum
) and it was fine in GNURadio but GQRX was still problematic. I had concluded that we needed to go and get the sample rate when the BW = 0.0MHz and substitute that. Your coding to do that is very neat. I was not familiar with that c construct previously …..but then I am not a c programmer.…… Actually I have learned a lot through this process.
Your SoapySDR_logf()
statement on the setBandwidth()
function shows GQRX calculating that odd bw_in = (SR-(SR/4))
and using it to calculate the wrong bwEnum
, but the second call to setBandwidth()
with the new algorithm fixes it. If you had a similar statement in setSampleRate()
you would see the double setting there with a 2Msps sample rate first and then the correct sample rate.
I am not sure if leaving the log statement in will confuse GQRX users and cause questions or not. Perhaps it might be more instructive if it showed the Sample Rate and the Bandwidth. I am happy to see you merge that into the main/master branch. One last thing, it may well be worth adding something into the wiki to explain the standard IF Bandwidth settings (and perhaps the preferred Sample Rate settings).
Thanks for all your work on this.
John – VK4JBE
Franco. That explains the weird bw_in
setting. Makes sense in a certain context.
John - VK4JBE
John, I just removed that log statement; since I didn't know know you already had done something similar, I added it temporarily to show you what happens.
As per SoapySDRPlay3, since it is a general purpose module that can be used by many different SDR applications in the context of the SoapySDR framework, it is sometimes difficult for me to 'forecast' how an application will be using a method like setBandwidth()
; the comments in the SoapySDR include file Device.hpp (https://github.com/pothosware/SoapySDR/blob/master/include/SoapySDR/Device.hpp) are more or less what I refer to as the 'standard' for what a given method should do, but they don't cover corner cases like this one.
On the other side, it is also hard if not impossible for a client application like gr-osmosdr to know the best thing to do; for instance the author of gr-osmosdr had the good intention of making the bandwidth a little less of the sample rate to prevent aliasing problems; they didn't know/realize that in the specific case of the SDRplay RSPs the selectable bandwidths are only a limited set of values, and in the case of a sample rate of 2Msps, 75% of that is 1500kHz, and the setBandwidth()
function ended up with an actual bandwidth of 600kHz; had they used a slightly higher percentage, for instance 77%, then setBandwidth()
would have set the bandwidth at 1536kHz, which is a much better value for that sample rate.
I plan to run some tests with CubicSDR tonight after work; if everything works OK, then I'll merge these changes into the master
branch. As per the Wiki, it is not part of the actual code I commit and push; I know there's a way to update it (I made an update a while ago; I just have to remember how I did it).
Franco K4VZ
Franco, I am happy to test the master
when you upload that.
If I am reading this right it seems like updating the wiki is really just an update to the README.md file with the appropriate markup (or is it markdown) for formatting. Can it be that simple!!
John - VK4JBE
John, good news; it looks like in CubiCSDR the method setBandwidth()
is currently only called for a specific device, the bladrRF (https://github.com/cjcliffe/CubicSDR/blob/master/src/sdr/SoapySDRThread.cpp#L487-L489):
if (device->getDriverKey() == "bladeRF") {
device->setBandwidth(SOAPY_SDR_RX, 0, sampleRate.load());
}
so these changes to setBandwidth()
do not affect CubicSDR.
I just merged the use-getBwEnumForRate
branch into master
; please give it a try, and let me know how if you see any problems.
Franco K4VZ
Will do Franco.
Edit: Just downloaded the new SoapySDRPlay3 from master. Install worked fine. Running GNURadio and GQRX with a variety of combinations of Sample Rate and Bandwidth including bandwidth = 0.0MHz and non-standard values (ie 3Mhz) as well as standard values (300kHz, etc) and it all seems to be working as expected.
Great work.
John - VK4JBE
People,
I am wondering of someone can help me with my SoapySDR / SDRPlay3 / SDRPlay RSPdx install. I have successfully installed the SDRPlay 3.07 API, Ryan Volz's radioconda and compiled the pothosware SoapySDRPlay3 0.8 library on a Ubuntu 22.04 system. The SDR is receiving signals fine with both GQRX and GNURadio but the bandwidth seems stuck on 200kHz and the device seems to be stuck in AGC = on mode.
Looking at the pothosware/SoapySDRPlay3 github site I have checked out the SoapySDRPlay.hpp and settings.cpp files and it appears from the comments that the default bandwidth is 200khz (although I can't actually see where this is set in code). The code to change that is in internal functions that appear to be part of the Sample Rate API in the settings.cpp.
I have also noticed that the I get a "Not updating IFGR gain because AGC is enabled" warning when I try to change the IFGR in GQRX. Once again AGC = on seems to be the default. In GQRX the AGC flag is not ticked but the error still occurs.
I have been digging through the c++ source code to see if I can figure it out but unfortunately I am not familiar enough with c++ to debug this stuff.
I am wondering if anybody else has noticed this and has a fix or has enough familiarity with the code to track the issue through.
John - VK4JBE