working up simulation for various QPSK modulation schemems on HF channel
authordrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Sun, 9 Feb 2014 04:09:50 +0000 (04:09 +0000)
committerdrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Sun, 9 Feb 2014 04:09:50 +0000 (04:09 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@1396 01035d8c-6547-0410-b346-abe4f91aad63

codec2-dev/octave/test_qpsk.m [new file with mode: 0644]

diff --git a/codec2-dev/octave/test_qpsk.m b/codec2-dev/octave/test_qpsk.m
new file mode 100644 (file)
index 0000000..d6baf3a
--- /dev/null
@@ -0,0 +1,299 @@
+% test_qpsk.m\r
+% David Rowe Feb 2014\r
+%\r
+% Single sample per symbol QPSK modem simulation, based on code by Bill Cowley\r
+% Generates curves BER versus E/No curves for different modems.  Design to\r
+% test perform initial tests on coherent demodulation for HF channels without\r
+% building a full blown modem.  Lacks filtering, timing estimation, frame sync.\r
+% \r
+\r
+1;\r
+\r
+% main test function \r
+\r
+function sim_out = ber_test(sim_in, modulation)\r
+\r
+    framesize        = sim_in.framesize;\r
+    Ntrials          = sim_in.Ntrials;\r
+    Esvec            = sim_in.Esvec;\r
+    phase_offset     = sim_in.phase_offset;\r
+    phase_est        = sim_in.phase_est;\r
+    w_offset         = sim_in.w_offset;\r
+    plot_scatter     = sim_in.plot_scatter;\r
+    Rs               = sim_in.Rs;\r
+    hf_sim           = sim_in.hf_sim;\r
+    hf_spread_hz     = sim_in.hf_spread_hz;\r
+    hf_delay_samples = sim_in.hf_delay_samples;\r
+\r
+    bps              = 2;\r
+    Nsymb            = framesize/bps;\r
+    prev_sym_tx      = qpsk_mod([0 0]);\r
+    prev_sym_rx      = qpsk_mod([0 0]);\r
+    rx_symb_log      = [];\r
+\r
+    Np               = 5;\r
+    r_delay_line     = zeros(1,Np);\r
+    s_delay_line     = zeros(1,Np);\r
+    hf_delay_line    = zeros(1,Nsymb+hf_delay_samples);\r
+    spread_main_phi  = 0;\r
+    spread_delay_phi = 0;\r
+    spread_main_phi_log = [];\r
+\r
+    % convert "spreading" samples from 1kHz carrier at Fs to complex baseband at Rs\r
+\r
+    Fs = 8000; Fc = 1000;\r
+    fspread = fopen("../unittest/sine1k_2Hz_spread.raw","rb");\r
+    spread1k = fread(fspread, "int16")/10000;\r
+\r
+    % down convert to complex baseband\r
+    spreadbb = spread1k.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k))');\r
+\r
+    % remove -2000 Hz image\r
+    b = fir1(50, 5/Fs);\r
+    spreadlpf = filter(b,1,spreadbb);\r
+\r
+    % decimate to symbol rate\r
+    spread = spreadlpf(1:floor(Fs/Rs):length(spreadlpf));\r
+\r
+    sc = 1;\r
+\r
+    % design root nyquist (root raised cosine) filter and init tx and rx filter states\r
+\r
+    alpha = 0.5; T=1/Fs; Nsym=7; M=Fs/Rs;\r
+    if floor(Fs/Rs) != Fs/Rs\r
+        printf("oversampling ratio must be an integer\n");\r
+        exit;\r
+    end\r
+    hrn = gen_rn_coeffs(alpha, T, Rs, Nsym, M);\r
+    Nfilter = length(hrn);\r
+    tx_filter_memory = zeros(1, Nfilter);\r
+    tx_baseband_log = [];\r
+    rx_filter_memory = zeros(1, Nfilter);\r
+    rx_baseband_log = [];\r
+    s_delay_line_filt = zeros(1,Nsym);\r
+\r
+    for ne = 1:length(Esvec)\r
+        Es = Esvec(ne);\r
+        EsNo = 10^(Es/10);\r
+    \r
+        variance = Fs/(2*Rs*EsNo);\r
+        Terrs = 0;  Tbits = 0;  Ferrs = 0;\r
+\r
+        for nn = 1: Ntrials\r
+                  \r
+           tx_bits = round( rand( 1, framesize ) );\r
+\r
+           % modulate\r
+\r
+            s = zeros(1, Nsymb);\r
+            for i=1:Nsymb\r
+                tx_symb = qpsk_mod(tx_bits(2*(i-1)+1:2*i));\r
+                %printf("shift: %f prev_sym: %f  ", tx_symb, prev_sym_tx);\r
+                if strcmp(modulation,'dqpsk')\r
+                    tx_symb *= prev_sym_tx;\r
+                    %printf("tx_symb: %f\n", tx_symb);\r
+                    prev_sym_tx = tx_symb;\r
+                end \r
+                s(i) = tx_symb;\r
+            end\r
+\r
+            s_ch = s;\r
+\r
+            % root nyquist filter symbols\r
+\r
+            for k=1:Nsym\r
+\r
+               % tx filter symbols\r
+\r
+               tx_baseband = zeros(1,M);\r
+\r
+               % tx filter each symbol, generate M filtered output samples for each symbol.\r
+               % Efficient polyphase filter techniques used as tx_filter_memory is sparse\r
+\r
+               tx_filter_memory(Nfilter) = s_ch(k);\r
+\r
+               for i=1:M\r
+                   tx_baseband(i) = M*tx_filter_memory(M:M:Nfilter) * hrn(M-i+1:M:Nfilter)';\r
+               end\r
+               tx_filter_memory(1:Nfilter-M) = tx_filter_memory(M+1:Nfilter);\r
+               tx_filter_memory(Nfilter-M+1:Nfilter) = zeros(1,M);\r
+               tx_baseband_log = [tx_baseband_log tx_baseband];\r
+\r
+               noise = sqrt(variance)*( randn(1,M) + j*randn(1,M) );\r
+               rx_baseband = tx_baseband.*exp(j*phase_offset) + noise;\r
+               phase_offset += w_offset;\r
+\r
+               % rx filter symbol\r
+\r
+               rx_filter_memory(Nfilter-M+1:Nfilter) = rx_baseband;\r
+               rx_filt = rx_filter_memory * hrn';\r
+               rx_filter_memory(1:Nfilter-M) = rx_filter_memory(1+M:Nfilter);\r
+               rx_baseband_log = [rx_baseband_log rx_filt];\r
+\r
+               % delay in tx data to compensate for filtering\r
+\r
+               s_delay_line_filt(1:Nsym-1) = s_delay_line_filt(2:Nsym);\r
+               s_delay_line_filt(Nsym) = s(k);\r
+               tx_bits(2*(k-1)+1:2*k) = qpsk_demod(s_delay_line_filt(1));\r
+               s(k) = s_delay_line_filt(1);   % input to phase est later\r
+\r
+               s_ch(k) = rx_filt;\r
+            end\r
+\r
+            % Channel simulation\r
+\r
+            if hf_sim\r
+                s_ch = s_ch.*spread(sc:sc+Nsymb-1)';\r
+                sc += Nsymb;\r
+            end\r
+\r
+            % coherent demod phase estimation and correction\r
+            % need sliding window\r
+            % use known (pilot) symbols\r
+            % start with all symbols pilots, then gradually decimate, e.g. 1 in 5 pilots\r
+\r
+            if phase_est\r
+                for i=1:Nsymb\r
+\r
+                    % delay line for phase est window\r
+\r
+                    r_delay_line(1:Np-1) = r_delay_line(2:Np);\r
+                    r_delay_line(Np) = s_ch(i);\r
+\r
+                    % delay in tx data to compensate data for phase est window\r
+\r
+                    s_delay_line(1:Np-1) = s_delay_line(2:Np);\r
+                    s_delay_line(Np) = s(i);\r
+                    tx_bits(2*(i-1)+1:2*i) = qpsk_demod(s_delay_line(floor(Np/2)+1));\r
+\r
+                    % estimate phase from known symbols and correct\r
+\r
+                    corr = s_delay_line * r_delay_line';\r
+                    s_ch(i) = r_delay_line(floor(Np/2)+1).*exp(j*angle(corr));\r
+               end    \r
+                %printf("corr: %f angle: %f\n", corr, angle(corr));\r
+            end\r
+\r
+            % de-modulate\r
+\r
+            rx_bits = zeros(1, framesize);\r
+            for i=1:Nsymb\r
+                rx_symb = s_ch(i);\r
+                if strcmp(modulation,'dqpsk')\r
+                    tmp = rx_symb;\r
+                    rx_symb *= conj(prev_sym_rx/abs(prev_sym_rx));\r
+                    prev_sym_rx = tmp;\r
+                end\r
+                rx_bits((2*(i-1)+1):(2*i)) = qpsk_demod(rx_symb);\r
+                rx_symb_log = [rx_symb_log rx_symb];\r
+            end\r
+\r
+            % Measure BER\r
+\r
+            % discard bits from first 2*Nsym symbols as tx and rx filter memories not full\r
+\r
+            if nn == 1\r
+                tx_bits = tx_bits(2*bps*Nsym+1:length(tx_bits));\r
+                rx_bits = rx_bits(2*bps*Nsym+1:length(rx_bits));\r
+            end\r
+\r
+            error_positions = xor( rx_bits, tx_bits );\r
+            Nerrs = sum(error_positions);\r
+            Terrs += Nerrs;\r
+            nerr(nn) = Nerrs;\r
+       \r
+            if Nerrs>0,  Ferrs = Ferrs +1;  end\r
+            Terrs = Terrs + Nerrs;\r
+            Tbits = Tbits + framesize;\r
+\r
+        end\r
+    \r
+        TERvec(ne) = Terrs;\r
+        FERvec(ne) = Ferrs;\r
+        BERvec(ne) = Terrs/Tbits;\r
+    end\r
+    \r
+    Ebvec = Esvec - 10*log10(bps);\r
+    sim_out.BERvec = BERvec;\r
+    sim_out.Ebvec = Ebvec;\r
+    sim_out.FERvec = FERvec;\r
+    sim_out.TERvec  = TERvec;\r
+\r
+    if plot_scatter\r
+        figure(2);\r
+        scat = rx_symb_log(2*Nsym:length(rx_symb_log)) .* exp(j*pi/4);\r
+\r
+        plot(real(scat), imag(scat),'+');\r
+        figure(3);\r
+        clf\r
+        plot(real(spread(1:100)));\r
+        hold on\r
+        plot(imag(spread(1:100)),'r')\r
+        hold off;\r
+        figure(4)\r
+        subplot(211)\r
+        plot(imag(tx_baseband_log(1:30*M)));\r
+        subplot(212)\r
+        plot(imag(rx_symb_log(2*Nsym:length(rx_symb_log))));\r
+    end\r
+endfunction\r
+\r
+% Gray coded QPSK modulation function\r
+\r
+function symbol = qpsk_mod(two_bits)\r
+    two_bits_decimal = sum(two_bits .* [2 1]); \r
+    switch(two_bits_decimal)\r
+        case (0) symbol =  1;\r
+        case (1) symbol =  j;\r
+        case (2) symbol = -j;\r
+        case (3) symbol = -1;\r
+    endswitch\r
+endfunction\r
+\r
+% Gray coded QPSK demodulation function\r
+\r
+function two_bits = qpsk_demod(symbol)\r
+    bit0 = real(symbol*exp(j*pi/4)) < 0;\r
+    bit1 = imag(symbol*exp(j*pi/4)) < 0;\r
+    two_bits = [bit1 bit0];\r
+endfunction\r
+\r
+% Start simulation ---------------------------------------\r
+\r
+sim_in.Esvec            = 1:10; \r
+sim_in.Ntrials          = 10;\r
+sim_in.framesize        = 100;\r
+sim_in.phase_offset     = 0;\r
+sim_in.phase_est        = 0;\r
+sim_in.w_offset         = 0;\r
+sim_in.plot_scatter     = 0;\r
+sim_in.Rs               = 100;\r
+sim_in.hf_sim           = 0;\r
+sim_in.hf_spread_hz     = 2;\r
+sim_in.hf_delay_samples = 5;\r
+\r
+sim_qpsk                = ber_test(sim_in, 'qpsk');\r
+\r
+sim_in.phase_offset     = 0;\r
+sim_in.phase_est        = 0;\r
+sim_in.w_offset         = 0;  \r
+%sim_qpsk_coh            = ber_test(sim_in, 'qpsk');\r
+\r
+sim_in.phase_offset     = 0;\r
+sim_in.phase_est        = 1;\r
+sim_in.w_offset         = 0;  \r
+sim_in.plot_scatter     = 1;\r
+sim_in.Esvec            = 10;\r
+sim_in.hf_sim           = 0;\r
+sim_qpsk_scatter        = ber_test(sim_in, 'qpsk');\r
+\r
+figure(1); \r
+clf;\r
+semilogy(sim_qpsk.Ebvec, sim_qpsk.BERvec)\r
+hold on;\r
+%semilogy(sim_qpsk_coh.Ebvec, sim_qpsk_coh.BERvec,'r;coherent;')\r
+hold off;\r
+xlabel('Eb/N0')\r
+ylabel('BER')\r
+grid\r
+\r