jgaeddert / liquid-dsp

digital signal processing library for software-defined radios
http://liquidsdr.org
MIT License
1.83k stars 429 forks source link

sym_track auto sync? #215

Open dj0abr opened 3 years ago

dj0abr commented 3 years ago

I'm using the latest code (11.2020). The symbol tracker works fine when I do a symtrack.._reset() as soon as a signal is there. But usually I receive just noise. When I get a signal (QPSK, 8PSK... does not matter), then symtrack does not sync. But when I do a symtrack_reset as soon as the signal is there, then it syncs immediately.

Is this the normal behaviour, or is there anything to do the get it synchronized without an additional reset ?

jgaeddert commented 3 years ago

This is normal; running noise into the synchronizer will cause it to drift off time and frequency significantly such that when a signal does become present, it cannot lock onto it. Resetting the synchronizer will set its carrier offset to zero and allow it to lock on.

The symtrack object was intended to track to waveforms with continuous transmission. That being said, there are a few options for moving forward with what you're doing:

  1. you can try to detect when a transmit occurs (a change in power envelope, detecting a preamble, etc.) and then feed samples into the synchronizer
  2. you can use one of the build-in framing methods such as the flexframe which takes care of synchronization for you
  3. create your own waveform and use some of the built-in detection and synchronization objects and algorithms in liquid

If you give me a little more information on what you're trying to do, I can provide you with a little better support on this.

dj0abr commented 3 years ago

thank you, ok, then it works as expected.

I build a modem for QPSK and 8PSK transmission via soundcard into an SSB transmitter/receiver. This project is also hostet on github: https://github.com/dj0abr/SSB_HighSpeed_Modem

First I developed it in GnuRadio, but for Linux/Windows portability I made it with liquid-DSP. The software works very well on Linux and Win10 (compiled with minGW64). Your symtrack object work significantly better then the GR's Polysync+CostasLoop. Symtrack allows about 4dB more noise and still syncs well.

The only issue is to reset symtrack as soon as a signal is received. Currently I reset every 4 seconds when I don't see a preamble, which is quite long.

Detecting the level of the receiver is difficult because when no signal is present the receiver's AGC will amplify the noise, so the level of noise and signal is almost the same. Is it possible to limit how far the synchronizer can get off time and frequency ? Maybe, if I set tight limits then it is able to sync ? For QPSK, is there a recommended pattern which makes it easier for the synchronizer to sync ? (I am able to compile liquid-dsp for Linux and Windows, so if required I can access code or variables which are not available in the default library).

jgaeddert commented 3 years ago

Sorry for the late reply. There currently is no interface to limit the frequency offset (or timing rate drift). Again, the symtrack was designed for a constant stream of data symbols, not bursty transmissions. If you did limit the range this would certainly help pull-in times, but then would also limit the range of offsets you could account for.

As for a recommended pattern, transmitting +1, -1, +1, -1,... puts maximum energy in the signal's transition bands which helps timing and carrier recovery algorithms. It's a bit inelegant but is quite effective.

The best solution would be to transmit a known pseudo-random sequence at the beginning of the transmission and then correlate the received signal with this. Once it's detected, you can get coarse estimates for carrier phase/frequency, timing, and gain offsets. From there you can use the symtrack object to track the rest of the frame.

Take a look at examples/qdetector_crcf_example.c. It's fairly long, but demonstrates how the qdetector does much of this for you.

Additionally, check out examples/framesync64_example.c; this pulls everything together in a simple package where you specify a payload of 64 bytes (or NULL for random data), and it generates a frame for transmission. On the receive side, you stream samples into the synchronizer and it invokes a callback every time a packet is found, accounting for timing, carrier, gain, etc.

Feel free to tinker with these and get back to me if you have any ideas or suggestions!

dj0abr commented 3 years ago

thanks for your explanation. I did some progress and its working well. Regarding your recommended pattern what do you mean with +1. -1, +1, -1. In case of qpsk I have 0,1,2,3 and after the modulator a get the constellation. So where to send +1,-1 ?

jgaeddert commented 3 years ago

Right! So all I mean with +1,-1,+1,-1... is to ensure that the sequence uses antipodal points on the constellation. For QPSK you might have this mapping:

           ^ Q
           |
   (1)     |     (0)
           |
           |
-----------+-----------> I
           |
           |
   (3)     |     (2)
           |

so you might send the symbols 0, 3, 0, 3,... or 1, 2, 1, 2, ...