Closed scd31 closed 1 year ago
@scd31 - thanks for reporting this problem with rx_sdr
.
I think SDR++ uses the SDRplay API natively, so this problem with the SoapySDRPlay3 module wouldn't apply to SDR++.
On the other hand there are several SDR applications that use SoapySDR and therefore SoapySDRPlay3, like CubicSDR (https://cubicsdr.com/), OpenWebRX (https://www.openwebrx.de/), and the GNU Radio module gr-soapy, if you are familiar with it. I do not have a RSP1A here, however I just ran a quick test with my RSPdx and CubicSDR; I selected a sample rate of 4Msps, and I am able to listen to a local NOAA station without any problems.
Can you try to install CubicSDR there, and see if it works correctly with say a sample rate = 4Msps?
If it does, then we'll have to look at the differences between rx_sdr
and CubicSDR; on the other hand, if you experience a similar problem with both programs, then we'll have to figure out what is the difference between your setup and mine.
Franco
I haven't had a chance to set up CubicSDR yet, but I gave rx_sdr
a try with my RTL-SDR and I can confirm it works with a sample rate of (2M+4) samples/second. I'll get CubicSDR compiled after work and let you know if I can reproduce the issue there.
Thanks!
Hi again,
I got cubicsdr working and it seems to work fine at higher sample rates. I went all the way to 10MSPS and it seems to work fine! Seems like something weird is happening with rxtools.
Thanks for trying with CubicSDR; since CubicSDR and rxtools use the same SoapySDR and the same SoapySDRPlay3 module, I agree with you that there must be some difference in the way they interface with the SoapySDRPlay3 that is causing this problem.
I have rx_sdr
here on my computer, so I can see if I can reproduce your problem here, and I'll let you know what I find out.
Franco
Thanks, I really appreciate it!
I ran a couple of tests tonight using the fm_player.py
Python script that I wrote a few months ago (https://github.com/fventuri/dual-tuner-experiments/blob/main/fm_player.py). Since it uses GNU Radio blocks to do all the DSP work, you'll need to have GNU Radio installed to be able to run it.
We have a local NOAA station here on 162.550MHz, which I use for this kind of tests since it has good signal and it is always on.
In the first test I ran rx_sdr
with a sample rate of 2MHz as follows (I have a RSPdx here; that's the reason for the Antenna C
argument):
rx_sdr -d driver=sdrplay -s 2000000 -f 162550000 -a 'Antenna C' -F CS16 /tmp/testfile-2M.iq16
After 30 or so seconds, I stopped rx_sdr
, and then I was able to play the IQ file and listen to the station with the following command:
./fm_player.py -i /tmp/testfile-2M.iq16 -s 2e6 -f 162550000
In the second test I ran rx_sdr
with a sample rate of 4MHz:
rx_sdr -d driver=sdrplay -s 4000000 -f 162550000 -a 'Antenna C' -F CS16 /tmp/testfile-4M.iq16
I let it run for another 30 seconds, then I played that output file with the command:
./fm_player.py -i /tmp/testfile-4M.iq16 -s 4e6 -f 162550000
and in this case too I was able to see the signal from the NOAA station in the frequency spectrum, and to listen to that station without any problems.
If you have GNU Radio there (or if you do not mind installing it), you could try the same tests to see if they work for you (the ./fm_player
script can only decode NBFM, so if you have an FM repeater on 2m or 70cm nearby, you can use those too).
Franco
I tried giving your script a try but I got the following error:
$ ./fm_player.py -i 2M.iq16 -s 2e6 -f 144390000
Traceback (most recent call last):
File "/home/stephen/src/dual-tuner-experiments/./fm_player.py", line 184, in <module>
main()
File "/home/stephen/src/dual-tuner-experiments/./fm_player.py", line 109, in main
interleaved_short_to_complex = blocks.interleaved_short_to_complex(False, False, 32767)
TypeError: make() takes from 0 to 2 positional arguments but 3 were given
I'm uploading the IQ sample files to my Nextcloud server in case you want to try them on your end. I captured APRS traffic at 144.390MHz. The commands I used were:
rx_sdr -d driver=sdrplay -s 2000000 -f 144390000 -t agc_setpoint=0 -F CS16 2M.iq16
rx_sdr -d driver=sdrplay -s 4000000 -f 144390000 -t agc_setpoint=0 -F CS16 4M.iq16
I'll post again when the samples are ready! Note that it's ~1.2GB total for the files.
I think that error might be due to the fact that your version of GNU Radio is a few years old; I just checked on GitHub, and it looks like they added the third argument (the scale factor) with GNU Radio version 3.9.0 about four years ago (https://github.com/gnuradio/gnuradio/commit/458414c7b2ab93fa1a6d130fa64d907dd9fca5f0).
Since I don't think I have an APRS decoder here, would you mind sending me an IQ recording from an analog FM signal? It could be either from a repeater, or just a local FM BC station, since I have another GNU Radio script that allows me to listen to those (15 or 20 seconds would be long enough).
If you prefer to email me the link directly, you can get my email address from the git log
commit messages.
Franco
Thanks - I updated my GNU Radio by compiling from source and I was able to use your program.
The 2M and 4M sound fine, except the 4M keeps having breaks in the audio. Every time there's a break, it prints aU
to the console. I'm assuming my system isn't powerful enough and I'm experiencing underflow. I also tried 2M + 1 samples and it worked flawlessly.
I also gave it a try with having rx_tools output cu8 instead of i16, since that's what I'm using. That also seemed to work fine (I used csdr to convert it to i16 before passing it into the fm player)
It sounds like the problem is in my fsk demodulator, so I'll start tackling that next. Thanks for your help!
I hope you can figure out what's the difference between having a sample rate of 2Msps compared to using a higher value like 4Msps.
csdr
is definitely another good set of tools for issues like this one; if I remember correctly they even have an example of a chain of csdr
commands that implements a NBFM receiver very similar to fm_player.py
so you could use that example instead.
If you instead decide to stay with GNU Radio and the script fm_player.py
, then the script should be able to read a file in cu8 format by replacing in these few lines https://github.com/fventuri/dual-tuner-experiments/blob/main/fm_player.py#L109-L113 all the occurrences of interleaved_short_to_complex
with interleaved_char_to_complex
(see here: https://www.gnuradio.org/doc/doxygen/classgr_1_1blocks_1_1interleaved__char__to__complex.html#details). Similarly if you select the 'FC32' format out of rx_sdr
, then you don't need that extra block interleaved_<something>_to_complex
, and you can just remove lines 109 and 110, and in line 113 connect directly the file source to the throttle block.
Franco
Here's what's driving me crazy - with an RTL-SDR and using the SoapySDR chain (still using rx_sdr) everything works fine at (2M + 4) SPS. When I switch to my RSP1A and change nothing else, suddenly I'm no longer demodulating packets properly. Both work fine at 2M SPS. I've tried it both with and without the -t agc_setpoint=0
I am not really familiar with the RTL-SDR (I only have SDRplay RSPs here), so I honestly cannot comment on the differences between what's inside the SoapyRTLSDR module and this module, however I just thought you could try this simple experiment:
rx_sdr
at 2Msps, and make sure your FSK demodulator works as expectedcsdr
, run the RSP1A with rx_sdr
at 4Msps, pipe its output into a decimator by 2 (using csdr fir_decimate_cc 2 ...
), and finally pipe the output from the decimator into the FSK demodulator (which should configured identical to case 1). In this case 2, do make sure that the IF bandwidth is set to 1536kHz and no wider to avoid aliasing problems in the decimator.I am curious to see if the FSK demodulator works in case 2.
Franco
For fun, I tried going the other way. Sampling at 2MSPS and interpolating to 4MSPS, into the FSK modem. This worked fine. It completely fell apart if I did 2000001 SPS. I didn't touch anything else, besides the sample rate in rx_tools
.
Anyway, onto your experiments:
case 1 - Works fine. Command:
rx_sdr -s 2000000 -f $RXFREQ -F CF32 -t agc_setpoint=0 - | \
csdr shift_addition_cc 0.25 | \
csdr convert_f_s16 | \
./fsk_demod --cs16 -s --stats=100 2 2000000 $BAUD_RATE - - 2> >(python3 fskdemodgui.py --wide) | \
./drs232_ldpc - - -vv | \
python3 rx_ssdv.py --partialupdate 64
case 2 - Not a single packet is decoded correctly. I do get a few checksum errors (about 100 vs 1600 packets sent) which indicates the preamble is at least detected sometimes. (Though, the preamble is allowed to have a few bit errors). The FFT spectrum graph looks fine. Command:
rx_sdr -s 4000000 -f $RXFREQ -F CF32 -t agc_setpoint=0 - | \
csdr fir_decimate_cc 2 | \
csdr shift_addition_cc 0.25 | \
csdr convert_f_s16 | \
./fsk_demod --cs16 -s --stats=100 2 2000000 $BAUD_RATE - - 2> >(python3 fskdemodgui.py --wide) | \
./drs232_ldpc - - -vv | \
python3 rx_ssdv.py --partialupdate 64
Oh, and for all these tests, I had the filter hardcoded to 1.536 MHz. This required a code change in rtl_sdr.c
, which confusingly is the source code for rx_sdr
.
Would it be possible for you to try both cases without the 500kHz shift? i.e. setting RXFREQ
to the exact value where you want to demodulate the FSK signal both in the 2Msps case and in the 4Msps case (and of course removing the csdr shift_addition_cc
step in both cases).
I know this choice is not optimal because of the DC component, but I just want to start ruling things out block by block, to see if we can finally figure out where the problem is.
Franco
Works:
rx_sdr -s 2000000 -f 446400000 -F CF32 -t agc_setpoint=0 - | \
csdr convert_f_s16 | \
./fsk_demod --cs16 -s --stats=100 2 2000000 $BAUD_RATE - - 2> >(python3 fskdemodgui.py --wide) | \
Doesn't work:
rx_sdr -s 4000000 -f 446400000 -F CF32 -t agc_setpoint=0 - | \
csdr fir_decimate_cc 2 | \
csdr convert_f_s16 | \
./fsk_demod --cs16 -s --stats=100 2 2000000 $BAUD_RATE - - 2> >(python3 fskdemodgui.py --wide) | \
The FSK signal is centered around 446.9 MHz. The demodulator actually expects the FSK signal to be above the 0 point (which is why I was doing the shift before). The exact placement isn't critical - I only skimmed the code but it appears to estimate which frequency bins to use.
I've just seen this and I just want to remind you that if I remember correctly, in the SoapySDRPlay library, Low-IF is used for sample rates of 2 MHz and below and Zero-IF is used for sample rates above 2 MHz.
In Zero-IF mode there is a DC component at the LO frequency and there is a DC offset compensation loop running in the API to remove this component. This is why you always need to keep an offset between the LO frequency and the center of an AM signal for example.
So if you can't offset where the software expects to see the center of the wanted signal, you'll need to stick with Low-IF mode (i.e. 2 MHz sample rate or lower)
Hope that helps.
Andy
btw, setting a setpoint of 0 is only valid if the IF gain range is in the extended mode, which I'm pretty sure it isn't in this case. Setting a setpoint of -30 is fairly typical (note the default in the API if you don't specify a setpoint is -60)
Andy
@scd31 - at this point I am really puzzled.
Would it be possible for you to try the FSK demodulator using the little toy program single_tuner_recorder
that I wrote a few months ago? This morning I added the option to write the I/Q output stream to stdout.
You can find it here: https://github.com/fventuri/single-tuner-experiments
These are the commands for 2Msps and 4Msps that should be the equivalent of what you ran yesterday.
For 2Msps:
single_tuner_recorder -r 6000000 -i 1620 -b 1536 -f 446400000 -o - | \
./fsk_demod --cs16 -s --stats=100 2 2000000 $BAUD_RATE - - 2> >(python3 fskdemodgui.py --wide) | \
For 4Msps:
single_tuner_recorder -r 4000000 -i 0 -b 1536 -f 446400000 -o - | \
./fsk_demod --cs16 -s --stats=100 2 4000000 $BAUD_RATE - - 2> >(python3 fskdemodgui.py --wide) | \
If they both work, then the problem should be in the SoapySDRPlay3 module, since single_tuner_recorder
uses the native SDRplay API, without going through the SoapySDRPlay3 module.
Andy, @scd31 wrote in his comment that the FSK signal is centered around 446.9MHz, while he is using a center frequency of 446.4MHz, so I don't think in these tests he is really affected by the DC spike.
Franco
btw I'm not sure of the benefit of a 4 MHz sample rate, remember that the hardware IF filter is 1.536 MHz until you get to 5 MHz sample rate - so all you end up with is an additional 2 MHz of attenuated spectrum.
What's the bandwidth of the wanted signal? Really the LO should be set just a bit away from half of that. I take your point about the 500 kHz offset - remember that the signal roll off will start at about 700 kHz from the LO frequency with a 1.536 MHz bandwidth.
Personally I would try 5 MHz sample rate to remove the issues that 4 MHz has.
Andy, just to give you some context here.
@scd31 FSK demodulator works fine with a sample rate of 2Msps (and 1Msps), but doesn't work with any sample rate > 2Msps. The reason for the choice of 2Msps (FSK demod OK) and 4Msps (FSK demod not OK) for these tests is because you can easily go from 4Msps to 2Msps with a decimator by 2 (that's also why the IF bandwidth is set to 1536kHz, to avoid aliasing in this case). Unfortunately even in this case his FSK demodulator doesn't seem to work (and he is not trying to demodulate a signal exactly at the center frequency).
Of course in a real world scenario one wouldn't use these settings, but this A/B comparison seem to indicate something is wrong in the 4Msps case, and I am not sure what (listening to a regular FM analog signal in both cases sounds OK).
Franco
Hi Franco,
I guess I'm not understanding the decimating part of this - you would never decimate 4 MHz down to 2 MHz because you would also be decimating the IF filter bandwidth (not withstanding also having the DC component problem) - you would end up with 2 MHz spectrum but the IF filter would no longer be 1.536 MHz it would be 0.768 MHz - just seems a strange test from my perspective. Any sample rate between 2 and 5 MHz isn't really useful if you are assuming the full spectrum bandwidth because of the IF filter bandwidth.
I don't know what processing is being done down stream so please ignore me if I've misunderstood the issue.
Best regards,
Andy
I just wanted to say I haven't forgotten about this, I've just gotten busy. Hoping to try out the new suggestions tomorrow if all goes well.
Andy, I am not sure I follow you when you talk about the IF filter.
If I have a signal at say 100kHz on the right of the center frequency, after decimation that signal is still at 100kHz on the right of the center frequency (not 50kHz); in other words from what I know decimation shouldn't change the spectral content of a signal (except for the aliasing effect, of course; that's why the IF filter). This would imply that if you have an IF filter that clips the incoming frequency spectrum at 1536kHz with a sample rate of 4Msps, the same frequancy spectrum should be still clipped at 1536kHz after decimation by 2.
@scd31 - I understand very well; I have a regular job during the day, and sometimes I only have very little time to check my emails and GitHub and answer them at night.
Franco
Hi Franco,
Yes, the spectral content of the signal is the same, I was confusing myself with the effects of the decimation filtering. My brain is frazzled at the moment with doing crazy hours so ignore me lol
Best regards,
Andy
Works:
single_tuner_recorder -r 6000000 -i 1620 -b 1536 -f 446400000 -o - | \
./fsk_demod --cs16 -s --stats=100 2 2000000 $BAUD_RATE - - 2> >(python3 fskdemodgui.py --wide) | \
Side note: why the 6000000 instead of 2000000?
Doesn't work:
single_tuner_recorder -r 4000000 -i 0 -b 1536 -f 446400000 -o - | \
./fsk_demod --cs16 -s --stats=100 2 4000000 $BAUD_RATE - - 2> >(python3 fskdemodgui.py --wide) | \
The FFT graph certainly doesn't look correct:
(No signal) (FSK signal)
I'm also wondering if there's a way to get the single tuner record to run indefinitely. Right now it stops after a few seconds.
For context, here's the same graphs on 2MSPS:
I'm thinking of throwing a program together that plots each IQ value on a 2D cartesian plane per frame, and then combines the frame into a video. I would expect to see the point bouncing around when there's no signal, and when there is a signal, it would alternate between spinning one way and spinning the other way (assuming the center frequency was the same as my FSK transmitter). That would potentially narrow things down some
Alright so I spent a bit of time today writing a program that takes in CU8 data, runs it through an FFT, and plots it. It doesn't even center on the center frequency, so the first half of the plot is the positive frequencies and the second half of the plot is negative frequencies. The FFT size is hardcoded to 64.
I tested it with rx_sdr
and single_tuner_recorder
and the results look correct for 2M samples - I get the classic FSK spectrum. However, 4M samples looks very mangled. The command used was single_tuner_recorder -r 4000000 -i 0 -b 1536 -f 446400000 -o - | csdr convert_i16_f | csdr convert_f_u8 | cargo run --release
For context, here's 2M samples. Command used was single_tuner_recorder -r 6000000 -i 1620 -b 1536 -f 446400000 -o - | csdr convert_i16_f | csdr convert_f_u8 | cargo run --release
The units are arbitrary, but they're logarithmic.
Also, the spectrum looks fine in SDRangel and SDR++, both at 4MSPS.
If you have arbitrary .cu8 (or anything else like .cs16) files then you can also check the spectrogram similar to the waterfall you'd see in SDR apps with https://triq.org/pdv/ or now with better scroll-zoom support in the beta https://triq.org/spectrogram-next/ -- both are battle-tested FFT visualisations.
Just make sure to tag the center frequency and sample rate in the filename like this: myfile_446.4M_2000k.cu8
-- M
and k
are fixed markers, don't scale differently.
This morning I ran single_tuner_recorder
with my RSPdx for both 2Msps and 4Msps as follows:
./single_tuner_recorder -r 6000000 -i 1620 -b 1536 -f 162500000 -a 'Antenna C' -o /tmp/162500000-2M.iq16
and
./single_tuner_recorder -r 4000000 -i 0 -b 1536 -f 162500000 -a 'Antenna C' -o /tmp/162500000-4M.iq16
The sample rate for the 2Msps case is set to 6M, because with that combination of sample rate, IF frequency, and IF bandwidth, the SDRplay API has an internal decimation by 3, so the actual output sample rate is 2Msps (see their API Specification Guide https://www.sdrplay.com/docs/SDRplay_API_Specification_v3.07.pdf in the section about sdrplay_api_Init()
on page 26, where they have the table with the conditions for LIF down-conversion).
I then created a very simple flowgraph in GNU Radio Compantion (attached to this comment) , and the frequency spectrum for 2Msps and 4Msps look very similar to me (since I took the two I/Q recordings at slightly different times, the peaks are slightly different in amplitude but at the same frequencies):
Franco
Quick question. Is it possible I'm overloading the frontend? I have no idea why that would happen at 2MSPS but not 4MSPS.
I've been experimenting with a UHF FM ham radio (don't worry, I'm licensed!)
Here's the spectrum at 4MSPS:
At 2MSPS I get a single peak as expected. I'm transmitting at 1W and I get that interference even if I'm 20 feet away or so (as far as I can get while still being able to see my screen).
For fun, I tried taking the antenna off my transmitter (obviously a very bad idea but it's a $30 handheld and I was only transmitting for a fraction of a second). I got the single peak as expected. This was with the transmitter only a foot away!
Taking the antenna off the SDR instead (leaving the TX antenna on) and transmitting from a few meters away I only get the single peak. But at 1 meter distance I get many peaks like above. Again, at 2MSPS it works fine!
Just wondering if you have any thoughts on this - specifically why it overloads at 4MSPS but not at 2MSPS.
@scd31 - very interesting finding!
Would it be possible for you to try with a sample rate of say 2048kHz (i.e. slightly above 2M) and setting IF=0 (i.e. Zero-IF) to see if those spurious peaks show up in that case too? If that's the case perhaps there's something going on when going from Low-IF (1620kHz) to Zero-IF.
Also if the ADC detects an overload, the SDRplay API generates a sdrplay_api_PowerOverloadChange
event. The SoapySDRPlay3 module currently just acknowledges that event (see here: https://github.com/pothosware/SoapySDRPlay3/blob/master/Streaming.cpp#L176-L180), but perhaps you could log the overload event to terminal by adding a line like this right before line 178 in Streaming.cpp
:
SoapySDR_log(SOAPY_SDR_WARNING, "Overload detected");
Then rebuild and install the SoapySDRplay3 module, and run rx_sdr
with both sample rates (2Msps and 4Msps) with your transmitter at various distances to see if the RSP ADC has overload problems.
Franco
rx_sdr -F CU8 -f 446400000 -s 2048000 -
-> No overloading
single-tuner-experiments/build/single_tuner_recorder -r 2048000 -i 0 -b 1536 -f 446400000 -o - | csdr convert_i16_f | csdr convert_f_u8
-> Overloads
I'm just on my lunch break but I'll try adding that logging after work. Thanks!
With the changes to SoapySdrPlay3 I'm getting an overload detected error whenever I key up - just one though. Strangely, this happens both when I'm running at 2MSPS (with no overloading) and 4MSPS (with overloading).
I did some more experimenting with AngelSDR and I think I can reproduce the issue by setting the IF to 0KHz and moving to 4MSPS.
@scd31 - one overload message is usually OK (I occasionally see them here too).
I know I already asked you to run a lot of tests, and I appreciate your patience, but I was wondering if you could run the usual 2Msps/4Msps comparison with the gain reduction set to the maximum value (i.e. with the lowest gain).
You would have to run rx_sdr
with the option -g
set to something like -g 'RFGR=<LNAmax>,IFGR=59'
, where LNAmax
is the maximum value for the LNA state, which depends on the model of SDRplay RSP you have there (and the band you are tuned to).
You can find the table with the LNA states in SDRplay API Specification Guide (https://www.sdrplay.com/docs/SDRplay_API_Specification_v3.07.pdf), section '5 Gain Reduction Tables' on page 38.
The same gain reduction settings in single_tuner_recorder
are called -l
(for LNA state) and -g
(for IFGR).
In both cases you should have a very low signal going into the ADC even with your transmitter not far away; I am curious to see if even in this case the output in the 4Msps case has those spurious spikes (if you have time you can then decrease those gain reduction settings RFGR
and IFGR
to find out at what point the problems begins to occur).
Franco
I'm more than happy to run as many tests as required! I really do appreciate the help.
I'm just getting ready for bed right now but I'll give that a try tomorrow, hopefully after work.
I only adjusted the RFGR setting as the IGFR was ignored because I have AGC enabled.
With RFGR=1, the overloading pretty much goes away unless the antenna is a foot from the SDR (no antenna connected) at 4MSPS. This isn't as good as at 2MSPS but it's a lot better.
At RFGR=2 I can get to maybe half a foot before it overloads.
This was all using rx_sdr. I couldn't get the overloading to happen at all at 2MSPS, even with the antenna right next to the SDR.
Thanks for trying those test cases; I see you are making some good progress there.
I was wondering if at this point you could try running rx_sdr
with a gain setting of RGFR=1
(or perhaps RFGR=2
), and then send its output to your FSK demodulator, as you were trying to do when we started this conversation.
It world be interesting to see if with that attenuation it is now able to demodulate the FSK signal in the 4Msps case.
Franco
@fventuri Hi!
Sorry for dying on you. I took a break from this project for a few weeks and when I came back I basically decided I was going to just live with this issue. I've been working on the same project basically nonstop and the issue's been haunting me constantly.
I brought it up to a friend today (he has a real knack for this stuff) and he basically fixed it within 5 minutes of messing around. Setting the RFGR to 9 makes the issue entirely go away. My entire year is made at this point - I don't fully understand why this has fixed it but I don't care!
Anyway, I hope this puts you at peace in the way it did for me. Closing this issue. Thank you so much for the help!
Hello,
I have an existing application which uses the
rtl_sdr
command to get IQ data, which is then piped into an FSK demodulator. I want to use it with higher sample rates, so I purchased an RSP1A and am now using rx_tools to do the same thing. (Therx_sdr
command).For sample rates like 1MSPS, 2MSPS, etc. it works great. If I go well above 2MSPS (4MSPS, 8MSPS) I get nothing out of the demodulator. I've tried manually increasing the size of the filter. It's made the frequency graph look healthier when there's only background noise, but when there's an actual FSK signal present, I just get garbage on the frequency graph. No characteristic FSK signal like I get at 2MSPS.
Interestingly, this also occurs at (2M - 1) samples per second and (2M + 1) samples per second.
Is there anything obvious I might be missing? I noticed in the code that 1MSPS and 2MSPS are handled as special cases.
Also, my RSP1A works fine in SDR++.
Thanks!