% Code for the Digital Communication 1 laboration
% 050210, 060227, 080207, 090216 Daniel Aronsson

clear
close all

channel='simulated';


%%%%%%%%%%%%%%%%%%%%%%%%%
% System variables
%%%%%%%%%%%%%%%%%%%%%%%%%

Nbits=3*4*4*11*19;          % Divisible by 3(for 8PSK),4(for BPSK,QPSK,16QAM) 
                            % another 4(for Hamming7_4),11(for Hamming15_11), Nbits=about 10000
coderate=;
Ncodedbits=round(Nbits/coderate);  % (round() removes machine rounding errors)
M=;                         % log2(M)=bits/symbol (e.g M=4 => QPSK)
Nfilter=8;                  % The length of the send/recv filter in symbols (even integer)
Nsuffix=100;                % Silence in the beginning to allow for the sound card to start up
Nprefix=100;                % Silence in the end to account for the delay in the system
Ntot=Ncodedbits/log2(M)+Nsuffix+Nprefix+32;  % Total number of symbols (32=length of training sequence)
fs=44100;                   % Sampling frequency (Hz)
R=fs/80;                    % Symbol rate (Hz). Make sure fs/R=integer.
T=Ntot/R;                   % Total time for the transmission (sec)
N=round(fs*T);              % Total number of samples (=fs/R * Ncodedbits/log2(M) i.e an integer)
                            % (round() removes machine rounding errors)
t=linspace(0,T-1/fs,N);     % Time axis
f=fftshift(linspace(-fs/2,fs/2-1/T,N)); % Frequency axis. Good for plotting the spectrum.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Create the baseband signal (complex).
% Create the baseband signal for the training sequence as it will
% look on the receiver side (after passing both send/recv filters).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

m=round(rand(Nbits,1));   % Meddelande

%%% Block 1 : Channel code
%c=some_encoder(m);  % INSERT FUNCTION CALL HERE

%%% Block 2 : Mapping onto symbols
%[I,Q]=some_modulator(c);   % INSERT FUNCTION CALL HERE

load trainingsequence  % Load the training sequency (random QPSK symbols)
            % It is needed to find the beginning of the signal on
            % the receiver side.
s=[zeros(Nprefix,1); trseq; I+sqrt(-1)*Q; zeros(Nsuffix,1)]; % Symbols to be transmitted

%%% Block 3 : Pulse shaping (square root raised cosine)
tx_pulsetrain=kron(s,[1; zeros(fs/R-1,1)]);  % Upsample by factor fs/R
pulse = srrc(fs,R,Nfilter,0.5);
tx_s_bb=fftfilt(pulse,tx_pulsetrain);

% The training signal (after passing both send and recv filters)
rx_trainingsequence=fftfilt(pulse,fftfilt(pulse,kron([trseq; zeros(2*Nfilter-1,1)],[1; zeros(fs/R-1,1)])));


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Create passband signal
% Send and receive passband signal.
% Send and receive "silence" (for measuring the noise).
% Mix down to baseband and filter.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

if strcmp(channel,'soundcard')
    
    % Play and record silence for noise measurement
    pause(1)
    wavplay(zeros(N,1),fs,'async');
    rx_n_pb  = wavrecord(N+100, fs,1);
    rx_n_pb=rx_n_pb(101:end);
    rx_n_pb=rx_n_pb-mean(rx_n_pb);
    
    %%% Block 4 : Carrier modulation
    wc=2000*2*pi;
    tx_s_pb=real(tx_s_bb).*cos(wc*t.')-imag(tx_s_bb).*sin(wc*t.');
    tx_s_pb=tx_s_pb/max(abs(tx_s_pb));
    
    %%% Block 5 : Channel (send and receive)
    pause(1)
    wavplay(tx_s_pb,fs,'async');
    rx_s_pb = wavrecord(N+100, fs,1);
    rx_s_pb = rx_s_pb(101:end);
    rx_s_pb = rx_s_pb-mean(rx_s_pb);
    
    %%% Block 6 : Mix down back to baseband
    rx_s_bb=2*rx_s_pb.*cos(wc*t.')-2*i*rx_s_pb.*sin(wc*t.');
    rx_n_bb=2*rx_n_pb.*cos(wc*t.')-2*i*rx_n_pb.*sin(wc*t.');
    
elseif strcmp(channel,'simulated')
    
    % Simulated noise
    Npow=0.03; % noise power. Experiment with this to produce different Eb/N0.
    n=randn(Ntot*fs/R,1)*sqrt(Npow);
    rx_n_pb=n;
    rx_n_pb=rx_n_pb-mean(rx_n_pb);
    
    %%% Block 4 : Carrier modulation    
    wc=2000*2*pi;
    tx_s_pb=real(tx_s_bb).*cos(wc*t.')-imag(tx_s_bb).*sin(wc*t.');
    tx_s_pb=tx_s_pb/max(abs(tx_s_pb));

    %%% Block 5 : Channel (add noise)    
    rx_s_pb = tx_s_pb + n;
    rx_s_pb = rx_s_pb-mean(rx_s_pb);

    %%% Block 6 : Mix down back to baseband    
    rx_s_bb=2*rx_s_pb.*cos(wc*t.')-2*i*rx_s_pb.*sin(wc*t.');
    rx_n_bb=2*rx_n_pb.*cos(wc*t.')-2*i*rx_n_pb.*sin(wc*t.');
    
else
    error('Unknown channel (check the channel variable!)');
end

%%% Block 7 : Filter (square root raised cosine)
rx_s_bb_filtered=fftfilt(pulse,rx_s_bb);
rx_n_bb_filtered=fftfilt(pulse,rx_n_bb);


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Use correlation to locate the beginning of the signal. Then sample.
% Measure Eb/N0 and BER.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

if ~isequal(round(xcorr_dc1([0 1 2 3],[1 2 3])) , [0 0 3 8 14 8 3])
    error(['Your xcorr.m is old. Update to Signal Processing Toolbox' ...
            ' 5 or more.']);
end

[corr,lags] = xcorr_dc1(rx_s_bb_filtered,rx_trainingsequence);
[cmax,nmax] = max(corr);
delay       = lags(nmax);
h           = cmax/sum(abs(rx_trainingsequence).^2);
k           = delay+(32+Nfilter)*fs/R+1;

try
    fprintf('Index : %d, scaling factor : %f+i*%f\n',k,real(h),imag(h));
    %%% Sampling (denoted by a switch in the block diagram)
    rx_s_bb_sampled=rx_s_bb_filtered(k:fs/R:k+fs/R*Ncodedbits/log2(M)-1)/h;
    rx_n_bb_sampled=rx_n_bb_filtered(k:fs/R:k+fs/R*Ncodedbits/log2(M)-1)/h; 
catch
    errmsg = lasterr;
    if(strfind(errmsg, 'Index exceeds matrix dimensions'))
        fprintf('Lost sync!\n');
    else
        error(errmsg);
    end
end

%%% Block 8 : Detect and channel decode. INSERT FUNCTION CALL HERE.
%estimated_c=some_detector(real(rx_s_bb_sampled),imag(rx_s_bb_sampled));
%estimated_m=some_decoder(estimated_c);

BER=sum(estimated_m ~= m) / length(m);
EbN0=10*log10(1/coderate/log2(M) * (var(rx_s_bb_sampled)/var(rx_n_bb_sampled)-1) );
fprintf('BER : %f\n',BER);
fprintf('EbN0 : %f\n',EbN0);
