% 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;
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
% 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
% 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
% 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);
% Version 2
%
-function fdmdv_demod(rawfilename)
+function fdmdv_demod(rawfilename, nbits)
fdmdv; % include modem code
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 ----------------------------------------------------
[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);
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)
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
tx_fdm *= gain;
fout = fopen(rawfilename,"wb");
fwrite(fout, tx_fdm, "short");
+fclose(fout);
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;
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
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);
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);
%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)
% 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