-
Notifications
You must be signed in to change notification settings - Fork 7
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
Query - support for dynamic frequency changing at runtime #45
Comments
@jcfitzpatrick12 - Jimmy, congratulations for the excellent work on SPECTRE, and I am happy to hear that the gr-sdrplay3 OOT module is useful in your research. I had never thought about message ports in my source blocks, however tonight I took a look at a couple of GNU Radio in-tree modules, and I think they are easy to add. To understand how they work and make sure they would fit your requirements, tonight I implemented a message port called I just pushed these changes to the new If it works and it is useful, I think I'll add similar message ports for other commonly changed settings, like the IF and RF gains. Franco |
@fventuri, thank you for the swift reply! This is great news, I will be able to start testing now. I will get back to you once I give the code on your new branch a go. It will take some time to do thorough testing (I need to create a custom sink block to drive the sweep and a custom sink block to save the swept IQ data to file), but I'll get back to you on this thread as soon as I can once I have done some preliminary work. Jimmy |
I have done some preliminary testing and am keen for your insight. I have created a source block called "Sweep Driver" which outputs floats in steps according to user defined variables: the samples per step, the minimum frequency, the maximum frequency and the frequency step. An example output would be for 2, 10MHz, 30MHz, 3MHz respectively: 10, 10, 13, 13, 16, 16, ..., 28, 28 (then it resets) -> 10, 10 Though the samples per step is larger than that in practice. Every time the block steps upwards in frequency, it publishes a message to the output port with the new frequency. Via the flowchart, I connect this output message port to the input message port which tunes the center frequency of the RSP devices. I have been experimenting with this and message passing to see how quickly I can update the center frequency of an RSP1A using your recent changes, however, I seem to be hitting some sort of limit with how quickly I can do this. Outwith gnuradio (and neglecting all hardware + system delays) the physical time between tuning would be dt = (samples per step) * 1/(sample rate). I was hoping for a dt of the order of somewhere between 0.001s -> 0.01s, but in practice, I can only get away with dt ~ 1s which is much too slow for what I need ! If I go below this, the receiver stops collecting data and just crashes gnuradio (sometimes the SDRPlayAPI stops responding and I have to restart my computer). I was wondering you might know:
If message passing was too slow, I wonder if it would be possible to create an input stream into your source blocks, and work with the input stream from sweep driver directly rather than via messaging. My knowledge of gnuradio runtime scheduling, the inner workings of the message passing API and your source blocks are limited, so any help is greatly appreciated. I can give you more information if needed, and thank you for any time you have for this :) Jimmy |
Jimmy, The reason I think this might be the case is because changing the center frequency is an asynchronous operation in the SDRplay API. First one has to change the center frequency setting ( I implemented a mechanism to wait for that parameter change in the SoapySDRPlay3 driver ( https://github.com/pothosware/SoapySDRPlay3/blob/master/Streaming.cpp#L94), but it is currently not in this GNU Radio OOT module. Franco |
I forgot that a couple of years ago I started to implement this 'wait for updates' approach in the When I have some time I'll have a look at what I did there and I hopefully I'll be able to port it to the On the other hand while this might definitely prove that the problem stems from the internals of the SDRplay API, it won't give you a way to address it, since the SDRplay API is proprietary and we can't change the way it works (but understanding the problem might give us some good ideas). Franco |
Great, thanks for the info! Like you say, it will be good to understand exactly what's causing the problem so to hopefully come up with an alternative. In the meantime, I'll keep fiddling with it and see how I get on. Please let me know if you make any headway ! Jimmy |
Hi Franco, Interesting developments, I think I've resolved the crashing issue! The flowchart I was using to test the frequency sweep included five blocks: the RSP1A source, the sweep driver source block, a throttle block, and two GUI sinks. In particular, there was some very odd behaviour regarding the throttle block: I noticed that the script completely crashed when I omitted it, and when I did include it, the script exhibited the cut-off behaviour I described before. I understand that throttle blocks should not be used in conjunction with hardware source blocks, so this was really puzzling behaviour. I resolved the issue by including an input port to the "Sweep Driver" block and connecting it with the output of the RSP1A. It doesn't do anything with the samples internally, but I envisioned that this would bound the Sweep Driver's output with exactly the receiver's output. I can now decrease the samples per step further and tune more rapidly without crashing! Of course, I'll look into this further, but certainly progress! As usual, thanks for all your help so far. Jimmy |
Although I shouldn't be so hasty in celebration, there does seem to be a jitter at a certain cut-off point (maybe due to the API issue you were discussing), but at least it's not crashing! |
Jimmy, I am really happy to hear you are making good progress there. When I was working with the SDRplay API on another SDR program (Linrad), I noticed something about how the SDRplay API and those RX callbacks work. I posted about it on Linrad group on Google groups: https://groups.google.com/g/linrad/c/3ySgbS592EY/m/HHwm1i-4AgAJ If you want to take a better look at this behavior, you may want to try my little utility program Franco |
No worries at all! I'll look at what you've described above and tinker with the single tuner recorder utility program. I've noticed that the "minimum time interval between tuning before jitter starts happening" is roughly constant for all sampling rates (around 30-50ms), and I'll explore this further too. |
Jimmy, Since this change for the option to enable synchronous updates is orthogonal to the message passing changes (and I plan to eventually merge them to the I also temporarily added a few debug lines to print the elapsed time (in ns) every time there's an update to one of the parameters of the RSP while streaming. I then ran a few tests changing the center frequency both in asynchronous mode (i.e. the way the blocks in the Franco |
Hi Franco, I appreciate the detailed response! Apologies for the delay, I've had a hectic weekend. I am currently doing some testing following your changes and I'll report back in this thread soon :) |
I have been testing your changes by attempting to create a stitched spectrogram over the FM band, sweeping in non-overlapping 8MHz steps from 80MHz to 120MHz. What is interesting, is the latency is still very visible! Broadly speaking, the spectrogram creation is in two steps: Binary data collection An important assumption in the above setup is that the frequency I am attaching to each sample (i.e. the internal current frequency in sweep driver) is actually representative of the centre frequency that the sample was collected at. It will be seen below that the latency plays a part in throwing this off. Post-processing The base-band spectrograms are then displaced in frequency according to the tagged current frequency for that step, and stacked in a way we pretend they are time coincident over the duration of the sweep: You can see the latency as follows. Consider the lower left portion of the spectogram: The very bottom segment is the first step collected by the program (collected at 84MHz, with 8MHz bandwidth). After a set number of samples (in this case, 600000 samples), the current_frequency variable was incremented to 92MHz. This step is directly above in the plot, but as mentioned, this is due to the assumed time-coincidence of the steps in the post-processing. You can see that although the samples have been TAGGED at the new current frequency, in-fact, they are still being produced at the old center frequency, up until a short duration later. Lowdown |
@jcfitzpatrick12 - thanks for your comments that help me understand better what you are trying to achieve. Perhaps the solution to your problem would be by adding 'stream tags' (https://wiki.gnuradio.org/index.php?title=Stream_Tags) to the SDRplay RSP block work function whenever the center frequency (and sample rate and gains) are flagged as changed in the RX callback function. From an initial look at that RX callback function, I think this might require adding some sort of buffer to keep track of when these changes are signaled besides the regular stream of data, and at this point I don't have a good idea of the best way to do it. I'll need some time to think this through. Franco |
As always, there's no rush at all. I appreciate the time you're putting into this. I can look into what it would take on my side to adapt my post-processing and blocks to stream tags too :) |
Hi @fventuri How are you? I haven't had as much time as usual to work on this; how significant life events get in the way! However, I've been making steady progress and should be able to handle stream tags appropriately in post-processing. Specifically, I can manage a variable number of samples at each frequency, which seems inevitable given the asynchronous nature of the messaging API and the behaviour of the SDRPlay API itself. Tagged Staircase
The block outputs a sequence of complex numbers where the imaginary part is always zero, and the real part forms a "staircase" pattern according to the user inputs. Each step in the real part has an increasing length as follows: (1,...,1),(2,...,2),(3,...,3),...,(N,...,N),(1,...,1), and so on In particular:
Once the maximum step size Additionally, the block tags the first sample of each step with a frequency tag ( Modified Sink (rx_freq_0, n_0, rx_freq_1, n_1, ..., rx_freq_N, n_N) where n_i is the number of samples assigned with frequency "rx_freq_i". This number of samples is inferred from the tagged stream itself at runtime. In brief, for two neighbouring frequency tags in the stream tag_i, and tag_j (i<j), all samples z_k, with k in [i, j), correspond to the frequency described by tag_i. Post-processing I have done some refactoring in my own code to nicely accommodate the detached header, and I am currently neatening up the post-processing for the swept spectrogram. Going Forward Jimmy |
@jcfitzpatrick12 - thanks for the update and the great news! I started working on them a couple of weeks ago (or perhaps three), but then I got sidetracked with something else (another SDR that uses an FPGA and therefore should be a lot of fun), so I kind of put this project aside. The SDRplay API provides only three pieces of information in the RX callback API:
Unfortunately, as far as I know, the RSPs have no 'knowledge' of time, i.e. they just stream I/Q samples at the requested sample rate. They do have a port for an external clock reference, so you might be able to calibrate them with a known reference signal at the beginning of your flowgraph (and perhaps periodically every second or something like that), and be able to figure out the exact time of each sample this way. I am kind of waving hands here, but I hope you get the idea. Franco |
Sounds cool about the SDR, a very reasonable sidetrack ! Take as much time as you need; there's a lot I can do on my end in the interim. Timing with an external reference is certainly something I'll look into later down the line. The Sun was very active the last couple of days with some nice broad-band radio bursts. I'm looking forward to when I can get the sweep up and running to see if it works in practice :) |
Hi Franco, How's it going ! Any movement on this? Now at a bit of a standstill. Is there a possibility it could be done this weekend ? I was looking into testing my code with the USRP B200mini (https://www.ettus.com/all-products/usrp-b200mini/) which supports message passing and frequency tagging, but it's very pricey 😅 |
Jimmy, thanks for the reminder! After that, I plan to begin working on adding stream tags to the source blocks - thanks for mentioning the USRP B200mini; I am going to look at the code for that source block to see how they handle stream tags (I am very new to them), so I can figure out how to do it (since the SDRplay API sends the events in the receive callback function, I need to figure out the best way to make them available in the GNU Radio block When writing new code I already have problems giving and keep deadlines, let alone for something that I do as a hobby in my free time. Franco |
Hi Franco, I appreciate the update ! the time question was bluntly put only so I could figure out out how I'll proceed throughout the week and beyond. You've already done loads so far, the code will come when it comes 🤲 I might have to bite the bullet for the b200mini but it looks quite cool in any case. Jimmy |
Minor update: after some deep internal reflection I went ahead with the purchase, so if it helps I'll let you know how I get on with the frequency sweep in practice ! Likewise, I appreciate this is a side gig for you, so if all works out with the USRP b200mini, I can even give a go at implementing the frequency tagging in a forked gr-sdrplay3 repo. |
Jimmy, excellent choice! If you are using GNU Radio in a professional/business context (i.e. not as a hobby like many of us), you will not be disappointed by the USRP SDRs, since they are first class citizens of the GNU Radio ecosystem: their modules are in-tree, and from what I can tell most of the experts in the GNU Radio discussion mailing list either work for Ettus Research/NI or use GNU Radio with a USRP SDR. On my side, this morning I looked at the GNU Radio code for the B200mini and other similar blocks where they do stream tags, and it doesn't look as bad as I initially thought. I still have to figure out the correct way to keep the different threads in sync and generate those tags with the right sample number, but hopefully I can figure that out too (and soon). Franco |
Good to hear it's worth it, and it certainly sounds non-trivial with implementing the tags. I'll report back on this thread when I make a bit of progress; the new SDR should be arriving later this week and I've a bit of tinkering to do to integrate it into spectre. Jimmy |
@jcfitzpatrick12 - I just pushed out a new version of the To enable this feature, please go in the The tag for changes to the center frequency is called Franco |
Hi Franco, Brilliant! I will be back late after work today, but I'll take a look when I'm back, do some testing and get back to you. Thanks, |
I am still doing some testing, but everything is looking really promising! It looks crude at the moment, but I managed to create my first swept spectrum over the FM band: And the spectrogram at each "step" is being correctly resolved, without any of the issues I was having previously: I still need to do some amount of further testing (and resolve some bugs in my post processing), but I'll get back on this thread once I've cleaned everything up. As one notable point, there is an issue when "cmaking" the OOT module in the message passing branch (see the attached text file: I am currently applying a bandaid fix, by replacing "SDRPLAY_RSPdxR2_ID" with "SDRPLAY_RSPdx_ID" where it is complaining, but I thought to let you know in any case. I know I've said it many times but thank you so much, I'm really excited that it is working! Jimmy |
Jimmy, thanks for the kind words and I am really glad to see that your first tests with the FM band look really good! And thanks for the hint about the USRP B200mini; I have been looking at their code a little bit more, and I see how they pass frequency changes and other commands via a message port. I think their approach is way more flexible than just a port for the frequency the way I do now, so I'll probably change the RSP source blocks to work the same way. Regarding that error message with your build not being able to find 'SDRPLAY_RSPdxR2_ID', I suspect it is because on your computer you have an older version of the SDRplay API, not the current one (3.15): https://www.sdrplay.com/api/ Franco |
Excellent, upgrading the API fixed the issue; thanks for the heads up. Using your new tags and message port, I've also added a sweep mode to the RSP1A receiver. SPECTRE can now generate spectrograms over a frequency range and time/frequency resolution comparable to the Callisto spectrometer: (https://www.e-callisto.org/), using much cheaper equipment in a (relatively) receiver-agnostic way. Next steps will be to include more SDRplay devices (using gr-sdrplay3) and additionally try and integrate USRP receivers. For interest, the set-up I am using with your block looks like this: The Sweep Driver block manages frequency sweeping by counting samples from the receiver. After reaching a defined number of samples, it increments the frequency and sends a message to update the receiver's centre frequency. The tagged data stream from the receiver is then saved by the Batched File Sink, which saves the data in a way we can reconstruct the swept spectrograms. While there are definitely a few artefacts (when collecting data for a long period of time, occasionally it looks like the data gets mixed up), I'd like to spend some time figuring these out before "reporting a bug" in case it's an issue at my end. There are definitely significant limits to this approach, but for the most part, things are looking very good! In any case, I'm more than happy to close this issue 🕺 Another FM band spectrogram, this time with the RSP1A: Jimmy |
@jcfitzpatrick12 - very nice results! It looks like you change frequency every 400k/8M = 50ms, which IIRC is in the same order of magnitude of the latency of the SDRplay API, which means that perhaps some of those frequency changes occur when the previous change is not fully competed, and in that case the behavior of my code and the SDRplay API might be undefined. Another option to try could be using zero IF, no decimation, and disabling DC offset correction and I/Q imbalance correction in the source block to see if that helps with the artifacts (you'll have to do some post processing for DC offset and I/Q imbalance in another GNU Radio block downstream). Franco |
Hi Franco,
I am writing a program called SPECTRE, which is a Python-based framework for recording and visualising radio spectrograms. With the help of your repository, I have integrated (so far!) an RSP1A and RSPduo into the program and I am currently using them for solar radio observations.
I am now looking to implement one of the program's critical functionalities: a receiver-agnostic frequency sweep, which will allow the program to capture spectrograms over a large frequency range. However, I cannot find any obvious way to dynamically change the centre frequency of the receivers at runtime. I have noted that message passing may be a route forward. I was hoping for your insight into:
I require good performance, in the sense that delay should be minimised between updating the centre frequency in the running flowchart and propagating to the receiver itself (I am looking to tag individual samples with the appropriate center frequency it was collected at). Currently, the program is limited to a fixed centre frequency, with the bandwidth capped by the sample rate of the receiver. So, being able to dynamically update the center frequency of the receivers would be a massive help in improving SPECTRE.
If you need any more information, please let me know.
For your interest, I have included an example image of a solar radio burst captured with SPECTRE and an RSPduo, thanks to gr-sdrplay3 :)
The text was updated successfully, but these errors were encountered: