Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overriding default setGain() function #55

Closed
luarvique opened this issue Aug 27, 2022 · 12 comments
Closed

Overriding default setGain() function #55

luarvique opened this issue Aug 27, 2022 · 12 comments

Comments

@luarvique
Copy link

Hello, Franco!

While trying to make an RSP device work with OpenWebRX, I have found that the single-value gain setting essentially drives Soapy crazy on RSP.

Further investigation has shown that the default setGain() method in Soapy tries approximating requested gain with multiple stage gains. Since RSP stage gains are essentially negative, and the RFGR value isn't even meadured in decibels, the whole setGain() thing fails rather miserably.

Because of that, I would like to ask you to override the default setGain() in SoapySDRPlay3 with implementation that ONLY sets IFGR to the requested value. This should at least sort out some confusion.

I have pending OpenWebRX changes to have separate RFGR and IFGR settings for RSP, with AUTO only affecting IFGR, as it does in hardware

@jketterl
Copy link

OK so here we go again.

I repeat that I do not support the suggested solution. The method SoapySDR::Device::setGain(const int dir, const size_t channel, double gain) (the version that does not target a gain stage specifically) should reproducibly set a gain for all stages and not completely ignore the RFGR stage, as suggested.

Further, the rfgain_sel parameter should be deprecated and and its functionality should be made available through the regular SoapySDR gain APIs so that the gain management of SDRPlay devices is in line with other manufacturers. If necessary, the SoapySDR API should be changed to include any hardware abilities that cannot be modeled correctly as of now.

@luarvique
Copy link
Author

Jakob, this is not going to happen. SDRPlay does not owe any of us anything and cannot change existing hardware, so the word "should" you are using is misplaced here. It cannot be fixed the way you are describing, just worked around.

The best I can do for you is TRY to create setGain() that kinda sorta approximates what it "should" do and try to persuade Franco into merging it. But even this attempt will not fix the fact that AGC only applies to IFGR in RSPs.

@jketterl
Copy link

You should read again. In no way did I ask for the hardware to be changed.

@luarvique
Copy link
Author

You asked to implement a behavior that cannot be implemented within this specific hardware architecture and repeatedly refused to settle for a workaround. I can add two and two, thank you.

@jketterl
Copy link

jketterl commented Aug 27, 2022

You mean, because I am asking to include the RFGR stage in the setGain() method? I believe the influence of the individual RFGR steps should be well known, so implementing a method that looks up values in a table to translate between decibels and RFGR should not be that hard to implement.

Just in case you didn't know, the same is done for RTL-SDR devices, see for example: https://github.com/osmocom/rtl-sdr/blob/master/src/tuner_r82xx.c#L940-L1020

@luarvique
Copy link
Author

First of all, the influence of individual RFGR steps is not well known. These steps differ between RSP models, they are not in decibels, and even SDRPlay themselves are not calling them "gain". This value is known as "lna_state" in their API.

Secondly, the AGC in RSPs only affects the IFGR (second stage) and mainly serves to prevent numeric overload of the ADC. With the overall gain setting implemented the way you like, it becomes impossible to define what AGC is, since it does not take RFGR gain into account.

Thus, as I have mentioned previously, it makes total sense to consider IFGR the only proper gain setting in RSPs, while keeping RFGR as a separate value, kind of like a multi-level BiasT switch. May not be pretty, but makes sense.

@jketterl
Copy link

First of all, the influence of individual RFGR steps is not well known. These steps differ between RSP models, they are not in decibels, and even SDRPlay themselves are not calling them "gain". This value is known as "lna_state" in their API.

They should be known. As far as I know, SDRPlay devices are calibrated and SDRUno is capable of displaying a calibrated S-Meter based on that information.

Even if (to my surprise) this information is not available, it should be obtainable by measurement.

Secondly, the AGC in RSPs only affects the IFGR (second stage) and mainly serves to prevent numeric overload of the ADC. With the overall gain setting implemented the way you like, it becomes impossible to define what AGC is, since it does not take RFGR gain into account.

The overall gain setting via setGain() as requested does not involve any AGC. Calling this method while the AGC is on should typically have no effect.

Assuming the RFGR stage does not have an AGC, the correct way to implement this would be to change the API in a way that allows AGC to be switched on or off on the individual stages instead of globally. With that change, the user would have the ability to change gain on the RFGR stage (via the existing targeted SoapySDR::Device::setGain(const int direction, const size_t channel, const std::string &name, const double value) call) while putting the IFGR stage into AGC.

Also, the device query should, in addition to the stage gain ranges, report whether or not a gain stage has AGC capabilities. The device can choose if it offers a global AGC switch and should report accordingly.

Thus, as I have mentioned previously, it makes total sense to consider IFGR the only proper gain setting in RSPs, while keeping RFGR as a separate value, kind of like a multi-level BiasT switch. May not be pretty, but makes sense.

I'm sorry, but it doesn't make sense. It only fuels further confusion by having a setting that influences the device gain but is semantically placed outside of the gain APIs.

@luarvique
Copy link
Author

luarvique commented Aug 27, 2022

They should be known. As far as I know, SDRPlay devices are calibrated and SDRUno is capable of displaying a calibrated S-Meter based on that information.

Well, SDRPlay does provide some approximate values in their documentation, at least for some devices, but I would not count on them. Thus, "they should" reflects your personal opunion, rather than reality.

Even if (to my surprise) this information is not available, it should be obtainable by measurement.

You are not suggesting that each user should measure his device, are you?

The overall gain setting via setGain() as requested does not involve any AGC. Calling this method while the AGC is on should typically have no effect.

Having manual gain set is semantically opposite to the variable gain implied by the AGC. So, these two settings are linked. In fact, they are shown linked in the OpenWebRX UI, aren't they?

Assuming the RFGR stage does not have an AGC, the correct way to implement this would be to change the API in a way that allows AGC to be switched on or off on the individual stages instead of globally.

Go ahead and change it then. I've actually tried, and just the changes to the OpenWebRX UI will be drastic.

I'm sorry, but it doesn't make sense. It only fuels further confusion by having a setting that influences the device gain but is semantically placed outside of the gain APIs.

Well, BiasT also controls gain for many people, but nobody suggests having it as part of gain APIs.

Anyways, I am making this change request to Franco, not to you, Jakob, since Franco maintains this repository. There is a thread in the OpenWebRX forum, if you would like to continue discussing what SDRPlay and Soapy should do to their APIs (something I have no control of, BTW).

@jketterl
Copy link

Well, SDRPlay does provide some approximate values in their documentation, at least for some devices, but I would not count on them. Thus, "they should" reflects your personal opunion, rather than reality.

It's not an opinion, it's a logical conclusion.

You are not suggesting that each user should measure his device, are you?

No, even though that may be the only way to have a deterministic outcome.

The values for the RTL-SDR I linked to earlier have been measured at some point and they are by no means representative, yet they work for most users and I have not seen them being questioned.

Having manual gain set is semantically opposite to the variable gain implied by the AGC. So, these two settings are linked. In fact, they are shown linked in the OpenWebRX UI, aren't they?

In the GUI, you have to decide between AGC and manual because the AGC setting is a global device setting, so it is implied that there is no manual gain control while the AGC is enabled.

In the API, there is no restrictions as to what methods are available at which time, so the behaviour of calling a method may be unexpected, there may be no effect, or you may end up in an error.

The underlying assumption is that while a hardware gain is in automatic mode, it cannot at the same time be set manually and vice versa. This assumption is too generic for this case since there is multiple gain stages that can be individually set into automatic mode. This is currently not properly represented in the SoapySDR API since there is only one global AGC switch, hence the call to change the API to support this capability.

Go ahead and change it then. I've actually tried, and just the changes to the OpenWebRX UI will be drastic.

Just because you couldn't do it doesn't mean it can't be done.

Well, BiasT also controls gain for many people, but nobody suggests having it as part of gain APIs.

It's not properly modeled because it's not part of the hardware. Not a good solution either, but since the hardware only supplies the voltage it's impossible to infer the results here.

Anyways, I am making this change request to Franco, not to you, Jakob, since Franco maintains this repository. There is a thread in the OpenWebRX forum, if you would like to continue discussing what SDRPlay and Soapy should do to their APIs (something I have no control of, BTW).

You backed this issue with "pending OpenWebRX changes". As the developer of OpenWebRX, I felt it was necessary for me to make clear that the requested changes merely represent your way of solving the problem, whereas OpenWebRX would prefer a different approach. Also, I don't think that discussion here is restricted in any way, so I will continue to express my opinion whenever I feel appropriate.

@luarvique
Copy link
Author

luarvique commented Aug 27, 2022

You backed this issue with "pending OpenWebRX changes". As the developer of OpenWebRX, I felt it was necessary for me to make clear that the requested changes merely represent your way of solving the problem, whereas OpenWebRX would prefer a different approach. Also, I don't think that discussion here is restricted in any way, so I will continue to express my opinion whenever I feel appropriate.

So, I am resolving the issue with the inconsistent setGain() behavior in SoaptSDRPlay3 separately from the issue with incorrect representation of the same gains in OpenWebRX. Two issues, two projects, two maintainers, two separate discussions.

Also, I have all the suggested changes implemented locally and they appear to work pretty well. I now have comprehensible control of gains in my receiver, same as offered by SDRuno, ExtIO, and other software.

@fventuri
Copy link
Collaborator

First of all thanks for your comments @luarvique and @jketterl

As you may already know, we have another issue currently open here (#35) about different approaches to handle gain controls for SDRplay RSP devices under SoapySDR. If you look at the discussion there we are evaluating a few options each with its own pros and cons.

SoapySDR is more or less an abstraction layer for a SDR transceiver device and, as far as I know, its specification is defined here: https://github.com/pothosware/SoapySDR/blob/master/include/SoapySDR/Device.hpp.

Being a general purpose interface it has some limitations when it comes to mapping to a specific hardware; a good example is this comment by Vincent Sonnier (pothosware/SoapySDRPlay2#62 (comment)), when we initially started working on integrating the new SDRplay API 3.X into SoapySDR:

I suppose that if we want to plug the square of RSP into the round of a Soapy module, we must cut corners eventually.

The other important factor to keep in mind is that SoapySDR (and hence this module SoapySDRPlay3) is used by many SDR applications, like CubicSDR, GNU Radio gr-soapy block, and not least OpenWebRX. This means that any major change to the way the different functions (including setGain()) work needs to be carefully evaluated to make it doesn't 'break' something somewhere.

One of the takeaways from the discussion in the 'New gain controls' issue seems that there's not a unified consensus on the 'One And True Gain', but different people have different opinions. @nmaster2042 suggested there (#35 (comment)) to introduce in the device selection string an additional parameter called say 'gain_control_mode', which would allow the user to select their favorite 'gain model' (I can't find a better term to define this concept).
I personally think this could offer a path forward: if the user doesn't specify it in the device connection string, it would default to what I call the 'legacy' gain model, i.e. it would work exactly like it is now (with all its goodness and badness), so the current users wouldn't be 'surprised' by a different behavior; other 'gain models' could be made available like the 'DB' one, and perhaps one that the OpenWebRX users could find useful.
I know the discussion in the other issue has been stale since April 17, but I have been busy with work and also on a couple of other SDR related projects (adding support for SDRplay devices to ka9q-radio and Linrad), but since those other projects are now winding down, it is probably time for me to go back to this issue.

A couple more notes and then I am done (I apologize for this long comment).

Typically when I am in doubt on something about the RSPs I use SDRplay program SDRuno as the reference on what to do (or at least the source of inspiration): in the case of RSP gains/gain reductions, I think SDRplay suggests the users to enable AGC for the IF stage and for the most part use the RF gain reduction/LNA state to control the overall gain - perhaps an approach like SDRuno would help in this use case.

Secondly SDRplay does have a set of 'Gain Reduction Tables' in Section 5 of their 'Software Defined Radio API' (https://www.sdrplay.com/docs/SDRplay_API_Specification_v3.07.pdf) that map the actual RF gain reduction from the LNA state, frequency band, antenna type, etc - I do use them for this kind of conversions in several cases ('DB' mode in the 'new gain controls' code, or in the GNU Radio 'gr-sdrplay3' OOT module, or in the new code I recently wrote for ka9q-radio and for Linrad); these values though are not calibrated values; as far as I know the only such values that SDRplay has published are those in the 'RSPduo Detailed Technical Information' document (https://www.sdrplay.com/wp-content/uploads/2018/06/RSPDuo-Technical-Information-R1P1.pdf), where starting from slide 5 they provide those accurate measurements; you'll notice there that a change of a few MHz can affect the gain reduction, and therefore I am not sure what would be the best way to incorporate them in a 'gain model' (given also the fact they don't seem to be available for other models, like the new RSPdx).

Franco

@luarvique
Copy link
Author

I suppose that if we want to plug the square of RSP into the round of a Soapy module, we must cut corners eventually.

This is definitely true.

The other important factor to keep in mind is that SoapySDR (and hence this module SoapySDRPlay3) is used by many SDR applications, like CubicSDR, GNU Radio gr-soapy block, and not least OpenWebRX. This means that any major change to the way the different functions (including setGain()) work needs to be carefully evaluated to make it doesn't 'break' something somewhere.

The current (non RSP-specific) setGain() implementation appears to be so broken for the RSPs, that replacing it with ANY reasonable RSP-specific implementation will only improve things for everybody. There is nothing to salvage there, it just acts wrong.

One of the takeaways from the discussion in the 'New gain controls' issue seems that there's not a unified consensus on the 'One And True Gain', but different people have different opinions.

There are two controls in SDRPlay, often called gains, but they are in fact attenuation controls, not true gains. Also, only one of these controls (IFGR) is measured in decibels. The other control (RFGR) is in artificial units which change with device and operating frequency. Hence is my suggestion to assume IFGR for setGain() method, at least for now. While it may not be One and True Gain, defaulting setGain() to it will at least sanitize things a little bit. The RFGR is kept as a device-specific parameter, with the default of 0.

@nmaster2042 suggested there (#35 (comment)) to introduce in the device selection string an additional parameter called say 'gain_control_mode', which would allow the user to select their favorite 'gain model'

This is more along the lines of letting all flowers bloom. Personally, I do not have any issue with this concept.

if the user doesn't specify it in the device connection string, it would default to what I call the 'legacy' gain model, i.e. it would work exactly like it is now (with all its goodness and badness), so the current users wouldn't be 'surprised' by a different behavior;

Not sure if the current behavior is useful for anyone, but if someone is hellbent on keeping it, then why not? Just provide a way to disable it, please.

Typically when I am in doubt on something about the RSPs I use SDRplay program SDRuno as the reference on what to do (or at least the source of inspiration): in the case of RSP gains/gain reductions, I think SDRplay suggests the users to enable AGC for the IF stage and for the most part use the RF gain reduction/LNA state to control the overall gain - perhaps an approach like SDRuno would help in this use case.

I know that SDRuno insists on keeping IFGR in the AGC mode and this does make sense for most use cases. The problem here is that this method does not map into Soapy's definition of gain: the RFGR is measured in funny units and does not allow for AGC. Honestly, neither of these values is real gain, but IFGR behaves more like gain. Most people will leave it at AUTO and adjust device-specific RFGR value for each band though, same as they do in SDRuno.

Secondly SDRplay does have a set of 'Gain Reduction Tables' in Section 5 of their 'Software Defined Radio API' (https://www.sdrplay.com/docs/SDRplay_API_Specification_v3.07.pdf) that map the actual RF gain reduction from the LNA state, frequency band, antenna type, etc

Yeah, these can also be found in most individual RSP device datasheets. Rather than simplifying gain calculation though, they just show that the RFGR value cannot be trusted for calculating gain.

These values are not entirely random though, especially if you look at the deltas rather than absolute values. Generally, the RFGR "step" differs depending on the frequency band, which can be explained by the fact that the MSI001 chip inside RSP has multiple LNAs, with separate inputs, connected to separate filters. I would assume that different RFGR steps correspond to different MSI001 LNA inputs.

PS: If you ever wondered why some Chinese RSP clones come with multiple SMA input connectors, that is why.

@luarvique luarvique closed this as not planned Won't fix, can't repro, duplicate, stale Dec 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants