pothosware / SoapyPlutoSDR

Soapy SDR plugin for PlutoSDR
https://github.com/pothosware/SoapyPlutoSDR/wiki
GNU Lesser General Public License v2.1
61 stars 23 forks source link

Maximum sample rate limitation SoapyPlutoSDR #45

Closed computer-wizard closed 3 years ago

computer-wizard commented 3 years ago

I use the Pluto SDR to generate DATV (Digital amateur tv) and found a limitation in the maximum sample rate I could use. My setup is OBS -> FFmpeg -> GNURadio version 3.9.2.0-0 > Pluto

I used a symbol rate of 2300 KSymbols/s to generate DVB-S2 for HDTV ( needs a sample rate of 4.6 Msps) and found that SoapyPlutoSDR couldn't handle this. By using SoapySDRUtil I found that the maximum is 4.2 ~ 4.0 Msps whatever test rate I set above it.

SoapySDRUtil --args="driver=plutosdr" --rate=4600000 --direction=TX ######################################################

Soapy SDR -- the SDR abstraction library

######################################################

[INFO] Using format CS16. [INFO] Has direct TX copy: 1 Stream format: CS16 Num channels: 1 Element size: 4 bytes Begin TX rate test at 4.6 Msps Starting stream loop, press Ctrl+C to exit... 4.23133 Msps 16.9253 MBps 4.23418 Msps 16.9367 MBps ....

Is there a way to increase this max sample rate in the source code as I didn't had this problem with the old OTT gr-iio module code of Analog Devices as used with previous GNURadio releases? (With the usual maximum practical limitations of the Pluto/Firmware and USB2)

zuckschwerdt commented 3 years ago

Use CS12 (no loss) or CS8 (lossy, in TX however you don't care) if you want higher sample rates.

computer-wizard commented 3 years ago

Thanks, but how do I specify the stream format in the arguments with SoapySDRUtil to test it. I tried with --args="driver=plutosdr,format=CS8" but that doesn't work as it still uses CS16

zuckschwerdt commented 3 years ago

SoapySDRUtil uses the "native" stream format, which SoapyPlutoSDR's getNativeStreamFormat() gives as CS16 for compatibility reasons. You'd have to change https://github.com/pothosware/SoapySDR/blob/master/apps/SoapyRateTest.cpp#L151 to select CS12 or CS8.

zuckschwerdt commented 3 years ago

And caveat: you likely need to use SoapyRemote as IIO uses CS16 internally :/ I did manage 10M sample rate though, IIRC.

AlexFWulff commented 3 years ago

@zuckschwerdt can you explain how you got 10M IQ samps/sec? From the way the driver is written, it looks like the fastest transfer should happen with CS16 (from https://github.com/pothosware/SoapyPlutoSDR/blob/master/PlutoSDR_Streaming.cpp#L395):

if (direct_copy) {
        // optimize for single RX, 2 channel (I/Q), same endianess direct copy
        // note that RX is 12 bits LSB aligned, i.e. fullscale 2048
        uint8_t *src = (uint8_t *)iio_buffer_start(buf) + byte_offset;
        int16_t const *src_ptr = (int16_t *)src;

        if (format == PLUTO_SDR_CS16) {

            ::memcpy(buffs[0], src_ptr, 2 * sizeof(int16_t) * items);

        }
....
}

Using the Python script at this gist, I'm only getting approx. 4M IQ samps/sec rather than the 10M requested. I have verified that the memcpy line is getting called by putting a print statement before that line in the driver.

Am I doing something wrong here? I suppose Python could be the problem and not the way I'm accessing things, but before I reimplement this in CPP I want to make sure that this is correct.

zuckschwerdt commented 3 years ago

USB 2.0 ist the bottleneck here, and IIO will only get you CS16 anyway. I use SoapyRemote on the Pluto to compress native CS16 to CS8. I.e. I don't use IIO to transfer over USB but SoapyRemote.

AlexFWulff commented 3 years ago

Ah ok I didn't realize USB 2.0 was the bottleneck here. According to the PlutoSDR wiki, the RX channel should be able to transfer ~8-10 million 2-byte samples per second over USB 2.0 so the 4 M IQ samps/sec makes sense now.

Do you have any documentation you followed for getting SoapyRemote set up on Pluto? It seems like it's not trivial to build and deploy applications on the SDR itself so a starting point for this would be helpful.

computer-wizard commented 3 years ago

Good remark. The test utility SoapySDRUtil transmits 4 bytes for each element (I assume this equals their samples I and Q) but ADI defines a Pluto sample as 2 bytes. Is the sample speed of SoapySDRUtil two times ADI's definition?

zuckschwerdt commented 3 years ago

Yes, IIO isn't concerned with RF or complex samples, each of I and Q are a simple channel on IIO. That's my note 2 channel (I/Q) in the source above, "IIO channels", not "Soapy channels".

computer-wizard commented 3 years ago

Here is an update about the SoapyPlutoSDR driver and DVB-S2. Frames are starting to be dropped with 333k Symbol rate (666k SR) and the 32APSK mode and up. Everything below that is fine, like 333k with 16APSk, etc., but anything that generates a higher netto bitrate (with Symbole Rate/Mode, etc. settings) drops frames. I see no errors with the feed (OBS, FFmpeg, GNURadio) USB 2.0 capacity should give no problem with this low SR. It is worse at 1000kS (2000k SR), already with QPSK. Buffer problem in Soapy driver???

fpgasdr commented 3 years ago

Hi, the usb2 on the pluto should not be the bottleneck in this case since the max sample rate achieved should be about 7MSPS now

https://ez.analog.com/adieducation/university-program/f/q-a/549401/maximum-continuously-receiving-sample-rate-of-pluto-sdr

zuckschwerdt commented 3 years ago

Interesting link (https://wiki.analog.com/university/tools/pluto/devs/performance) -- the direct USB backend should be somewhat faster than the RNDIS abstraction. Still 20-26 MBit translates to 5-6 Msps max, not accounting for overhead. Much higher rates are possible but hindered by USB speeds.

fpgasdr commented 3 years ago

If I try this pluto Soapysdr example: https://gist.github.com/AlexFWulff/524e7b8174bc3dfc3c1311babd6d166f

I get 7.130 M IQ samps/s

so no problem with usb2, i guess it's something in the tx..

zuckschwerdt commented 3 years ago

Ok, I can confirm this now. Nearly 8 Msps on RX, but only 4 Msps on TX.

zuckschwerdt commented 3 years ago

The low TX rate is indeed USB-bound, not on overall throughput but IOPS. The low-latency 4k (2048 I/Q samples) TX buffers are suitable only up to 4 Msps. There was a reason I choose 4k, maybe native IIO block size, I don't remember. I guess I'll add variable MTU for TX after some further tests.

computer-wizard commented 3 years ago

Interesting link (https://wiki.analog.com/university/tools/pluto/devs/performance) -- the direct USB backend should be somewhat faster than the RNDIS abstraction. Still 20-26 MBit translates to 5-6 Msps max, not accounting for overhead. Much higher rates are possible but hindered by USB speeds.

That is exactly what I did see with DVB-S2 and the original gr-iio in GNU-Radio 3.8. Just a little bit above 5.5 Msps it starts to get unreliable due to USB2 limits. This shows up as TX output power interruptions & lost frames.

computer-wizard commented 3 years ago

I guess I'll add variable MTU for TX after some further tests.

Hopefully this will solve my problem with Soapy and DVB :-)

zuckschwerdt commented 3 years ago

If you want to try TX at higher rates right away, change the 4096 (=1<<12) to e.g. 1<<16 or 1<<17 or even 1<<18 at https://github.com/pothosware/SoapyPlutoSDR/blob/master/PlutoSDR_Streaming.cpp#L176 https://github.com/pothosware/SoapyPlutoSDR/blob/master/PlutoSDR_Streaming.cpp#L610

computer-wizard commented 3 years ago

Thanks, I will try that. What most likely is needed is a block buffer-size setting in the Soapy Pluto Sink block of GNU-Radio, as that is presently missing. (The PlutoSDR sink block of gr-iio has this, I used 32.768k )

zuckschwerdt commented 3 years ago

We have the magic "bufflen" arg for RX on setupStream(), but I'd rather remove that and use the numElems burst control arg on activateStream(). That way we can reconfigure the buffers easily. I need to check, but "burst control" sounds like exactly the latency vs. throughput knob we are trying to turn.

Anyway, the automatic setting based on samplerate works well for RX. I'll copy that, but I guess at a higher target rate of maybe 100-200 fps? At 4 Msps with 4k buffers we are maxing out at 1000 fps (1µs per frame).

Are you using gr-iio with 32k buffer at 8 Msps (would be 250 fps)?

computer-wizard commented 3 years ago

I use a 32k buffer at around max 6 Msps sample rate.

fpgasdr commented 3 years ago

Hi @computer-wizard what firmware version are you using in pluto?. Since v0.33 they speed up almost a 25%. The max sample rate achieved should be 7.5 msps now

computer-wizard commented 3 years ago

The quoted max sample rate was for v0.32. Sorry that I that I didn't mentioned that. I used and have v0.33 but I didn't test it for max sample rate yet.

fpgasdr commented 3 years ago

if I change the buffer size to 32k like @zuckschwerdt propose in:

If you want to try TX at higher rates right away, change the 4096 (=1<<12) to e.g. 1<<16 or 1<<17 or even 1<<18 at https://github.com/pothosware/SoapyPlutoSDR/blob/master/PlutoSDR_Streaming.cpp#L176 https://github.com/pothosware/SoapyPlutoSDR/blob/master/PlutoSDR_Streaming.cpp#L610

I get now this:

/^C(cusignal-dev) juli@juli-jetson:~/SoapyPlutoSDR/build$ SoapySDRUtil --args="driver=plutosdr" --rate=8000000 --direction=TX ######################################################

Soapy SDR -- the SDR abstraction library

######################################################

WARNING: Unknown parameter '0' in WARNING: Unknown parameter '23' in WARNING: Unknown parameter 'v0.23' in WARNING: Unknown parameter '0' in WARNING: Unknown parameter '23' in WARNING: Unknown parameter 'v0.23' in [INFO] Using format CS16. [INFO] Has direct TX copy: 1 Stream format: CS16 Num channels: 1 Element size: 4 bytes Begin TX rate test at 8 Msps Starting stream loop, press Ctrl+C to exit... 6.82027 Msps 27.2811 MBps 6.81949 Msps 27.2779 MBps 6.8211 Msps 27.2844 MBps 6.82084 Msps 27.2834 MBps

My host cpu is a jeston nano so maybe there is something in the cpu that limit my max sample rate but it's a good improvement(previously I was in 3.7msps).

I'll try with other Buffer sizes to see what happend

zuckschwerdt commented 3 years ago

Note that the current version is: v0.34

For a weaker cpu I'd use a bigger buffer. 32k at 6 Msps is 183 fps, at 8 Msps 244 fps, at 64k 122 fps. I guess a target fps of 100-200 fps will be acceptable throughput vs latency, i.e. Msps/200 rounded up to a power of 2.

fpgasdr commented 3 years ago

Thanks @zuckschwerdt I know the v0.34is the latest but there is no important improvements in this version the important is in the V0.33.

with bigger buffer size I improve the performance to the maximum usb limit.

with 64k buff size i get: 7.17033 Msps 28.6813 MBps with 128k buff size i get: 7.35508 Msps 29.4203 MBps with 256k buff size i get: 7.47722 Msps 29.9089 MBps with 512k buff size i get: 7.55 Msps 30.2 MBps with 1M buff size i get: 7.5759 Msps 30.3036 MBps

I guess this solve all our problems.

computer-wizard commented 3 years ago

v0.34 installed and with 64k buffer I get in Soapy,

8.02229 Msps 32.0892 MBps 8.01105 Msps 32.0442 MBps 8.00737 Msps 32.0295 MBps 8.00546 Msps 32.0218 MBps 8.00439 Msps 32.0176 MBps 8.00364 Msps 32.0146 MBps 8.00311 Msps 32.0124 MBps 8.00269 Msps 32.0108 MBps 8.0024 Msps 32.0096 MBps 8.00205 Msps 32.0082 MBps 8.00195 Msps 32.0078 MBps

So far so good and will test it later today with DVB/DATV!

fpgasdr commented 3 years ago

v0.34 installed and with 64k buffer I get in Soapy,

8.02229 Msps 32.0892 MBps 8.01105 Msps 32.0442 MBps 8.00737 Msps 32.0295 MBps 8.00546 Msps 32.0218 MBps 8.00439 Msps 32.0176 MBps 8.00364 Msps 32.0146 MBps 8.00311 Msps 32.0124 MBps 8.00269 Msps 32.0108 MBps 8.0024 Msps 32.0096 MBps 8.00205 Msps 32.0082 MBps 8.00195 Msps 32.0078 MBps

So far so good and will test it later today with DVB/DATV!

I'm surprise this gives you better performance than the iio interface.

did you tried with bigger buffer?

computer-wizard commented 3 years ago

I never tested v.0.33 & v.0.34 with iio because gr-iio OOT module is not supported by GNU Radio 3.9.2 yet. That is why I switched over to Soapy. No, I didn't tested it with a larger buffer as yet.

zuckschwerdt commented 3 years ago

Do you have any documentation you followed for getting SoapyRemote set up on Pluto?

I've now setup binary builds of SoapySDR for the Pluto to test if you like. There are notes on two possible toolchains, if you want to compile yourself. E.g. 50 Msps (RX) works fine on on the hardware itself: SoapySDRUtil --args="driver=plutosdr" --rate=50000000 --direction=RX

computer-wizard commented 3 years ago

I tried to test the remote with, SoapySDRUtil --args="driver=remote,remote:driver=plutosdr" --rate=10000000 --direction=TX Speed still stays around 8 Msps. I guess I have to change the stream format, how do I do that?

zuckschwerdt commented 3 years ago

SoapySDRUtil uses getNativeStreamFormat(), so you'd need custom code to pick CS12 or CS8. SOAPY_SDR_CS8 in https://github.com/pothosware/SoapySDR/blob/master/apps/SoapyRateTest.cpp#L151 should do that.

fpgasdr commented 3 years ago

SoapySDRUtil uses getNativeStreamFormat(), so you'd need custom code to pick CS12 or CS8. SOAPY_SDR_CS8 in https://github.com/pothosware/SoapySDR/blob/master/apps/SoapyRateTest.cpp#L151 should do that.

So it not possible to assign in command line the local and remote format without modify the code?.

As far as I can understand for be able to make this works, the only thing I have to do is to send to pluto the Soapyremote you provide in your repo in pluto board and launch it with SoapySDRServer --bind command

then recompile the SoapySDR with the line in https://github.com/pothosware/SoapySDR/blob/master/apps/SoapyRateTest.cpp#L151 changed to: const auto format = SOAPY_SDR_CS8 and then run in my computer: SoapySDRUtil --args="driver=remote,remote:driver=plutosdr" --rate=10000000 --direction=TX

is that correct?.in my case not. if I try this I get:

SoapySDRUtil --args="driver=remote,remote:driver=plutosdr" --rate=10000000 --direction=TX

######################################################

Soapy SDR -- the SDR abstraction library

######################################################

[INFO] SoapyRemote::setupTxStream(remoteFormat=CS8, localFormat=CS8, scaleFactor=128, mtu=1500, window=44040192) [INFO] Client side stream bound to 192.168.2.10:34661 [INFO] Client side status bound to 192.168.2.10:45603 [INFO] Using format CS8. [INFO] Has direct TX copy: 1 [INFO] Server side stream bound to 192.168.2.1:41626 [INFO] Server side stream connected to 192.168.2.10:34661 [INFO] Server side status connected to 192.168.2.10:45603 [WARNING] StreamEndpoint resize socket buffer: set 43008 KiB, got 176 KiB [INFO] Configured receiver endpoint: dgram=1452 bytes, 714 elements @ 2 bytes, window=176 KiB [INFO] Client side stream connected to 192.168.2.1:41626 [WARNING] StreamEndpoint resize socket buffer: set 43008 KiB, got 1024 KiB [INFO] Configured sender endpoint: dgram=1452 bytes, 714 elements @ 2 bytes, window=1024 KiB Stream format: CS8 Num channels: 1 Element size: 2 bytes Begin TX rate test at 10 Msps Starting stream loop, press Ctrl+C to exit... 3.00846 Msps 6.01692 MBps 3.00135 Msps 6.00271 MBps 2.99892 Msps 5.99784 MBps

the bit rate is reduced by a factor of 4. Previously without this change I got:

SoapySDRUtil --args="driver=remote,remote:driver=plutosdr" --rate=10000000 --direction=TX

######################################################

Soapy SDR -- the SDR abstraction library

######################################################

[INFO] SoapyRemote::setupTxStream(remoteFormat=CS16, localFormat=CS16, scaleFactor=32768, mtu=1500, window=44040192) [INFO] Client side stream bound to 192.168.2.10:47705 [INFO] Client side status bound to 192.168.2.10:33210 [INFO] Using format CS16. [INFO] Has direct TX copy: 1 [INFO] Server side stream bound to 192.168.2.1:44353 [INFO] Server side stream connected to 192.168.2.10:47705 [INFO] Server side status connected to 192.168.2.10:33210 [WARNING] StreamEndpoint resize socket buffer: set 43008 KiB, got 176 KiB [INFO] Configured receiver endpoint: dgram=1452 bytes, 357 elements @ 4 bytes, window=176 KiB [INFO] Client side stream connected to 192.168.2.1:44353 [WARNING] StreamEndpoint resize socket buffer: set 43008 KiB, got 1024 KiB [INFO] Configured sender endpoint: dgram=1452 bytes, 357 elements @ 4 bytes, window=1024 KiB Stream format: CS16 Num channels: 1 Element size: 4 bytes Begin TX rate test at 10 Msps Starting stream loop, press Ctrl+C to exit... 6.21219 Msps 24.8487 MBps 6.19421 Msps 24.7768 MBps 6.19682 Msps 24.7873 MBps 6.2003 Msps 24.8012 MBps 6.2056 Msps 24.8224 MBps 6.20896 Msps 24.8358 MBps

Any ideas?

fpgasdr commented 3 years ago

the strange is if I make the same with SC12 I get better results: SoapySDRUtil --args="driver=remote,remote:driver=plutosdr" --rate=10000000 --direction=TX ######################################################

Soapy SDR -- the SDR abstraction library

######################################################

[INFO] SoapyRemote::setupTxStream(remoteFormat=CS12, localFormat=CS12, scaleFactor=2048, mtu=1500, window=44040192) [INFO] Client side stream bound to 192.168.2.10:45599 [INFO] Client side status bound to 192.168.2.10:37413 [INFO] Using format CS12. [INFO] Has direct TX copy: 1 [INFO] Server side stream bound to 192.168.2.1:39152 [INFO] Server side stream connected to 192.168.2.10:45599 [INFO] Server side status connected to 192.168.2.10:37413 [WARNING] StreamEndpoint resize socket buffer: set 43008 KiB, got 176 KiB [INFO] Configured receiver endpoint: dgram=1452 bytes, 476 elements @ 3 bytes, window=176 KiB [INFO] Client side stream connected to 192.168.2.1:39152 [WARNING] StreamEndpoint resize socket buffer: set 43008 KiB, got 1024 KiB [INFO] Configured sender endpoint: dgram=1452 bytes, 476 elements @ 3 bytes, window=1024 KiB Stream format: CS12 Num channels: 1 Element size: 3 bytes Begin TX rate test at 10 Msps Starting stream loop, press Ctrl+C to exit... 7.88389 Msps 23.6517 MBps 7.84429 Msps 23.5329 MBps 7.85634 Msps 23.569 MBps

Why is limited to 24MBps when should be 30?

I'm using v.0.34 firmware and ryzen5 3400 ubuntu computer in host. I'll try with jetson nano also...

zuckschwerdt commented 3 years ago

I just tested that same thing and also got those disappointing rates. I do remember getting far better results. I'll have to poke at it some more. If I run the test locally on the Pluto I get 50 Msps (RX, TX) without problems.

fpgasdr commented 3 years ago

the pluto as standalone should get the max sample rate from the AD9361. I got with the iio running inside the pluto 61msps because the usb is not between the cpu and the transceiver.

But I think we are in the correct way since the SC12 option give better results than the SC16 but the SC8 version is not but don't know why.

Also the 24MBps maybe is because it's using the ip interface instead of the usb backend.

what are your results?.

zuckschwerdt commented 3 years ago

For convenience I've added --format=CS16 in feat-ratefmt to SoapySDR.

Running locally on the Pluto I get:

Direct driver, e.g. SoapySDRUtil --args="driver=plutosdr" --rate=80000000 --direction=TX --format=CS16

Remote driver (locally!), e.g. SoapySDRUtil --args="driver=remote,remote:driver=plutosdr" --rate=12000000 --direction=TX --format=CS16 -TX, CS16: 10 Msps 41 MBps -TX, CS12: 13.6 Msps 41 MBps -TX, CS8: 21 Msps 42 MBps

I guess local network throughput is limited to ~42 MBps. USB network throughput should be 24-30 MBps, but it seems UDP overhead (or MTU) drastically reduce that. For me SoapyRemote is consistently worse than direct native CS16 :(

zuckschwerdt commented 3 years ago

I've created a new release of the apps. This time with --format= for SoapySDRUtil rate test and also iperf3 for raw network throughput tests. Testing UDP/TCP up/down I get:

So about 20 MBps should be a safe SoapyRemote capacity for me. It gets stuck at a much lower rate though :/

computer-wizard commented 3 years ago

Thank you for the new release of the apps. I have tested SoapyPlutoSDR with DATV (DVB-S2) using a 64k buffer setting. DVB-S2 at 2300kS/s (Sample rate 4.6 Msps) runs now very good. DVB-S2 with 1000 kS/s (SR 2 Msps) runs badly with many dropped frames. I tried several buffer settings but this doesn't help, very strange.

computer-wizard commented 3 years ago

The PlutoSDR uses RNDIS as the default USB Ethernet compatibility mode (driver interface) This can be changed (Since firmware v0.33) to CDC-NCM or CDC-ECM if your OS supports it. I switched it over to CDC-NCM, what gives a much greater throughput. (32 MBps)

computer-wizard commented 3 years ago

The Pluto SDR works now excellent with the Soapy Plugin and also with Soapy Server (Remote) at the local computer. To recap, I have the buffer set to 65536 (64k) in PlutoSDR_Streaming.cpp and have the following Device argument line in the Soapy Pluto Sink block of GNURadio, format=CS8,driver=remote,remote=tcp://127.0.0.1:55132,remote:driver=plutosdr. Thanks for your work and assistance. I close this thread as solved.