> Date: Sat, 18 Jul 2020 12:06:11 -0400 > From: Nicholas Savka <nicholas.s.sa...@gmail.com> > To: discuss-gnuradio@gnu.org > Subject: Correlation Estimator Questions > > Hello, > > My ultimate goal is to use the correlation estimator block for > synchronization using a preamble in order to send packets of digital > data > from one sdr to another, both running gnu-radio. In order to > understand how > the correlation estimator works, I am looking at the provided example > "example_corr_est_and_phase_sync." It looks like this example is > using a > BPSK modulation scheme and I am trying to modify it to work with QPSK > instead to make sure I know how it works, but I am running into > problems. I > have four questions: > > 1.) > I do not understand the purpose of the "tag marking delay" entry in > the > correlation estimator block. How should this value be determined?
The block will output a tag on the output sample stream when it detects a correlation. By default (delay of 0) this tag will be set at the start of your preamble. The tag marking delay lets you adjust the position of the output tag in units of samples. You should set this empirically to be at the center of the first symbol in the preamble. > 2.) > How does the correlation estimator "talk to" the costas loop and > Polyphase > Clock Sync blocks? Is there something going on behind the scenes here > that > I cannot see? Is it somehow passing the frequency/phase correction > information to these blocks? Using the time_est tag on the output sample stream, to tell the clock sync blocks, "This is the approximate center of a symbol, reset your symbol clock timing recovery". A CPO estimate is also output on the "phase_est", but I don't think any block uses it. > 3.) > I think my main issue is that I do not understand how to format the > "Data > Vector" entry in the "Modulate Vector" block. This is my (probably > incorrect) understanding: > > I want my preamble symbols to be [1+1j, 1+1j, 1+1j, -1-1j, -1-1j, > 1+1j, > -1-1j] > > My constellation object has the following parameters: > Symbol Map: [0,1,2,3] > Constellation Points: [(-1-1j),(-1+1j),(1-1j),(1+1j)] > > Therefore, my desired preamble would map to: [3,3,3,0,0,3,0] > So, in the "Data Vector" box in the "Modulate Vector" block, I should > enter: [0x3,0x3,0x3,0x0,0x0,0x3,0x0] > 4.) > Why is the Modulate Vector block needed at all? Why can I not simply > enter > [1+1j, 1+1j, 1+1j, -1-1j, -1-1j, 1+1j, -1-1j] into the field for > "Symbols" > in the correlation estimator block? The corr_est block "Symbols" input wants the correlation/matched filter taps (*before* time-reversal and conjugation) for the preamble it is trying to match. It can't use symbols from the constellation, because it doesn't make any assumptions about your pulse filter, you modulation, or how you truncate the transient of pulse filtering your preamble symbols. I suggest that you do not use the Modulate Vector block, as it doesn't give you insight or much control into what it is actually producing. Instead, produce your correlation/matched filter taps yourself using MatLab or Octave or Python. See the attached Octave scripts for a QPSK example with your preamble and symbol mapping. BTW, the GNURadio Constallation object will silently scale your constellation so that the constellation points have an average radius of 1. So your constealltion points are really 1/sqrt(2) * [(-1-1j),(- 1+1j),(1-1j),(1+1j)], as far as GNURadio is concerned. Regards, Andy
pkg load signal; % Octave needs this Fs = 20000; % sample rate fc = Fs/4 * 1; % optional IF frequency Rs = 2000; % symbol rate sps = Fs/Rs; % samples per symbol % % Root raised cosine pulse filter % https://www.michael-joost.de/rrcfilter.pdf % r = 0.22; % bandwidth factor ntaps = 8 * sps + 1; st = [-floor(ntaps/2):floor(ntaps/2)] / sps; hpulse = 1/sqrt(sps) * (sin ((1-r)*pi*st) + 4*r*st.*cos((1+r)*pi*st)) ./ (pi*st.*(1-(4*r*st).^2)); % fix the removable singularities hpulse(ceil(ntaps/2)) = 1/sqrt(sps) * (1 - r + 4*r/pi); % t = 0 singulatiry sing_idx = find(abs(1-(4*r*st).^2) < 0.000001); for k = [1:length(sing_idx)] hpulse(sing_idx) = 1/sqrt(sps) * r/sqrt(2) * ((1+2/pi)*sin(pi/(4*r))+(1-2/pi)*cos(pi/(4*r))); endfor % normalize to 0 dB gain hpulse = hpulse / sum(hpulse); delay_hpulse = (ntaps-1)/2; % % Create a correlation filter for a QPSK preamble % % preamble_symbols = [3 3 3 0 0 3 0]; constellation_map = 1/sqrt(2) * [-1-1j -1+1j 1-1j 1+1j]; % Map the preamble symbols to the constellation points preamble_qpsk = constellation_map(preamble_symbols+1); % Upsample and pulse shape the preamble x = sps*[upsample(preamble_qpsk, sps), zeros(1, delay_hpulse)]; preamble_bb_init = filter(hpulse, [1], x); % Discard the most of the transient preamble_bb = preamble_bb_init(floor(delay_hpulse*0.70)+1:end); % Set the correlation preak ref to the middle of the last symbol preamble_bb = preamble_bb(1:(end-ceil(sps*0.75))); % Modulate the preamble up to IF and then create the correlation filter k = [0 : length(preamble_bb)-1]; preamble_if = preamble_bb .* exp(1j*2*pi*fc/Fs*k); % Use preamble_if for the "Symbols" input of the corr_est block preamble_if % Use this for the actual correlation filter taps in Octave/Matlab hcorr = fliplr(conj(preamble_if)); figure(1); t1 = [0:length(preamble_bb_init)-1]/Fs; plot(t1, real(preamble_bb_init), 'o-', t1, imag(preamble_bb_init), 'x-'); xlabel("Time (s)"); ylabel("Amplitude"); title("Pulse Shaped Preamble Symbols - Baseband, Untrimmed"); figure(2); t2 = [0:length(preamble_bb)-1]/Fs; plot(t2, real(preamble_bb), 'o-', t2, imag(preamble_bb), 'x-'); xlabel("Time (s)"); ylabel("Amplitude"); title("Pulse Shaped Preamble Symbols - Baseband, Trimmed"); figure(3); t3 = [0:length(preamble_if)-1]/Fs; plot(t3, real(preamble_if), '.-', t3, imag(preamble_if), '.-'); xlabel("Time (s)"); ylabel("Amplitude"); title("Pulse Shaped Preamble Symbols - Modulated to IF"); figure(4); t4 = [0:length(hcorr)-1]/Fs; plot(t4, real(hcorr), '.-', t4, imag(hcorr), '.-'); xlabel("Time (s)"); ylabel("Amplitude"); title("Preamble Correlation Filter Taps at IF");