clear all;
close all;
clc 
% Factor for manpulating consoliation data points
delta = 1;


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%          Random Binary Input Sequance, Bernoli
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
probability_of_zero = 0.5;                     % Probability of generting a zero bit
n=10000;                                       % Number of bits
input = zeros(1,n); 
input = input + 48;                            %48 is assci for 0
for i=1:n                                      % Generating bits
    if rand(1) > probability_of_zero % rand(1) return float number between 0 to 1
        input(i) = input(i) + 1;
    end
end 
input = char(input)   ;                         % Coverting to string
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% A test input
%input = '0000000100100011010001010110011110001111';
%input = '1101';


numOfSymbols = length(input)/4        ;                              % Four bits for each symbol
a_mapping = [ -3*delta , -1*delta , 1*delta , 3*delta];             % Represent inphase corrdinates   
b_mapping = [ -3*delta , -1*delta , 1*delta , 3*delta];             % Represent inphase corrdinates
I = [ '11' , '10' , '00' , '01'];                                   % Inphase mapping bits
Q = [ '11' , '10' , '00' , '01'];                                   % Quadreture mapping bits

inphase_vector = [];                                                % Holds inphase bits of each symbol
quad_vector = [];                                                   % Holds quadreutre bits of each symbol

% Separating inphase and quadreture bits of each symbol and store them in
% inpahse_vector and quad_vector matrices.
  for i=1:2:length(input)
      if mod(i,4) == 1 
          inphase_vector = [inphase_vector ,  input(i:i+1) ];
      else 
          quad_vector = [quad_vector ,  input(i:i+1)];
      end  
  end
  
  
% Find inphase value for the inphase bits of the symbol and storing them
% in the a matrix.
a = [];
for i=1:2:length(inphase_vector)
    index = 1;
    for j=1:2:length(I)
        if I(j:j+1) == inphase_vector(i:i+1)
            a = [a, a_mapping(index) ];
            break
        end
        index = index + 1;
    end
end
 
% Find quadreture value for the quadreture bits of the symbol and storing them
% in the b matrix. 
 b = [];
 for i=1:2:length(quad_vector)
    index = 1;
    for j=1:2:length(Q)
        if Q(j:j+1) == quad_vector(i:i+1)
            b = [b , b_mapping(index)];
            break
        end
        index = index + 1;
    end   
 end
 
 
% These lines to print the concetalation points, original data points
figure
plot(a,b,'O')
axis([-4,4,-4,4])
title('original data points');
grid
   
fc = 3;                                                             % Carrier frequnecy
Ts = 1;                                                             % Period of each symbol
d = 0.01;                                                           % Step size of time points
t = 0:d:Ts*(length(input)/4);                                       % Time  of symbols duration
modulated = zeros(1,length(t));                                     % Represents the modulated signal

% Get modulated signal from inphase and quadreture compntnts of each symbol
for i=1:length(a)
    sub_t = 1+(Ts/d)*(i-1):(Ts/d)*i;                                % Interval for each symbol signal period
    temp = (a(i).*cos(2*pi*fc*t(sub_t)) + b(i).*sin(2*pi*fc*t(sub_t)));
    modulated(sub_t) = temp;
    
end

% Plotting the modulated signal
figure
plot(t, modulated)
axis([0 10*Ts -5 5])
title('the modulated signal in time domain');

grid

% Adding noise to the modulated signal
modulated_With_Noise = awgn(modulated,10);

% Plotting the modulated signal with noise added
figure
plot(t, modulated_With_Noise)
axis([0 10*Ts -5 5])
title('the modulated signal with noise added');
grid

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                   Reciever
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

recovered_amplitudes = [];                                          % Recovered amplitude after demodulation
recovered_phase = [];                                               % Recovered phase after demodulation

% Getting the amplitude and phase of each symbol from modulated signal
for i=1:numOfSymbols
    sub_t = 1+(Ts/d)*(i-1):(Ts/d)*i;                                % Symbol data points period
    % Get the amplitude
    recovered_amplitudes = [recovered_amplitudes , (max(modulated_With_Noise(sub_t)))];
   
    % Get the phase. Reference signal is coise, finding delay between the
    % first beak of the symbol signal and the peak of the reference signal.
    temp_peak_index = find(modulated_With_Noise(sub_t)==max(modulated_With_Noise(sub_t))) + (Ts/d)*(i-1);
    peak_index = temp_peak_index(1);
    first_peak_time =1+  (Ts/d)*(i-1);
    recovered_phase=[recovered_phase, mod((peak_index - first_peak_time)* d * fc * 360,360)];
end

% Getting inphase and quadreture corrdinates from the recovered amplitudes
% and phase of each symbol.
recovered_inphase = recovered_amplitudes.*cos(recovered_phase*pi/180);
recovered_quad = recovered_amplitudes.*sin(recovered_phase*pi/180);


% These lines to print the recovered concetalation points
figure
plot(recovered_inphase,recovered_quad,'o')
grid
axis([-5,5,-5,5])
title('the recovered concetalation points')


% Converting the inphase and quadreture corrdinates of each symbol to their
% closest symbol representation in binary sequance.
recovered_bits = '';                                                % Holds recovered binary sequance
for i=1:numOfSymbols
    x1 = (recovered_inphase(i));                                    % Inphase component of symbol
    y1 = (recovered_quad(i));                                       % Quadreture component of symbol
    best_x_index=-20;                                               % Initial correct symbol inphase index
    best_y_index=-20;                                               % Initial correct symbol quadreture index
    best_distance = 999999999;                                      % Initial best distance
    % Comparing distance of the recovered symbol with standared ones and
    % mapping to closest
    for j=1:length(a_mapping)
        for k=1:length(b_mapping)
            distance = sqrt(power(x1-a_mapping(j),2) + power(y1-b_mapping(k),2));
            if best_distance > distance
                best_distance = distance;
                best_x_index =j;
                best_y_index = k;
            end
            
        end
    
    end
    % Adding symbol binary sequance to output binary sequance of data
    recovered_bits=[recovered_bits,I(2*best_x_index-1:2*best_x_index)];
    recovered_bits=[recovered_bits,Q(2*best_y_index-1:2*best_y_index)];
end



%calculating error between transmitted data and received data
errorCount = 0;
for i=1:length(input)
    if input(i) ~= recovered_bits(i)
        errorCount = errorCount + 1;
    end

end


%printing results
input
recovered_bits
error_rate = errorCount/length(input)*100
