QSpectrumAnalyzer now works with LimeSDR!

Just to let you know, my opensource spectrum analyzer app QSpectrumAnalyzer (and its new soapy_power backend) now works with LimeSDR.

There are still some problems, it seems that if you are changing frequencies quickly, there are some artifacts. You can temporarily solve it by adding --tune-delay 0.3 (or more) to additional backend parameters in Settings, but this of course will result in much slower spectrum sweeps. This has to be fixed in LimeSDR driver itself.

7 Likes

Nice! Look forward to trying it out this week :slight_smile:

Any info of why there are artifacts if I don’t wait at least 0.3 seconds after tuning before reading samples? Will it be fixed?

Do you have plans to add a broadband sweep capability? If not, do you mind if I fork and implement that myself? I’ve been working on a similar program from scratch, but yours far and away is beating where I am at.

Afraid not, but @zack or @joshblum may be able to help.

What do you mean by broadband sweep capability? QSpectrumAnalyzer is doing frequency hopping, so it is broadband. But right now this is limited (slow) on LimeSDR because of needed delay after changing frequency.

Or do you mean something like superfast hackrf_sweep implemented directly in LimeSDR firmware? That would be really great!

I am open to pull requests, bring it on! :wink:

Either or, being able to set a span to greater than 60 MHz at the very minimum is what I had in mind. Making a custom HDL image for fast tuning support actually sounds like a very good idea.

Unfortunately I’m not able to try your program out at the moment to see what is there and is missing - I get an immediate segfault with your program. I must have borked the installation and need to try again.

I’d look at the buffer clearing routines in the FPGA and driver code.
If your swept data is coming as fast or faster (or before the routine that clears the buffers even runs) than their clearing times you are in a race condition.

You can do even 4 GHz sweep if you want, there is no limit. Or am I misunderstanding you somehow?

Looks quite good. Have you tested installing QSpectrumAnalyzer into a python virtual environment? If not, I will try and report back.

Do you think it is a good or bad idea to merge Soapy_power into SoapySDR? The only reason I mention it is due to the large number of dependencies for all the radio software.
Qt, PyQt, Py3, Py2, osmo, numpy, scipy, etc., etc.

I expect that there will be still quite some changes in soapy_power, so I would prefer to develop it out of SoapySDR tree for now.

Dependencies aren’t that bad if you use yours distribution package manager (e.g. I am providing PKGBUILD for Arch Linux in AUR, so Arch Linux users can just do pacaur -S qspectrumanalyzer and that’s all). I hope that major distributions will package it in the future.

As for Windows, I am looking into creating installer (Python app frozen with cx_Freeze into exe, with all dependencies bundled with it). There has been some roadblocks (e.g. SoapySDR / Pothos has only 64-bit builds, but my Windows virtual machine is 32-bit), but I hope to finish it soon.

Also I am switching QSpectrumAnalyzer from PyQt4 to PyQt5 now as we speak :wink:

Can this program emit a tracking frequency? It would fulfill one of my greatest wishes for the LimeSDR. Especially if the tracking frequency could be synced to a harmonic or offset of the analyzed frequency, or visa-versa. I may hack this into the code if I can if it is not there. I was going to write something that just generated a CSV file to crunch with a spreadsheet but this would be a huge jump forward of that. Whenever I get my device, that is.

I understand about soapy_power.

Really appreciate these kinds of visual tools as an RF newcomer.

I don’t run arch or windows. But whenever I see PyQtx mentioned I grimace a little bit only because it has caused headaches in the past. Although it has gotten better.

Also I cannot see any reason why running QSpectrumAnalyzer from a python virtual env would not work. I have installed everything so far except PyQt4. (i am doing things different than below)

All it takes is to do these things:

python3 -m venv /path/to/py3virt
. /path/to/py3virt/bin/activate

test it

which python
which pip

pip install QSpectrumAnalyzer

The advantages of a python virtual env are:

  • no sudo needed
  • leave the native OS python install alone
  • can easily remove and recreate python virtual envs
  • can create many python envs and easily switch between them

The tuning of the frontend PLLs and streaming are basically independent. Those samples that are produced during tuning are basically not useful. I have a curious idea. Record the time getHardwareTime() before and after the tune operation. Even if the streaming is backed up a little you will know exactly which samples came from before the tune, during the tune operation (bad samples), and after the tune completed.

So basically I can’t be sure which samples come from which frequency? Isn’t there some sync/blocking mode? E.g. on RTL-SDR setFrequency call is blocking and I never get problem like this. Airspy seems similar in this (I am not sure now, but I definitely don’t get artifacts from previous frequency hops with it).

HackRF has similar problem, but much less bad (I only need to flush about 2 buffers after tuning step and then artifacts are gone).

Some drivers throw out the samples during tuning and some don’t. I guess you could say that limesdr is in the hackrf camp on this issue because the streaming and tuning are independent operations. But there is definitely a merit to having a feature like this, we could probably implement it in the SoapyLMS7 layer so fft and visualization applications would not have to reimplement the throwing out of the bad samples.

But currently, I would say that there are two ways know which samples are good and to which frequency they come from:

  • The timestamps which I mentioned above can be used to differentiate exactly which samples are before the tune, during the tune, and after.
  • Also I believe that stopping streaming, tuning, and starting the streaming would be an adequate solution. The buffers should flush in between the stop and start. So its only good samples to be read out.
    • This could work as a general solution for any hardware driver, but I could see that some drivers may not support doing this in rapid succession.

If we add a feature like this in SoapyLMS7, it will probably just implement one of the two above solutions. I would be interested to hear how one of these options effect the QSpectrumAnalyzer, if not just for quick test to see which feels faster or more reliable in recovering after a tune operation. That would influence which one we could push down in the SoapyLMS7 layer.

Looks like you have finished this already! Should I try it? I already am using it with PyQt4 and Python 3.6 (but not without the usual pain to make it work).

BTW thanks for the nice software and your big contribution.

p.s. Had an esoteric problem with python and some strange failures with SoapySDR and had to build python 3.6.0 shared library, some distros only deliver a static python lib

By stopping and starting streaming again you mean only deactivateStream / activateStream or also closeStream / setupStream?

I will try deactivateStream / activateStream first and let you know the results…

You can, it works great with PyQt5 (but PyQt4 is still supported, even PySide and PySide2 should work, thanks to Qt.py wrapper). I am waiting with new release till I can resolve this problem with LimeSDR and create Windows installer.

But now I have problem with SoapySDR under Windows 7 Pro (x64) in VirtualBox :-/ SoapySDR devices are detected without problems, but whenever I start streaming (I have tried CubicSDR, GQRX and my soapy_power), program simply freezes. If I use device directly (e.g. in GQRX), it works without problems, so it must be SoapySDR specific issue (USB virtualization works).

What do you mean by emitting tracking frequency? I am going to add peak detection algorithm in the future, so something like exporting detected peaks to file (or to some socket API?) would be enough?