building up rate Fs dqpsk simulation with variable power
authordrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Sat, 5 Apr 2014 01:49:09 +0000 (01:49 +0000)
committerdrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Sat, 5 Apr 2014 01:49:09 +0000 (01:49 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@1488 01035d8c-6547-0410-b346-abe4f91aad63

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

diff --git a/codec2-dev/octave/test_dqpsk2.m b/codec2-dev/octave/test_dqpsk2.m
new file mode 100644 (file)
index 0000000..a1806b6
--- /dev/null
@@ -0,0 +1,405 @@
+% test_dqpsk2.m\r
+% David Rowe April 2014\r
+%\r
+% DQPSK modem simulation inclduing filtering to test modulating modem\r
+% tx power based on speech energy.  Unlike test_dpsk runs at sample\r
+% rate Fs.\r
+\r
+1;\r
+\r
+% main test function \r
+\r
+function sim_out = ber_test(sim_in)\r
+    Fs = 8000;\r
+\r
+    verbose          = sim_in.verbose;\r
+    framesize        = sim_in.framesize;\r
+    Ntrials          = sim_in.Ntrials;\r
+    Esvec            = sim_in.Esvec;\r
+    phase_offset     = sim_in.phase_offset;\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
+    Nc               = sim_in.Nc;\r
+    symbol_amp       = sim_in.symbol_amp;\r
+\r
+    bps              = 2;\r
+    Nsymb            = framesize/bps;\r
+    for k=1:Nc\r
+      prev_sym_tx(k) = qpsk_mod([0 0]);\r
+      prev_sym_rx(k) = qpsk_mod([0 0]);\r
+    end\r
+\r
+    % design root nyquist (root raised cosine) filter and init tx and rx filter states\r
+\r
+    alpha = 0.5; T=1/Fs; Nfiltsym=7; M=Fs/Rs;\r
+    if floor(Fs/Rs) != Fs/Rs\r
+        printf("oversampling ratio must be an integer\n");\r
+        return;\r
+    end\r
+    hrn = gen_rn_coeffs(alpha, T, Rs, Nfiltsym, M);\r
+    Nfilter = length(hrn);\r
+\r
+    % Start Simulation ----------------------------------------------------------------\r
+\r
+    for ne = 1:length(Esvec)\r
+        EsNodB = Esvec(ne);\r
+        EsNo = 10^(EsNodB/10);\r
+    \r
+        variance = 1/EsNo;\r
+         if verbose > 1\r
+            printf("EsNo (dB): %f EsNo: %f variance: %f\n", EsNodB, EsNo, variance);\r
+        end\r
+        \r
+        Terrs = 0;  Tbits = 0;\r
+\r
+        tx_symb_log             = [];\r
+        rx_symb_log             = [];\r
+        noise_log               = [];\r
+        sim_out.errors_log      = [];\r
+        sim_out.tx_baseband_log = [];\r
+        sim_out.rx_filt_log     = [];\r
+\r
+        % init HF channel\r
+\r
+        hf_n = 1;\r
+        hf_angle_log = [];\r
+        hf_fading = ones(1,Nsymb);             % default input for ldpc dec\r
+        hf_model = ones(Ntrials*Nsymb/Nc, Nc); % defaults for plotting surface\r
+        symbol_amp_index  = 1;\r
+\r
+        % bunch of outputs we log for graphing\r
+\r
+        sim_out.errors_log = [];\r
+        sim_out.Nerrs = [];\r
+        sim_out.snr_log = [];\r
+        sim_out.hf_model_pwr = [];\r
+        sim_out.tx_fdm_log = [];\r
+\r
+        % init filter memories and LOs\r
+\r
+        tx_filter_memory  = zeros(Nc, Nfilter);\r
+        rx_filter_memory  = zeros(Nc, Nfilter);\r
+        s_delay_line_filt = zeros(Nc, Nfiltsym);\r
+        phase_tx = ones(1,Nc);\r
+        phase_rx = ones(1,Nc);\r
+        Fcentre = 1500; Fsep = (1+alpha)*Rs;\r
+        freq = (2*pi/Fs)*(Fcentre/2 + Fsep*(1:Nc));\r
+        freq = exp(j*freq);\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:Nc:Nsymb\r
+              for k=1:Nc\r
+                tx_symb = qpsk_mod(tx_bits(2*(i-1+k-1)+1:2*(i+k-1)));\r
+                s_qpsk(i+k-1) = tx_symb;\r
+                tx_symb *= prev_sym_tx(k);\r
+                prev_sym_tx(k) = tx_symb;\r
+                s(i+k-1) = symbol_amp(symbol_amp_index)*tx_symb;\r
+              end\r
+            end\r
+            symbol_amp_index++;\r
+            s_ch = s;\r
+\r
+            for i=1:Nc:Nsymb\r
+\r
+                % Delay tx symbols to match delay due to filters qpsk\r
+                % (rather than dqpsk) symbols used for convenience as\r
+                % it's easy to shift symbols than pair of bits\r
+\r
+                s_delay_line_filt(:,1:Nfiltsym-1) = s_delay_line_filt(:,2:Nfiltsym);\r
+                s_delay_line_filt(:,Nfiltsym) = s_qpsk(i:i+Nc-1);\r
+                s_qpsk(i:i+Nc-1) = s_delay_line_filt(:,1);  \r
+                for k=1:Nc\r
+                    tx_bits(2*(i-1+k-1)+1:2*(i+k-1)) = qpsk_demod(s_qpsk(i+k-1));\r
+                end\r
+\r
+                % tx filter\r
+\r
+                tx_baseband = zeros(Nc,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(i:i+Nc-1);\r
+\r
+                for k=1:M\r
+                    tx_baseband(:,k) = M*tx_filter_memory(:,M:M:Nfilter) * hrn(M-k+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(Nc,M);\r
+\r
+                sim_out.tx_baseband_log = [sim_out.tx_baseband_log  tx_baseband];\r
+\r
+                % upcovert\r
\r
+                tx_fdm = zeros(1,M);\r
+\r
+                for c=1:Nc\r
+                    for k=1:M\r
+                        phase_tx(c) = phase_tx(c) * freq(c);\r
+                       tx_fdm(k) = tx_fdm(k) + tx_baseband(c,k)*phase_tx(c);\r
+                    end\r
+                end\r
\r
+                sim_out.tx_fdm_log = [sim_out.tx_fdm_log tx_fdm];\r
\r
+                % HF channel\r
+                \r
+                rx_fdm = tx_fdm;\r
+\r
+                % downconvert\r
+\r
+                rx_baseband = zeros(Nc,M);\r
+                for c=1:Nc\r
+                    for k=1:M\r
+                        phase_rx(c) = phase_rx(c) * freq(c);\r
+                       rx_baseband(c,k) = rx_fdm(k)*phase_rx(c)';\r
+                    end\r
+                end\r
+\r
+                % rx filter\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
+                sim_out.rx_filt_log = [sim_out.rx_filt_log rx_filt];\r
+\r
+                s_ch(i:i+Nc-1) = rx_filt;\r
+            end\r
+\r
+            % HF channel simulation  ------------------------------------\r
+            \r
+            if hf_sim\r
+            end\r
+\r
+            % "genie" SNR estimate \r
+            \r
+            snr = (s_ch*s_ch')/(Nsymb*variance);\r
+            sim_out.snr_log = [sim_out.snr_log snr];\r
+            sim_out.hf_model_pwr = [sim_out.hf_model_pwr mean(hf_fading.^2)];\r
+\r
+            % AWGN noise and phase/freq offset channel simulation\r
+            % 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im\r
+\r
+            noise = sqrt(variance*0.5)*(randn(1,Nsymb) + j*randn(1,Nsymb));\r
+            noise_log = [noise_log noise];\r
\r
+            % organise into carriers to apply frequency and phase offset\r
+\r
+            for i=1:Nc:Nsymb\r
+              for k=1:Nc\r
+                 s_ch(i+k-1) = s_ch(i+k-1)*exp(j*phase_offset) + noise(i+k-1);\r
+              end \r
+              phase_offset += w_offset;\r
+            end\r
+               \r
+            % de-modulate\r
+\r
+            rx_bits = zeros(1, framesize);\r
+            for i=1:Nc:Nsymb\r
+              for k=1:Nc\r
+                rx_symb = s_ch(i+k-1);\r
+                tmp = rx_symb;\r
+                rx_symb *= conj(prev_sym_rx(k)/abs(prev_sym_rx(k)));\r
+                prev_sym_rx(k) = tmp;\r
+                rx_bits((2*(i-1+k-1)+1):(2*(i+k-1))) = qpsk_demod(rx_symb);\r
+                rx_symb_log = [rx_symb_log rx_symb];\r
+              end\r
+            end\r
+\r
+            % ignore data until we have enough frames to fill filter memory\r
+            % then count errors\r
+\r
+            if nn > ceil(Nfiltsym/(Nsymb/Nc))\r
+                error_positions = xor(rx_bits, tx_bits);\r
+                sim_out.errors_log = [sim_out.errors_log error_positions];\r
+                Nerrs = sum(error_positions);\r
+                sim_out.Nerrs = [sim_out.Nerrs Nerrs];\r
+                Terrs += Nerrs;\r
+                Tbits += length(tx_bits);\r
+            end\r
+\r
+        end\r
+\r
+        TERvec(ne) = Terrs;\r
+        BERvec(ne) = Terrs/Tbits;\r
+\r
+        if verbose \r
+            printf("EsNo (dB): %f  Terrs: %d BER %f BER theory %f", EsNodB, Terrs,\r
+                   Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)));\r
+            printf("\n");\r
+        end\r
+        if verbose > 1\r
+            printf("Terrs: %d BER %f BER theory %f C %f N %f Es %f No %f Es/No %f\n\n", Terrs,\r
+                   Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)), var(tx_symb_log), var(noise_log),\r
+                   var(tx_symb_log), var(noise_log), var(tx_symb_log)/var(noise_log));\r
+        end\r
+    end\r
+    \r
+    Ebvec = Esvec - 10*log10(bps);\r
+\r
+    sim_out.BERvec = BERvec;\r
+    sim_out.Ebvec  = Ebvec;\r
+    sim_out.TERvec = TERvec;\r
+\r
+    if plot_scatter\r
+        figure(2);\r
+        clf;\r
+        scat = rx_symb_log(Nfiltsym*Nc:length(rx_symb_log)) .* exp(j*pi/4);\r
+        plot(real(scat), imag(scat),'+');\r
+        title('Scatter plot');\r
+\r
+        figure(3);\r
+        clf;        \r
+        y = 1:Rs*2;\r
+        x = 1:Nc;\r
+        EsNodBSurface = 20*log10(abs(hf_model(y,:))) - 10*log10(variance);\r
+        mesh(x,y,EsNodBSurface);\r
+        grid\r
+        title('HF Channel Es/No');\r
+    end\r
+\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
+    if isscalar(symbol) == 0\r
+        printf("only works with scalars\n");\r
+        return;\r
+    end\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
+function sim_in = standard_init\r
+  sim_in.verbose          = 1;\r
+  sim_in.plot_scatter     = 0;\r
+\r
+  sim_in.Esvec            = 5:15; \r
+  sim_in.Ntrials          = 100;\r
+  sim_in.framesize        = 64;\r
+  sim_in.Rs               = 100;\r
+  sim_in.Nc               = 8;\r
+\r
+  sim_in.phase_offset     = 0;\r
+  sim_in.w_offset         = 0;\r
+  sim_in.phase_noise_amp  = 0;\r
+\r
+  sim_in.hf_delay_ms      = 2;\r
+  sim_in.hf_sim           = 0;\r
+  sim_in.hf_phase_only    = 0;\r
+  sim_in.hf_mag_only      = 0;\r
+endfunction\r
+\r
+function awgn_hf_ber_curves()\r
+  sim_in = standard_init();\r
+\r
+  Ebvec = sim_in.Esvec - 10*log10(2);\r
+  BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10)));\r
+\r
+  dpsk_awgn = ber_test(sim_in);\r
+  sim_in.hf_sim           = 1;\r
+  dpsk_hf   = ber_test(sim_in);\r
+\r
+  figure(1); \r
+  clf;\r
+  semilogy(Ebvec, BER_theory,'r;QPSK theory;')\r
+  hold on;\r
+  semilogy(dpsk_awgn.Ebvec, dpsk_awgn.BERvec,'g;DQPSK;')\r
+  semilogy(dpsk_hf.Ebvec, dpsk_hf.BERvec,'g;DQPSK HF;')\r
+  hold off;\r
+  xlabel('Eb/N0')\r
+  ylabel('BER')\r
+  grid("minor")\r
+  axis([min(Ebvec) max(Ebvec) 1E-3 1])\r
+end\r
+\r
+sim_in = standard_init();\r
+\r
+% energy file sampled every 10ms\r
+\r
+load ../src/ve9qrp.txt\r
+pdB=10*log10(ve9qrp);\r
+for i=1:length(pdB)\r
+  if pdB(i) < 0\r
+    pdB(i) = 0;\r
+  end\r
+end\r
+\r
+% Down sample to 40ms rate used for 1300 bit/s codec, every 4th sample is transmitted\r
+\r
+pdB = pdB(4:4:length(pdB));\r
+\r
+% Use linear mapping function in dB domain to map to symbol power\r
+\r
+power_map_x  = [ 0 20 24 40 50 ];\r
+power_map_y  = [-6 -6  0 6  6];\r
+mapped_pdB = interp1(power_map_x, power_map_y, pdB);\r
+\r
+%sim_in.symbol_amp = 10 .^ (mapped_pdB/20);\r
+sim_in.symbol_amp = ones(1,length(pdB));\r
+sim_in.plot_scatter = 1;\r
+sim_in.verbose      = 2;\r
+sim_in.hf_sim       = 1;\r
+sim_in.Esvec        = 100;\r
+sim_in.Ntrials      = 100;\r
+\r
+dqpsk_pwr_hf = ber_test(sim_in);\r
+\r
+% note: need way to test that power is aligned with speech\r
+\r
+figure(4)\r
+clf;\r
+plot((1:sim_in.Ntrials)*80*4, pdB(1:sim_in.Ntrials));\r
+hold on;\r
+plot((1:sim_in.Ntrials)*80*4, mapped_pdB(1:sim_in.Ntrials),'r');\r
+hold off;\r
+\r
+figure(5)\r
+clf;\r
+\r
+s = load_raw("../raw/ve9qrp.raw");\r
+M=320; M_on_2 = M/2; % processing delay between input speech and centre of analysis window\r
+plot(M_on_2:(M_on_2-1+sim_in.Ntrials*M),s(1:sim_in.Ntrials*M))\r
+hold on;\r
+plot((1:sim_in.Ntrials)*M, 5000*sim_in.symbol_amp(1:sim_in.Ntrials),'r');\r
+hold off;\r
+axis([1 sim_in.Ntrials*M -3E4 3E4]);\r
+\r
+figure(6)\r
+clf;\r
+plot((1:sim_in.Ntrials)*M, 20*log10(sim_in.symbol_amp(1:sim_in.Ntrials)),'b;Es (dB);');\r
+hold on;\r
+plot((1:sim_in.Ntrials)*M, 10*log10(dqpsk_pwr_hf.hf_model_pwr),'g;Fading (dB);');\r
+plot((1:sim_in.Ntrials)*M, 10*log10(dqpsk_pwr_hf.snr_log),'r;Es/No (dB);');\r
+\r
+ber = dqpsk_pwr_hf.Nerrs/sim_in.framesize;\r
+ber_clip = ber;\r
+ber_clip(find(ber > 0.2)) = 0.2;\r
+plot((1:length(ber_clip))*M, -20+100*ber_clip,'k;BER (0-20%);');\r
+hold off;\r
+axis([1 sim_in.Ntrials*M -20 20])\r
+\r
+fep=fopen("dqpsk_errors_pwr.bin","wb"); fwrite(fep, dqpsk_pwr_hf.errors_log, "short"); fclose(fep);\r
+fber=fopen("ber.bin","wb"); fwrite(fber, ber, "float"); fclose(fber);\r