I am trying to demodulate GFSK signal, and extract the packets using GNURadio.

TX information:

It is basically BLE transmission but customized. BW: 2MHz, data rate: 1MSymbols/sec, 1 bit per symbol. Each packet is 160 bits (which equals to 181us duration). And the packets are repeated every 100ms, hence approx. 10 packets per sec

RX information:

I am using a BladeRF with 4Msps and storing it to a .complex and read back in GNU Radio. The samples are given through an LPF performing decimation by 2 which reduces the sample rate to 2Msps. Then I use a quadrature demodulation block following which I use a Symbol Sync block. After this I use a custom OOT module, to count the packets.

So, everything is perfect until the demodulation, after demodulation I can clearly see the data stream. Only thing is that we can't make a hard decision here (we have 2 samples per symbols). In order to fix that we pass it through the Symbol Sync block. Then we do packet detection


My main issue is not every packed is synced/recovered by this block. As most of the symbol timing recovery is a kind of estimation/control loop algorithm. Setting the correct parameters is very important. I played a lot with the parameters. And whatever I have set now works best for me. Even in this best-case scenario, I am losing some packet. The capture file I have is for 32.03 seconds, which approx. contains 319 packets, but I can only recovery 311 packets.

I have been experimenting with this for nearly a month, with different packet rates, like 10, 25, 50, 75, 100 packets per second. All the test capture is done in a very low noise environment, and RX close to TX. So, any channel effects can be ignored. I even tried inserting a matched filter before demodulation, use a polyphase clock recovery, etc. but still, packets are lost.

And every time packet loss rate is always 5% to 7%


1) why exactly this happens? is it because that the limit of symbol recovery can do or Am I doing something wrong?

2) is there any other alternative for this problem, to recovery 100% or at least with less than 4% loss? I have seen a technique which reverse engineer like M.ossmann's clock recovery use (https://github.com/mossmann/clock-recovery). But, I want to do it in real-time.

Any other suggestions to modify the algorithm or parameter or even approach are highly welcomed and appreciated....!!! I stuck with this problem for soo long and it's getting on my nerves.

Please, I am calling out experts in the field for help and looking for discussions.

Thanks in advance

P.S: I am attaching my screenshot of the GNU Radio flow graph. And also a plot showing how some packets are distorted after passing through the symbol sync block. The red is the bits of a packet after the symbol sync block and blue is before that. You can see that it's been lost many bits. Hence, the packet detection block is unable to detect it.

GNU Radio Flowgraph Symbol Sync Block Parameters Plot of a Packet before and after


Based on the suggestion from the comments, apparently the loop bandwidth and damping factor value are not very optimal. As my preamble is 8 symbols the loop should settle to linear operation within this time. This corresponds to the loop bandwidth of ~40KHz (normalized loop BW 20m). After these changes also I was still getting a 5% packet loss. In order to analyze a bit deeper, I created a bit more detailed graph with the debug signals from the Symbol Sync block. I have superimposed the recovered packet with error, instantaneous period, average period debug signals. I am attaching the graph for both cases, where the packet is recovered/detected good and the failure case. The first image corresponds to a good packet, the second image is for a bad packet. Success Case

Failure Case

  • $\begingroup$ Hi Yaaseen - I suggest looking at the waveforms at the input and output of each functional block and make sure technically the block is doing what you expect-- you need to narrow this down. Also the loop parameters do not make sense to me at all: if 500u means uHz and a damping factor of 3; I would be using a damping factor of 1 and loop bandwidth of 20KHz. Although I wouldn't start by just simply changing that but I would as I said make sure everything up to that point is doing what it should. $\endgroup$ – Dan Boschen May 3 at 2:54
  • $\begingroup$ To get any more meaningful input from here it may help to post more details once your problem is more narrowed down so that you can simplify the question (might be just to broad and open right now). $\endgroup$ – Dan Boschen May 3 at 2:57
  • $\begingroup$ Hello Dan - yes, I did that, the graph had 6 packet burst which is demodulated and passed through this Symbol Sync block. The first 4 packets were recovered properly, the last two weren't. What you are seeing here is the zoomed view of the distorted packet. And with respect to the loop bandwidth, it would be really helpful $\endgroup$ – Yaaseen Mohamed May 3 at 14:00
  • $\begingroup$ And with respect to the loop bandwidth, it would be really helpful if can tell how did you came up with that number (20kHz & 1). Because, I followed the documentation which " It should nominally be close to 0, but greater than 0. If unsure, start with a number around 2*pi*0.04, and experiment to find the value that works best for your situation" $\endgroup$ – Yaaseen Mohamed May 3 at 14:18
  • $\begingroup$ 2*pi*0.04 sounds like it is in units of fractional frequency not Hz. So that would translate to 80 KHz which is reasonable to me, see my further explanation in the answer below. Anywhere from 1/10 to 1/50th of the symbol rate is reasonable. $\endgroup$ – Dan Boschen May 3 at 14:27

The Symbol Synchronizer block is a PLL-based synchronizer that is trying to estimate the symbol clock period and symbol clock phase (aka timing offset) based on the samples coming in that represent the data symbols.

Being a PLL configured with static parameters, there is a fundamental trade off between acquisition speed and tracking stability of the symbol clock estimate. The more reactive the loop configuration, the faster it will acquire, but the more likely it may loose track later and cause an error. The more sluggish the loop configuration, the longer it will take to acquire, but it will track much better when locked.

You can speed acquisition by using a correlator out front (e.g. the corr_est block) that detects your preamble and marks the center of a symbol with a "time_est" tag. The symbol sync block will notice the "time_est" tag (or a "clock_est" tag) and reset it's tracking estimates right there to rapidly acquire lock.

But that is not your immediate problem.

For the symbol sync block to work well, you must understand the requirements, assumptions, and behaviors of the Timing Error Detector you have selected.

The M&M TED, with the default "bpsk" decision constellation, is expecting:

  1. symbols that are peaked in the center
  2. symbols that ideally have peak(trough) levels of $\pm 1$
  3. you to set an expected TED gain that comes from modeling and simulation of the TED in this particular situation (expected SNR, samples symbol in use, matched filter in use, etc.) in MatLab, Octave, Python or other M&S tool of your choice.

When you model and simulate the M&M TED, you may notice something peculiar about its behavior:

If you have a good estimate of the symbol clock period, then the M&M TED S-curve, and hence TED gain, collapses to $0$ on sequences of alternating symbols: $..., -1, 1, -1, 1, -1, 1, ...$

This is likely why you are failing to acquire lock at the beginning of some packets when starting with some random symbol clock phase (aka timing offset) estimate.

Either use a correlator that marks a preamble symbol to jump-start the timing synchronization, or use a different TED. The M&M TED is old technology.

When using a different TED, make sure you understand its derivation and the assumptions that went in to its derivation.

Also design and modeling and simulation in MatLab, Octave, R, Python, or whatever, is absolutely essential if you want something other than suboptimal results. GNURadio is a fine prototype tool, but is not a very good up front design tool.

Please read this brief, if you haven't already:


| improve this answer | |

(See the helpful comments below by @AndyWalls who wrote the timing recovery block for GNU Radio)

The loop bandwidth parameters do not sound right. Consider that once the loop has converged to a linear operation the settling time is proportional to the inverse of the bandwidth (for a first order loop the 10% to 90% settling is $0.35/BW$). Acquisition is even longer and would take even more time to converge.

The setting of 0.0005 is likely in fractional frequency units ($f/f_s$) with $f_s = 2 MHz$ at 2 samples/symbol. So this would be a loop bandwidth of 1 KHz, suggesting a settling time on the order of 350 us once the loop has converged to linear operating range. That is 350 symbols! Consider how many symbols are allocated to timing acquisition in the packet and use that as a guide to set the loop bandwidth. Setting it too high will enhance tracking noise which may ultimately limit performance. Setting it too low and it uses up too much of the packet to establish timing. A good rule of thumb is 1/10 to 1/50th of the symbol rate. This is similar to the considerations made for carrier tracking loop bandwidth that have been detailed at this post: Carrier Tracking Loop: Tracking noise vs Phase Noise Trade-off

Further the damping factor of 3 is also very high! Meaning severely over-damped. The damping factor that optimizes overshoot with settling time in a 2nd order system is 0.7 and 1 would be a reasonable value to start with, not knowing the implementation details. (See slide 30 at this link showing transient response versus damping factor: https://www.slideshare.net/amrelsayedm/modern-control-lec-03-feedback-control-systems-performance-and-characteristics )

Another suggestion is to interpolate the signal prior to symbol recovery as a diagnostic so that you can see what is happening with regards to timing convergence, by setting the samples higher and comparing output to input. Eye diagrams are very helpful as well.

Also the M&M Timing Error Detector is very sensitive to carrier offsets but has higher SNR performance once converged. If the Gardner TED is an option consider using that one as the SNR of the timing loop will likely not be limiting overall SNR.

| improve this answer | |
  • 1
    $\begingroup$ @Dan_Boschen I wrote the "Symbol Synchronizer" block implementation in GNU Radio. In case it helps you improve your answer: gnuradio.org/grcon/grcon17/presentations/… . Yes, the Gardner TED is available, as is a small signal ML approximation TED fred harris describes in some of his papers. I also provided an example Octave script for estimating TED gain for some TEDs: github.com/gnuradio/gnuradio/blob/master/gr-digital/examples/… $\endgroup$ – Andy Walls May 4 at 16:41
  • $\begingroup$ @AndyWalls thanks! I look forward to seeing these presentations. Was there anything particular in my answer that wasn’t accurate (just so we fix that right away). $\endgroup$ – Dan Boschen May 4 at 16:45
  • 1
    $\begingroup$ Also the flowgraph above is very basic and is missing some things like CFO correction and a correlator to match and mark a symbol in the preamble to jump start the symbol timing acquisition. This is necessary, because the "quad demod" block just does a $d\phi/dt$ operation to do FM demod, and will generate horrible noise output when operating on interburst noise. This could have the initial state of the symbol sync block pulled way off for the nominal expected symbol rate when a burst comes in. $\endgroup$ – Andy Walls May 4 at 16:46
  • $\begingroup$ @AndyWalls It would be an awesome diagnostic feature (if not already implemented) for the block to output its measured error per symbol (to evaluate response times and transient behavior). Does the block already do this? $\endgroup$ – Dan Boschen May 4 at 16:49
  • 1
    $\begingroup$ The block has the normal output, and 3 additional debug outputs: the error term, the instantaneous symbol period estimate, and the average symbol period estimate. One of the slides at the end of the brief I linked shows the plot of the debug outputs with an intentionally poorly tuned loop. $\endgroup$ – Andy Walls May 4 at 16:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.