777arc/PySDR

Synchronization of TX and RX Signals in BladeRF 2.0 xA9

Opened this issue · 23 comments

I want to implement a FMCW or a pulsed radar using a SDR I tried using Pluto sdr but that does not have any synchronization mechanisms, I do have a BladeRF in my laboratory and I saw that in the API to control the bladeRF there is a bladerf_sync_config(), bladerf_sync_rx(), bladerf_sync_tx() functions. So, I wanted to know that if I use these functions in my code then will the TX and the RX signals be tine synchronized.

Are you just trying to get the samples on the rx side that correspond to the exact moment you transmitting some samples fed to the SDR from the PC?

Well keep in mind, the signal transmitted by the SDR comes from samples sent to it by the PC, so there's some delay there, and then on the receive side there's delay before the samples show up to the PC. So maybe all you really need is accurate time-stamping? Or are you trying to feed in an external clock signal that you want the transmit and receive samples to align to? You'll have to provide more details about what you're actually trying to accomplish.

First off, not sure what you mean by "Pluto sdr but that does not have any synchronization mechanisms" because the Phaser is just a Pluto + Pi + phased array analog parts.

The code for that Phaser example is here https://github.com/jonkraft/PhaserRadarLabs/blob/main/FMCW_RADAR_Waterfall_ChirpSync.py
and the part you're interested in is here is at line 131. They are using the TDD module, which you can read more about here https://wiki.analog.com/university/tools/pluto/hacking/power_amp. No clue if the BladeRF has similar capabilities, you'll have to ask on their forum or support email. I think a lot of this functionality is AD936X specific, but it's possible the BladeRF API doesn't expose it like the Pluto API does.

Btw if you're going to IEEE Radar Conference in a couple weeks, I'm helping Jon with his workshops that include the Phaser.

Oh wow, didn't realize it wasn't supported in the stock Pluto's HDL, weird considering this page is Pluto specific and mentions TDD https://wiki.analog.com/university/tools/pluto/hacking/power_amp. How long ago did you ask? There's a comment in Jon's code that says

This script uses the new Pluto TDD engine
   As of March 2024, this is in the main branch of https://github.com/analogdevicesinc/pyadi-iio
   Also, make sure your Pluto firmware is updated to rev 0.38 (or later)

Also tagging @jonkraft in case he sees this. Could be a nice section for PySDR, to explain the TDD engine.

Oh ok, so yeah it is supported with the latest code, I think you'll just have to spend time diving deeper into Jon's Python example here https://github.com/jonkraft/PhaserRadarLabs/blob/main/FMCW_RADAR_Waterfall_ChirpSync.py because it's as close as you're going to get to what you want.

Yes, Ionut is the expert in this. So its good you connected on ez. But if you have a Pluto, you should be able to time align (though not perfectly phase synchronize) the start of transmit with the start of the receive buffer. You use tdd.channel[2] for the transmit buffer timing.

Yes, Ionut is the expert in this. So its good you connected on ez. But if you have a Pluto, you should be able to time align (though not perfectly phase synchronize) the start of transmit with the start of the receive buffer. You use tdd.channel[2] for the transmit buffer timing.

what if I want to continously switch between the tx and rx like a pulsed radar? like transmit for a certain amount of time and then turn off tx and then turn on rx and then repeat the same.

You can send 0+0j's to the transmitter to effectively turn it off, and as far as receiving, you can always toss out buffers if you don't care to process them, so I think you can get away using Jon's example as a starting point for your application.

okay I will try doing that. I tried using the same code given by jon but some of the functions are not being recognized by the python ide. I have installed the latest version of pyadi-iio and iio and the dependencies told by him in his video. I have cloned his repository from his github. and made no changes to it.

Screenshot from 2024-05-30 17-29-31

The phaser part id alright but the tdd.channel[0].enable = True
tdd.channel[0].polarity = False
tdd.channel[0].on_ms = 0.01
tdd.channel[0].off_ms = 0.1
tdd.channel[1].enable = True
tdd.channel[1].polarity = False
tdd.channel[1].on_ms = 0.01
tdd.channel[1].off_ms = 0.1
tdd.channel[2].enable = False

parts also are not bing recognized by the ide.

https://github.com/Yamakaja/gnuradio/tree/feature/gr-iio-tdd
Above is the link to a forked repository but for some reason when I install this gnuradio the tdd flow graph don't work. They throw a error saying
/home/deadshot/Downloads/TDD.py:11: DeprecationWarning: The distutils package is deprecated and slated for removal in Python 3.12. Use setuptools or check PEP 632 for potential alternatives
from distutils.version import StrictVersion
Warning: Ignoring XDG_SESSION_TYPE=wayland on Gnome. Use QT_QPA_PLATFORM=wayland to run on Wayland anyway.

Done (return code -11)

when asked on gnuradio support the creator of the fork said that the warning doesn't have anything to do with the block not working so I dont exactly know how do I proceed?

Pretty sure those 2 warnings don't have anything to do with why it's not working. But I can really only help with you getting it working in Python (not GR), and using Jon's example as a starting point.

That works for me I was just trying out all the options to get the signals synchronized. I also wanted to ask that if there is a documentation for the commands used by @jonkraft in his version of the code so that by refering to that documentaion I will be able to write a code of my own as I have no idea what work the functions called performs which makes it impossible to understand the code.

Which function are you talking about? The TDD stuff is implemented here and it's mostly just setting fields https://github.com/analogdevicesinc/pyadi-iio/blob/main/adi/tddn.py

A lot happens in the my_sdr.rx() call which is implemented here https://github.com/analogdevicesinc/pyadi-iio/blob/main/adi/rx_tx.py#L235

That's about all I can help you with though, for any issues with using the API or whatnot you can post a specific question to https://ez.analog.com/rf/wide-band-rf-transceivers/design-support/ and make sure to include minimal example code demonstrating the issue.

I checked this it doesn't have any information about channels tdd.channel[0].polarity = False what is channel[0], what does polarity mean the documentaion says use it to set polarity what True or False depits same with the other functions.

Not sure, you'll have to ask on the ADI support page I linked to, that way their response can be archived and easily found by the next person who comes along with the same question. Having the info living in this github issue wouldnt be great for long term indexing. I recommend compiling a list of these specific questions to include in your post.

Yes, Ionut is the expert in this. So its good you connected on ez. But if you have a Pluto, you should be able to time align (though not perfectly phase synchronize) the start of transmit with the start of the receive buffer. You use tdd.channel[2] for the transmit buffer timing.

@jonkraft which channels do I use to switch between the tx and the rx part as you said to use channel 2 for tx and which do I use for rx part as I am using my pluto in 1tx 1 rx mode as there is no need for me to use the second tx and rx and do I need to do any other thing, and I can keep my existing code same right.

Configure TDD controller

tdd.enable = False # disable TDD to configure the registers
tdd.sync_external = True
tdd.startup_delay_ms = 0
tdd.frame_length_ms = pulse_duration/1e3 + 1.2 # each chirp is spaced this far apart
num_chirps = 1
tdd.burst_count = num_chirps # number of chirps in one continuous receive buffer

tdd.channel[0].enable = True

tdd.channel[0].on_ms = 0.01
tdd.channel[0].off_ms = 0.1
tdd.channel[1].enable = True

tdd.channel[1].on_ms = 0.01
tdd.channel[1].off_ms = 0.1
tdd.channel[2].enable = False
tdd.enable = True

what channels should I use i'll change the on_ms and off_ms according to the channel