From 132e232ea1e209c43a184d1b2a29d3ba272af18c Mon Sep 17 00:00:00 2001 From: drowe67 Date: Fri, 2 Mar 2012 07:09:18 +0000 Subject: [PATCH] added DQPSK mode, which works and can demod with small frequency offsets, modiied test bit pattern to resync better, now have working simulations with Pathsim git-svn-id: https://svn.code.sf.net/p/freetel/code@338 01035d8c-6547-0410-b346-abe4f91aad63 --- codec2-dev/octave/fdmdv.m | 69 +++++++++++++++++++++++++++------ codec2-dev/octave/fdmdv_demod.m | 30 +++++++++++--- codec2-dev/octave/fdmdv_mod.m | 7 +++- codec2-dev/octave/fdmdv_ut.m | 41 +++++++++++++++++--- 4 files changed, 122 insertions(+), 25 deletions(-) diff --git a/codec2-dev/octave/fdmdv.m b/codec2-dev/octave/fdmdv.m index 030b8ba4..ea06e3ff 100644 --- a/codec2-dev/octave/fdmdv.m +++ b/codec2-dev/octave/fdmdv.m @@ -63,7 +63,7 @@ global gt_alpha5_root = real((ifft_GF_alpha5_root(1:Nfilter))); % generate Nc QPSK symbols from vector of (1,Nc*Nb) input bits -function tx_symbols = bits_to_qpsk(tx_bits) +function tx_symbols = bits_to_qpsk(prev_tx_symbols, tx_bits, modulation) global Nc; global Nb; @@ -73,9 +73,29 @@ function tx_symbols = bits_to_qpsk(tx_bits) tx_bits_matrix(1:Nc,1) = tx_bits(1:Nb:Nb*Nc); tx_bits_matrix(1:Nc,2) = tx_bits(2:Nb:Nb*Nc); - % map to (Nc,1) QPSK symbols - - tx_symbols = -1 + 2*tx_bits_matrix(:,1) - j + 2j*tx_bits_matrix(:,2); + if (strcmp(modulation,'dqpsk')) + % map to (Nc,1) DQPSK symbols + + for c=1:Nc + msb = tx_bits_matrix(c,1); lsb = tx_bits_matrix(c,2); + + if ((msb == 0) && (lsb == 0)) + tx_symbols(c) = prev_tx_symbols(c); + endif + if ((msb == 0) && (lsb == 1)) + tx_symbols(c) = j*prev_tx_symbols(c); + endif + if ((msb == 1) && (lsb == 0)) + tx_symbols(c) = -prev_tx_symbols(c); + endif + if ((msb == 1) && (lsb == 1)) + tx_symbols(c) = -j*prev_tx_symbols(c); + endif + end + else + % QPSK mapping + tx_symbols = -1 + 2*tx_bits_matrix(:,1) - j + 2j*tx_bits_matrix(:,2); + endif endfunction @@ -261,7 +281,7 @@ endfunction % sure but it's worth 3dB so worth experimenting or using coherent as % an option. -function rx_phase = rx_est_phase(rx_symbols) +function rx_phase = rx_est_phase(prev_rx_symbols, rx_symbols) % modulation strip @@ -272,15 +292,42 @@ endfunction % convert symbols back to an array of bits -function rx_bits = qpsk_to_bits(rx_symbols) +function rx_bits = qpsk_to_bits(prev_rx_symbols, rx_symbols, modulation) global Nc; global Nb; + global Nb; - % map (Nc,1) QPSK symbols back into an (1,Nc*Nb) array of bits + if (strcmp(modulation,'dqpsk')) + % extra 45 degree clockwise lets us use real and imag axis as + % decision boundaries - rx_bits = zeros(1,Nc*Nb); - rx_bits(1:Nb:Nc*Nb) = real(rx_symbols) > 0; - rx_bits(2:Nb:Nc*Nb) = imag(rx_symbols) > 0; + phase_difference = rx_symbols .* conj(prev_rx_symbols) * exp(j*pi/4); + + % map (Nc,1) DQPSK symbols back into an (1,Nc*Nb) array of bits + + for c=1:Nc + d = phase_difference(c); + if ((real(d) >= 0) && (imag(d) >= 0)) + msb = 0; lsb = 0; + endif + if ((real(d) < 0) && (imag(d) >= 0)) + msb = 0; lsb = 1; + endif + if ((real(d) < 0) && (imag(d) < 0)) + msb = 1; lsb = 0; + endif + if ((real(d) >= 0) && (imag(d) < 0)) + msb = 1; lsb = 1; + endif + rx_bits(2*(c-1)+1) = msb; + rx_bits(2*(c-1)+2) = lsb; + end + else + % map (Nc,1) QPSK symbols back into an (1,Nc*Nb) array of bits + + rx_bits(1:Nb:Nc*Nb) = real(rx_symbols) > 0; + rx_bits(2:Nb:Nc*Nb) = imag(rx_symbols) > 0; + endif endfunction @@ -358,7 +405,7 @@ global rx_baseband_mem_timing = zeros(Nc, Nfiltertiming); % Test bit stream state variables -global Ntest_bits = 100; % length of test sequence +global Ntest_bits = Nc*Nb*4; % length of test sequence global current_test_bit = 1; global test_bits = rand(1,Ntest_bits) > 0.5; global rx_test_bits_mem = zeros(1,Ntest_bits); diff --git a/codec2-dev/octave/fdmdv_demod.m b/codec2-dev/octave/fdmdv_demod.m index f19d9941..9cc707e6 100644 --- a/codec2-dev/octave/fdmdv_demod.m +++ b/codec2-dev/octave/fdmdv_demod.m @@ -7,7 +7,7 @@ % Version 2 % -function fdmdv_demod(rawfilename) +function fdmdv_demod(rawfilename, nbits) fdmdv; % include modem code @@ -15,13 +15,20 @@ fin = fopen(rawfilename, "rb"); rx_fdm = fread(fin, Inf, "short"); gain = 1000; rx_fdm /= gain; -frames = floor(length(rx_fdm)/M); +if (nargin == 1) + frames = floor(length(rx_fdm)/M); +else + frames = nbits/(Nc*Nb); +endif total_bit_errors = 0; total_bits = 0; rx_timing_log = []; rx_symbols_log = []; +rx_phase_log = []; +prev_rx_symbols = ones(Nc,1)*exp(j*pi/4); +modulation = 'dqpsk'; % Main loop ---------------------------------------------------- @@ -32,8 +39,17 @@ for i=1:frames [rx_symbols rx_timing] = rx_est_timing(rx_filt, rx_baseband); rx_timing_log = [rx_timing_log rx_timing]; - rx_symbols_log = [rx_symbols_log rx_symbols]; - rx_bits = qpsk_to_bits(rx_symbols); + %rx_phase = rx_est_phase(rx_symbols); + %rx_phase_log = [rx_phase_log rx_phase]; + %rx_symbols = rx_symbols*exp(j*rx_phase); + + if strcmp(modulation,'dqpsk') + rx_symbols_log = [rx_symbols_log rx_symbols.*conj(prev_rx_symbols)*exp(j*pi/4)]; + else + rx_symbols_log = [rx_symbols_log rx_symbols]; + endif + rx_bits = qpsk_to_bits(prev_rx_symbols, rx_symbols, modulation); + prev_rx_symbols = rx_symbols; [sync bit_errors] = put_test_bits(rx_bits); @@ -55,10 +71,12 @@ clf; plot(real(rx_symbols_log(:,20:m)),imag(rx_symbols_log(:,20:m)),'+') figure(2) clf; -subplot(211) +subplot(311) plot(rx_timing_log) -subplot(212) +subplot(312) Nfft=Fs; S=fft(rx_fdm,Nfft); SdB=20*log10(abs(S)); plot(SdB(1:Fs/4)) +subplot(313) +%plot(rx_phase_log) diff --git a/codec2-dev/octave/fdmdv_mod.m b/codec2-dev/octave/fdmdv_mod.m index 7148619c..69a310c1 100644 --- a/codec2-dev/octave/fdmdv_mod.m +++ b/codec2-dev/octave/fdmdv_mod.m @@ -13,11 +13,13 @@ fdmdv; % include modem code frames = floor(nbits/(Nc*Nb)); tx_fdm = []; -gain = 1000; % Sccle up to 16 bit shorts +gain = 1000; % Scale up to 16 bit shorts +prev_tx_symbols = ones(Nc,1)*exp(j*pi/4); for i=1:frames tx_bits = get_test_bits(Nc*Nb); - tx_symbols = bits_to_qpsk(tx_bits); + tx_symbols = bits_to_qpsk(prev_tx_symbols, tx_bits,'dqpsk'); + prev_tx_symbols = tx_symbols; tx_baseband = tx_filter(tx_symbols); tx_fdm = [tx_fdm fdm_upconvert(tx_baseband)]; end @@ -25,3 +27,4 @@ end tx_fdm *= gain; fout = fopen(rawfilename,"wb"); fwrite(fout, tx_fdm, "short"); +fclose(fout); diff --git a/codec2-dev/octave/fdmdv_ut.m b/codec2-dev/octave/fdmdv_ut.m index 8071f49b..562da5c4 100644 --- a/codec2-dev/octave/fdmdv_ut.m +++ b/codec2-dev/octave/fdmdv_ut.m @@ -13,7 +13,15 @@ fdmdv; % load modem code rand('state',1); randn('state',1); +% Simulation Parameters -------------------------------------- + frames = 50; +EbNo_dB = 40; +Foff_hz = 1; +modulation = 'dqpsk'; + +% ------------------------------------------------------------ + tx_filt = zeros(Nc,M); rx_symbols_log = zeros(Nc,1); rx_phase_log = 0; @@ -23,6 +31,9 @@ noise_pwr = 0; total_bit_errors = 0; total_bits = 0; rx_fdm_log = []; +rx_bits_offset = zeros(Nc*Nb*2); +prev_tx_symbols = ones(Nc,1)*exp(j*pi/4); +prev_rx_symbols = ones(Nc,1)*exp(j*pi/4); % Eb/No calculations. We need to work out Eb/No for each FDM carrier. % Total power is sum of power in all FDM carriers @@ -31,8 +42,6 @@ C = 1; % power of each FDM carrier (energy/sample) N = 1; % total noise power (energy/sample) of noise source before scaling % by Ngain -EbNo_dB = 40; - % Eb = Carrier power * symbol time / (bits/symbol) % = C *(Rs/Fs) / 2 Eb_dB = 10*log10(C) + 10*log10(Rs) - 10*log10(Fs) - 10*log10(2); @@ -53,19 +62,30 @@ CNo_dB = 10*log10(C) + 10*log10(Nc) - No_dBHz; B = 2400; SNR = CNo_dB - 10*log10(B); +phase_offset = 1; +freq_offset = exp(j*2*pi*Foff_hz/Fs); % Main loop ---------------------------------------------------- for i=1:frames tx_bits = get_test_bits(Nc*Nb); - tx_symbols = bits_to_qpsk(tx_bits); + %tx_bits = zeros(1,Nc*Nb); + %tx_bits = ones(1,Nc*Nb); + %tx_bits = [0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1]; + %tx_bits = [1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0]; + tx_symbols = bits_to_qpsk(prev_tx_symbols, tx_bits, modulation); + prev_tx_symbols = tx_symbols; tx_baseband = tx_filter(tx_symbols); tx_fdm = fdm_upconvert(tx_baseband); tx_pwr = 0.9*tx_pwr + 0.1*tx_fdm*tx_fdm'/(M); noise = Ngain/sqrt(2)*[randn(1,M) + j*randn(1,M)]; noise_pwr = 0.9*noise_pwr + 0.1*noise*noise'/M; - rx_fdm = tx_fdm + noise; + for i=1:M + phase_offset *= freq_offset; + rx_fdm(i) = phase_offset*tx_fdm(i); + end + rx_fdm += noise; rx_fdm_log = [rx_fdm_log rx_fdm]; rx_baseband = fdm_downconvert(rx_fdm); @@ -78,8 +98,13 @@ for i=1:frames %rx_phase_log = [rx_phase_log rx_phase]; %rx_symbols = rx_symbols*exp(j*rx_phase); - rx_symbols_log = [rx_symbols_log rx_symbols]; - rx_bits = qpsk_to_bits(rx_symbols); + if strcmp(modulation,'dqpsk') + rx_symbols_log = [rx_symbols_log rx_symbols.*conj(prev_rx_symbols)*exp(j*pi/4)]; + else + rx_symbols_log = [rx_symbols_log rx_symbols]; + endif + rx_bits = qpsk_to_bits(prev_rx_symbols, rx_symbols, modulation); + prev_rx_symbols = rx_symbols; [sync bit_errors] = put_test_bits(rx_bits); if (sync == 1) @@ -123,6 +148,10 @@ plot(SdB(1:Fs/4)) % dump file type plotting & instrumentation % determine if error pattern is bursty % HF channel simulation +% +% phase estimator not working too well and would need a UW +% to resolve ambiguity. But this is probably worth it for +% 3dB. Test with small freq offset % Implementation loss BER issues: % QPSK mapping -- 2.25.1