freedv-gui/codec2-1.2.0/octave/qpsk.m

141 lines
3.5 KiB
Matlab

% qpsk.m
%
% David Rowe Sep 2015
%
% Octave functions to implement a QPSK modem
1;
% Gray coded QPSK modulation function
function symbol = qpsk_mod(two_bits)
two_bits_decimal = sum(two_bits .* [2 1]);
switch(two_bits_decimal)
case (0) symbol = 1;
case (1) symbol = j;
case (2) symbol = -j;
case (3) symbol = -1;
endswitch
endfunction
% Gray coded QPSK demodulation function
function two_bits = qpsk_demod(symbol)
bit0 = real(symbol*exp(j*pi/4)) < 0;
bit1 = imag(symbol*exp(j*pi/4)) < 0;
two_bits = [bit1 bit0];
endfunction
% Inserts pilot symbols a frame of symbols. The pilot symbols are
% spread evenly throughout the input frame.
function frameout = insert_pilots(framein, pilots, Npilotstep)
lpilots = length(pilots);
lframein = length(framein);
frameout = zeros(1, lframein + lpilots);
pin = 1; pout = 1; ppilots = 1;
while (lpilots)
%printf("pin %d pout %d ppilots %d lpilots %d\n", pin, pout, ppilots, lpilots);
frameout(pout:pout+Npilotstep-1) = framein(pin:pin+Npilotstep-1);
pin += Npilotstep;
pout += Npilotstep;
frameout(pout:pout) = pilots(ppilots);
ppilots++;
pout++;
lpilots--;
end
endfunction
% Removes the pilots symbols from a frame of symbols.
function frameout = remove_pilots(framein, pilots, Npilotstep)
frameout = [];
lpilots = length(pilots);
pin = 1; pout = 1;
while (lpilots)
%printf("pin %d pout %d lpilots %d ", pin, pout, lpilots);
%printf("pin+spacing-1 %d lvd %d lframein: %d\n", pin+spacing-1, lvd, length(framein));
frameout(pout:pout+Npilotstep-1) = framein(pin:pin+Npilotstep-1);
pin += Npilotstep+1;
pout += Npilotstep;
lpilots--;
end
endfunction
% Estimate and correct phase offset using a window of Np pilots around
% current symbol
function symbpilot_rx = correct_phase_offset(aqpsk, symbpilot_rx)
rx_pilot_buf = aqpsk.rx_pilot_buf;
Npilotstep = aqpsk.Npilotstep;
Nsymb = aqpsk.Nsymb;
for ns=1:Npilotstep+1:Nsymb
% update buffer of recent pilots, note we need past ones
rx_pilot_buf(1) = rx_pilot_buf(2);
next_pilot_index = ceil(ns/(Npilotstep+1))*(Npilotstep+1);
rx_pilot_buf(2) = symbpilot_rx(next_pilot_index);
% average pilot symbols to get estimate of phase
phase_est = angle(sum(rx_pilot_buf));
%printf("next_pilot_index: %d phase_est: %f\n", next_pilot_index, phase_est);
% now correct the phase of each symbol
for s=ns:ns+Npilotstep
symbpilot_rx(s) *= exp(-j*phase_est);
end
end
aqpsk.rx_pilot_buf = rx_pilot_buf;
endfunction
% builds up a sparse QPSK modulated version version of the UW for use
% in UW sync at the rx
function mod_uw = build_mod_uw(uw, spacing)
luw = length(uw);
mod_uw = [];
pout = 1; puw = 1;
while (luw)
%printf("pin %d pout %d puw %d luw %d\n", pin, pout, puw, luw);
pout += spacing/2;
mod_uw(pout) = qpsk_mod(uw(puw:puw+1));
puw += 2;
pout += 1;
luw -= 2;
end
endfunction
% Uses the UW to determine when we have a full codeword ready for decoding
function [found_uw corr] = look_for_uw(mem_rx_symbols, mod_uw)
sparse_mem_rx_symbols = mem_rx_symbols(find(mod_uw));
% correlate with ref UW
num = (mem_rx_symbols * mod_uw') .^ 2;
den = (sparse_mem_rx_symbols * sparse_mem_rx_symbols') * (mod_uw * mod_uw');
corr = abs(num/(den+1E-6));
found_uw = corr > 0.8;
endfunction