pothosware / SoapySDRPlay3

Soapy SDR plugin for SDRPlay APIv3
https://github.com/pothosware/SoapySDRPlay3/wiki
MIT License
90 stars 15 forks source link

Are RSP1A parameters for the SoapySDR function calls documented anywhere? #69

Open w0dz opened 1 year ago

w0dz commented 1 year ago

I have written my own Python code using SoapySDR to talk to an RSP1A, but figuring out what the parameters are has been a real problem. The SoapySDR docs show all the high level function calls, but the specifics are up to the driver. And the SoapySDR docs say "they're the same as the C calls except for the two notations below, so go look at the header file." That's not very helpful, since the actual Python parameters passed into the functions are not described anywhere. I had to guess, for example, that the setGain function wanted "IFGR" or "RFGR" for the two gain reduction parameters. And only by some severe poking around did I learn that that overloaded function works differently if you use the short form without a parameter name. And what about AGC response times for attack and decay, and AGC threshold? Where do they go? And how long do I have to wait for these commands to "take"? Pretty hard to use an API when it's not documented anywhere.

fventuri commented 1 year ago

@w0dz - first of all I am really sorry to hear that you are having problems using this SoapySDRPlay3 module with Python.

The SoapySDRPlay3 module is an attempt to provide an interface between the SDRplay APIs (whose specification guide you can find here: https://www.sdrplay.com/docs/SDRplay_API_Specification_v3.07.pdf), and the SoapySDR Device API (which is described here: https://github.com/pothosware/SoapySDR/blob/master/include/SoapySDR/Device.hpp). As such it tries to find a trade-off between the complexity of the SDRplay API and the design of SoapySDR. In some cases, like the specific parameters for the AGC that you mention, I decided to use SDRplay defaults since they seemed reasonable to me, and there's not really an obvious way to select them via the SoapySDR API (perhaps using the writeSettings() method?).

This said, here are a few notes that I hope you'll find useful:

Hope this helps.

73, Franco K4VZ

w0dz commented 1 year ago

HI Franco, I want to be able to set the AGC time constant to slow, medium or fast based on mode (fast for CW, medium for SSB, slow for AM) and the AGC Threshold. From what you are saying, SoapySDR apparently doesn't let me do this. There's no way the SDR could know what mode I am using since that is determined after reading in the buffer, demodulating and filtering. So there needs to be a way to access the register that lets me set that. Can you tell me more about "writeSettings", as maybe this is how to do it? Specifically, I need access to this structure:

typedef struct { sdrplay_api_AgcControlT enable; // default: sdrplay_api_AGC_50HZ int setPoint_dBfs; // default: -60 unsigned short attack_ms; // default: 0 unsigned short decay_ms; // default: 0 unsigned short decay_delay_ms; // default: 0 unsigned short decay_threshold_dB; // default: 0 int syncUpdate; // default: 0 } sdrplay_api_AgcT;

fventuri commented 1 year ago

Since SoapySDR aims to be a general purpose interface for all sorts of SDRs and the designers of the SoapySDR API couldn't foresee all the possible configuration settings, they introduced the Settings API (https://github.com/pothosware/SoapySDR/blob/master/include/SoapySDR/Device.hpp#L1204-L1310), which is the catch-all API for those parameters that do not naturally fit elsewhere, like the specific settings for the SDRplay AGC. For instance the writeSettings() method has this description:

     * Write an arbitrary setting on the device.
     * The interpretation is up the implementation.

You can list the available settings using the method getSettingInfo().

What you could do is to follow the code that is already there for the AGC set point (https://github.com/pothosware/SoapySDRPlay3/blob/master/Settings.cpp#L1425-L1432), and add similar blocks for all the other settings you would like to control. If you were to decide to do that, there are three methods that would need to be changed:

Franco

w0dz commented 1 year ago

I guess what I'm really asking is if the Python API has a hook in it to allow writes to the registers. I would rather not edit your C code and thus have a custom version.

Brian

fventuri commented 1 year ago

Brian, my bad, I misunderstood your earlier question about writeSetting().

The way SoapySDR provides a Python API is by 'Python bindings', courtesy of SWIG (https://github.com/pothosware/SoapySDR/wiki/PythonSupport). SWIG is used to (almost) automatically generate a Python 'interface' from the C/C++ header files that describe the classes, methods, arguments, etc of SoapySDR. This means that these bindings 'expose' a Python module that is almost exactly what the C/C++ library is (with a few minor differences because of the way Python works, described in the last section of the Wiki page I linked above).

In other words if something exists in SoapySDR C/C++ API, then it exists in Python, but if it is not the C/C++ API, it is not in the Python bindings either.

I hope this helps, Franco

w0dz commented 1 year ago

OK, but I can't FIND the Python bindings! I can find a list of functions, none of which have the parameters, and I had to hunt for literally days to find examples that had a hint of what I wanted for the other stuff (such as "IFGR" and "RFGR" for the parameters in the setGain function. Where is such a document?

Brian

fventuri commented 1 year ago

To clarify what I wrote above, Python bindings are just a mechanism to translate from the Python function calling convention (for instance almost everything in Python is a PyObject) to the C/C++ calling convention; say for instance a C++ function expects a string as one of its arguments, then the Python bindings take care of extracting the string from the PyObject, and passing it to the C++ function underneath. Similarly they take care of wrapping the return value from the C/C++ function into another PyObject, to make Python happy.

Coming to your question about the name of the gains, as I said at the beginning of this discussion, the SoapySDR API (C/C++ or Python; it's the same) provides the method listGains() that returns those gain names. As a matter of fact the very example provided in the Python Support Wiki page (https://github.com/pothosware/SoapySDR/wiki/PythonSupport#basic-example) has this piece of code:

#query device info
print(sdr.listAntennas(SOAPY_SDR_RX, 0))
print(sdr.listGains(SOAPY_SDR_RX, 0))
freqs = sdr.getFrequencyRange(SOAPY_SDR_RX, 0)
for freqRange in freqs: print(freqRange)

where they show how to get all the info you need from the device.

Regarding how say RFGR works, then we are entering in the specific details of the SDRplay RSP hardware and API - for instance in this case the way to go from RFGR to actual gain reduction is via some gain reduction tables that are in chapter 5 (page 38) of the SDRplay API Specification Guide (https://www.sdrplay.com/docs/SDRplay_API_Specification_v3.07.pdf).

Franco

w0dz commented 1 year ago

I know all about the gain tables. I cannot find a one-one mapping of SoapySDR calls to those of the RSP1A. For example, please show me how I would use SoapySDR to set the AGC threshold to -60dBm. Or the attack or decay times. Those are settable in C, but I can't find any such reference in Python.

Brian

fventuri commented 1 year ago

Brian, since the setting agc_setpoint is available in writeSetting(), you can set it to say -30 by writing something like this in Python:

sdr.writeSetting('agc_setpoint', -30)

The exact line where that value gets assigned to the structure you mentioned earlier is this one (https://github.com/pothosware/SoapySDRPlay3/blob/master/Settings.cpp#L1427):

      chParams->ctrlParams.agc.setPoint_dBfs = stoi(value);

For the other parameters, like attack and decay, they are not implemented in writeSettings(), but you could replicate the code used for 'agc_setpoint' for them.

Franco

w0dz commented 1 year ago

Thanks Franco! You've been a big help. I really appreciate the fast response and detailed info. One other question - in order to add the attack and decay settings, don't I have to edit and recompile your SoapySDRPlay code? I don't think I have everything I need to do that.

Brian

fventuri commented 1 year ago

Brian, glad to help!

The steps to build SoapySDRPlay from source and install it are very simple, and you can find them in the Wiki here: https://github.com/pothosware/SoapySDRPlay3/wiki#building-soapy-sdr-play

The part that could be a little tricky is to make SoapySDR (and all the applications that use it like SoapySDRUtil) can see and use the version you built from source, not the current one (I imagine you use the one that comes by default with your Linux distribution, but I am not sure).

One way to validate that is, before you make any other changes to the code, add a statement like this right before line 1799 in the source file Settings.cpp (https://github.com/pothosware/SoapySDRPlay3/blob/master/Settings.cpp#L1799):

    SoapySDR_log(SOAPY_SDR_INFO, "W0DZ version");

and then after building and installing your own version, run say SoapySDRUtil --probe="deriver=sdrplay" (see here: https://github.com/pothosware/SoapySDRPlay3/wiki#probing-soapy-sdr-play) to make sure you do see the line 'W0DZ version' on the terminal.

Once you see that message, then you should have a good grasp of the whole process, and adding that additional code for the other AGC settings should be pretty straightforward.

Franco

w0dz commented 1 year ago

Actually, now that I recall, I did compile the code. At least I see it on the machine. I had to build a new OS image from scratch, so I rebuilt pretty much everything. So I will have to experiment. Odd not to have the slow/medium/fast stuff in Python. You might consider adding it at some point.

fventuri commented 1 year ago

If I remember correctly, the fact that only agc_setpoint is available in writeSetting() is for historical reasons; this module SoapySDRPlay3 started as just fixes to make the previous version (SDRPlay2 - https://github.com/pothosware/SoapySDRPlay2) work with the new version (3.X) of the SDRplay API. Since that original version had only the control for agc_setpoint, I just carried that over to the new version without thinking much of it.

Now that I am starting to become more familiar with the way AGC works in the SDRplay API, I see that they have three predefined settings: 5Hz (slow), 50Hz (medium), and 100Hz (fast), so perhaps it makes more sense to replace that agc_setpoint control with another control called say agc_speed (or something like that) that can be either 5Hz (or 200ms), 50Hz (or 20ms), or 100Hz (or 10ms), similar to what I think you were proposing (correct me if I misunderstood you).

Franco

w0dz commented 1 year ago

Hi Franco,

The 5/50/100 is the loop bandwidth, not the AGC speed, and I doubt if it does all that much. The “decay” parameter is the one that sets the slow/medium/fast setting. The “setpoint” is in that same structure. I wouldn’t change the setpoint var, but I would add the others – attack, decay, delay, etc. See below (AGC Control Parameters Structure).

I do wonder if the AGC True/False setting should handle all the enumerated types in the LoopBW, since the first setting is AGC Disable and all the others are settings within the “enable” function (I think). I don’t understand how those two structures play with each other.

Brian

From: Franco Venturi @.> Sent: Monday, May 1, 2023 7:59 PM To: pothosware/SoapySDRPlay3 @.> Cc: w0dz @.>; Mention @.> Subject: Re: [pothosware/SoapySDRPlay3] Are RSP1A parameters for the SoapySDR function calls documented anywhere? (Issue #69)

If I remember correctly, the fact that only agc_setpoint is available in writeSetting() is for historical reasons; this module SoapySDRPlay3 started as just fixes to make the previous version (SDRPlay2 - https://github.com/pothosware/SoapySDRPlay2) work with the new version (3.X) of the SDRplay API. Since that original version had only the control for agc_setpoint, I just carried that over to the new version without thinking much of it.

Now that I am starting to become more familiar with the way AGC works in the SDRplay API, I see that they have three predefined settings: 5Hz (slow), 50Hz (medium), and 100Hz (fast), so perhaps it makes more sense to replace that agc_setpoint control with another control called say agc_speed (or something like that) that can be either 5Hz (or 200ms), 50Hz (or 20ms), or 100Hz (or 10ms), similar to what I think you were proposing (correct me if I misunderstood you).

Franco

— Reply to this email directly, https://github.com/pothosware/SoapySDRPlay3/issues/69#issuecomment-1530764854 view it on GitHub, or https://github.com/notifications/unsubscribe-auth/AELAMGQMMSA7QWWQMUHLFPDXEBS7ZANCNFSM6AAAAAAXMYA6RU unsubscribe. You are receiving this because you were mentioned. https://github.com/notifications/beacon/AELAMGQWGLXYISEUJJYG673XEBS7ZA5CNFSM6AAAAAAXMYA6RWWGG33NNVSW45C7OR4XAZNMJFZXG5LFINXW23LFNZ2KUY3PNVWWK3TUL5UWJTS3HWPDM.gif Message ID: < @.> @.>

fventuri commented 1 year ago

Brian, as far as I know a good document on how the AGC implemented by SDRplay works (or used to work) is this reference note from 2015: https://www.sdrplay.com/docs/SDRplay_AGC_technote_r2p2.pdf - unfortunately I was not able to find in it mentions of the various parameters regarding the speed of the AGC response (attack, decay, decay delay, etc).

The SDRuno User Manual (https://www.sdrplay.com/docs/SDRplay_SDRuno_User_Manual.pdf) on page 63 has the following section:

SDRuno 1.3 saw the introduction of an updated API with an improved IF AGC scheme. This has more configuration and allows you to better condition the IF AGC to their signal environment. Further improvements to better align the gain change with the correct point in the IQ stream has also helped to remove the bouncing effect that was seen in previous versions

Attack ms - Time taken for the AGC to reach 95% of the target value after in increase in the signal power Decay ms - Time taken for the AGC to reach 95% of the target value after a reduction in the signal power Decay Delay ms - Amount by which the power level has to fall before the decay delay timer is activated Decay Threshold (dB) - Time after the power levels has reduced by an amount ≥ to the decay threshold, before the AGC loop starts the decay process. Tuner IF AGC Setpoint (dBfs) - Sets the target level power at which AGC routine will attempt adjust the power on the ADC input. A larger value will position the signal near the top of the ADC range. A lower value will reduce the signal power and hence levels at the ADC input.

I also found this morning this piece of code in the RSPTCPServer in the SDRplay GitHub repository (https://github.com/SDRplay/RSPTCPServer/blob/master/rsp_tcp.c#L908-L912), where they set those parameters to the same time constants shown in the picture in the SDRuno manual.

I think you are right that it may make more sense to have instead a setting called say agc_settings (instead of just agc_setpoint), where the user could pass a comma separated list of setpoint,attack,decay,decay_delay,decay_threshold so they can all be controlled.

Given that initial sentence in the SDRuno user manual about an "improved IF AGC scheme", it is perhaps possible that they kept the old way of controlling the loop bandwidth just as a legacy, and we are now supposed to use sdrplay_api_AGC_CTRL_EN and set the appropriate parameters. Just a wild guess.

Franco

fventuri commented 1 year ago

Good news Brian! It looks like the upcoming version of SoapySDR (version 0.9) will have a page with Python documentation and online documentation for all APIs (see announcement here: https://github.com/pothosware/SoapySDR/issues/403).

Franco

w0dz commented 1 year ago

Awesome! Thanks!

Brian

From: Franco Venturi @.> Sent: Monday, May 8, 2023 7:20 AM To: pothosware/SoapySDRPlay3 @.> Cc: w0dz @.>; Mention @.> Subject: Re: [pothosware/SoapySDRPlay3] Are RSP1A parameters for the SoapySDR function calls documented anywhere? (Issue #69)

Good news Brian! It looks like the upcoming version of SoapySDR (version 0.9) will have a page with Python documentation and online documentation for all APIs (see announcement here: pothosware/SoapySDR#403 https://github.com/pothosware/SoapySDR/issues/403 ).

Franco

— Reply to this email directly, view it on GitHub https://github.com/pothosware/SoapySDRPlay3/issues/69#issuecomment-1538351570 , or unsubscribe https://github.com/notifications/unsubscribe-auth/AELAMGWDOK3UXEXRYP4E433XFDXJXANCNFSM6AAAAAAXMYA6RU . You are receiving this because you were mentioned. https://github.com/notifications/beacon/AELAMGQUJQ6KAFFOCWN44MTXFDXJXA5CNFSM6AAAAAAXMYA6RWWGG33NNVSW45C7OR4XAZNMJFZXG5LFINXW23LFNZ2KUY3PNVWWK3TUL5UWJTS3WFQ5E.gif Message ID: @. @.> >