% WEBDEMO demo_constellation.m-file, Institute of Telecommunications, University of Stuttgart, Germany
% www.inue.uni-stuttgart.de
% author: Klaus Oestreich, oestreich@inue.uni-stuttgart.de
% date: 13.12.2013
%
% Written for GNU Octave (works for MATLAB as well)
%
% EXAMPLE:  demo_ber( .... 'demo_constellation')
% PARAMETERS:
%  nb,              % number of bits per symbol
%  labeling,        % 1: Gray, 2: anti-Gray, 3: natural labeling
%  mapPamQam,       % 1: QAM, 2: PAM, 3: PSK
%  keepPlot,        % if 1, then the results of the previous plot are shown in the following plot as well.
%  svg_en,          % if 1, then also output svg-file
%  webdemo_en,      % if 0, then test-mode in Octave/Matlab commandline, no need for webserver running
%  filename         % output file for webdemo


% BEGIN, main function (control)

function demo_constellation( ...
    nb, ...
    labeling, ...
    mapPamQam, ...
    keepPlot, ...
    svg_en, ...
    webdemo_en, ...
    filename )

% default parameters 
switch nargin
    case 0
        nb = 4;
        labeling = 1;
        mapPamQam = 1;
        keepPlot = 0;
        svg_en = 0;
        webdemo_en = 0;
        filename = 'demo_ber';
    otherwise
end
        
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% BEGIN, set up graphical output
    
% Create an invisible figure.

if (webdemo_en)
    fig = figure(1); set(fig, 'visible', 'off');
else
    fig = figure(1); set(fig, 'visible', 'on');
end

landscape = '-S930,350';
portrait  = '-S640,480';
output_format = portrait; %portrait;landscape; 

set(0, 'defaultlinelinewidth', 2);

if (webdemo_en)
    set(0, 'defaultaxesfontsize', 8);
    set(0, 'defaultaxesfontname', 'Helvetica');
    set(0, 'defaulttextfontsize', 8);
    set(0, 'defaulttextfontname', 'Helvetica');
    const_lw = 2;
elseif (svg_en)
    set(0, 'defaultaxesfontsize', 6);
    set(0, 'defaultaxesfontname', 'Helvetica');
    set(0, 'defaulttextfontsize', 6);
    set(0, 'defaulttextfontname', 'Helvetica');
    const_lw = 1;
else
    set(0, 'defaultaxesfontsize', 10);
    set(0, 'defaultaxesfontname', 'Helvetica');
    set(0, 'defaulttextfontsize', 8);
    set(0, 'defaulttextfontname', 'Helvetica');
    const_lw = 2;
end

% RGB color definitions, http://www.rapidtables.com/web/color/RGB_Color.htm
gray 	   = [[0,0,0]; [32,32,32]; [64,64,64]; [96,96,96]; [128,128,128]; [160,160,160]; [192,192,192]; [224,224,224]; [255,255,255]]/255;
violett    = [[51,0,25]; [102,0,51]; [153,0,76]; [204,0,102]; [255,0,127]; [255,51,153]; [255,102,178]; [255,153,204]; [255,204,229]]/255;
magenta    = [[51,0,51]; [102,0,102]; [153,0,153]; [204,0,204]; [255,0,255]; [255,51,255]; [255,102,255]; [255,153,255]; [255,204,255]]/255;
lilac      = [[25,0,51]; [51,0,102]; [76,0,153]; [102,0,204]; [127,0,255]; [153,51,255]; [178,102,255]; [204,153,255]; [229,204,255]]/255;
blue       = [[0,0,51]; [0,0,102]; [0,0,153]; [0,0,204]; [0,0,255]; [51,51,255]; [102,102,255]; [153,153,255]; [204,204,255]]/255;
seablue    = [[0,25,51]; [0,51,102]; [0,76,153]; [0,102,204]; [0,128,255]; [51,153,255]; [102,178,255]; [153,204,255]; [204,229,255]]/255;
cyan       = [[0,51,51]; [0,102,102]; [0,153,153]; [0,204,204]; [0,255,255]; [51,255,255]; [102,255,255]; [153,255,255]; [204,255,255]]/255;
seagreen   = [[0,51,25]; [0,102,51]; [0,153,76]; [0,204,102]; [0,255,128]; [51,255,153]; [102,255,178]; [153,255,204]; [204,255,229]]/255;
green      = [[0,51,0]; [0,102,0]; [0,153,0]; [0,204,0]; [0,255,0]; [51,255,51]; [102,255,102]; [153,255,153]; [204,255,204]]/255;
lightgreen = [[25,51,0]; [51,102,0]; [76,153,0]; [102,204,0]; [128,255,0]; [153,255,51]; [178,255,102]; [204,255,153]; [229,255,204]]/255;
yellow     = [[51,51,0]; [102,102,0]; [153,153,0]; [204,204,0]; [255,255,0]; [255,255,51]; [255,255,102]; [255,255,153]; [255,255,204]]/255;
amber      = [[51,25,0]; [102,51,0]; [153,76,0]; [204,102,0]; [255,128,0]; [255,153,51]; [255,178,102]; [255,204,153]; [255,229,204]]/255;
red        = [[51,0,0]; [102,0,0]; [153,0,0]; [204,0,0]; [255,0,0]; [255,51,51]; [255,102,102]; [255,153,153]; [255,204,204]]/255;


% END, set up graphical output
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% BEGIN check input parameters for consistency


% END check input parameters for consistency
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

sizeFontLabeling = 10;
posCorrection = -0.15;
colorSigPoints = blue(6,:);

plotConstellation(nb,labeling,mapPamQam,sizeFontLabeling,posCorrection,colorSigPoints)

    
% Create an image file. This image is displayed on the webpage.
if (webdemo_en)
    print(filename, '-dpng',output_format);
end
if (svg_en)
    print(['fig_',filename], '-dsvg',output_format);
end    
    
end

% END, main program (control)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% select Mapping and labeling
function [m l] = get_mapping_and_labeling(nb,labeling,mapPamQam)

if( nb == 1 )
    m = [0, 1]; % Gray, anti-Gray, natural, random 
    l = [-1, 1];
elseif( nb == 2 ) 

   mArray= [ get_labeling(nb,1,1); % Gray, QAM
             get_labeling(nb,0,1); % anti-Gray
                     0:3;  % natural
                     randperm(2^nb)-ones(1,2^nb); % random
                     get_labeling(nb,1,0); % Gray, PAM
                     get_labeling(nb,0,0); % anti-Gray
                     0:3;  % natural
                     randperm(2^nb)-ones(1,2^nb); % random
                     get_labeling(nb,1,0); % Gray, PSK
                     get_labeling(nb,0,0); % anti-Gray
                     0:3;  % natural
                     randperm(2^nb)-ones(1,2^nb)]; % random
                     
    lArray =  [ (1/sqrt(2))*[-1-1i, 1-1i, 1+1i, -1+1i ]; ... % QAM
                    (1/sqrt(5))*[-3+0i, -1+0i, 1+0i, 3+0]; ...  % PAM
                    (1/sqrt(2))*[-1-1i, 1-1i, 1+1i, -1+1i]]; % PSK
                    
    m = mArray(labeling+(mapPamQam-1)*4,1:end);
    l = lArray(mapPamQam,1:end);
    
elseif( nb == 3 )

    mArray = [ 0, 2, 6, 4, 1, 3, 7, 5; ...
                      0, 6, 4, 2, 1, 7, 5, 3; ...
                      0, 2, 4, 6, 1, 3, 5, 7;
                      randperm(2^nb)-ones(1,2^nb);
                      0, 1, 3, 2, 6, 7, 5, 4;
                      0, 7, 1, 6, 3, 4, 2, 5;
                      0, 1, 2, 3, 4, 5, 6, 7;
                      randperm(2^nb)-ones(1,2^nb);
                      0, 1, 3, 2, 6, 7, 5, 4;
                      0, 7, 1, 6, 3, 4, 2, 5;
                      0, 1, 2, 3, 4, 5, 6, 7;
                      randperm(2^nb)-ones(1,2^nb)];
                      
       lArray = [ (0.4597)*[-1-1i,1-1i,1+1i,-1+1i, -(1+sqrt(3))*1i,1+sqrt(3),(1+sqrt(3))*1i,-1-sqrt(3)];
                      (1/sqrt(21))*[-7, -5, -3, -1, 1, 3, 5, 7];
                      (1/sqrt(2))*(-1-1i), -1i, (1/sqrt(2))*(1-1i), 1, (1/sqrt(2))*(1+1i), 1i,(1/sqrt(2))*( -1+1i), -1 ];
                      
    m = mArray(labeling+(mapPamQam-1)*4,1:end);
    l = lArray(mapPamQam,1:end);
    
elseif( nb == 4 )
        mArray = [ get_labeling(nb,1,1); 
                          get_labeling(nb,0,1); 
                          0:15;
                          randperm(2^nb)-ones(1,2^nb);
                          get_labeling(nb,1,0); %0, 1, 3, 2, 6, 7, 5, 4, 12, 13, 15, 14, 10, 11, 9, 8; 
                          get_labeling(nb,0,0); 
                          0:15;
                          randperm(2^nb)-ones(1,2^nb);
                          get_labeling(nb,1,0); 
                          get_labeling(nb,0,0); 
                          0:15;
                          randperm(2^nb)-ones(1,2^nb)];
                          
       lArray =  [ (1/sqrt(10))*[-3-3i,-1-3i,1-3i,3-3i, -3-1i,-1-1i,1-1i,3-1i, -3+1i,-1+1i,1+1i,3+1i, -3+3i,-1+3i,1+3i,3+3i]; 
                     (1/sqrt(85))*[-15, -13, -11, -9, -7, -5, -3, -1, 1, 3, 5, 7, 9, 11, 13, 15];
                     exp(10i*pi/8), exp(11i*pi/8), -1i, exp(13i*pi/8), exp(14i*pi/8), exp(15i*pi/8), 1, exp(1i*pi/8), exp(2i*pi/8), exp(3i*pi/8), 1i, exp(5i*pi/8), exp(6i*pi/8), exp(7i*pi/8), -1, exp(9i*pi/8)];
                     
    m = mArray(labeling+(mapPamQam-1)*4,1:end);
    l = lArray(mapPamQam,1:end);
    
elseif( nb == 6 )

        mArray = [ get_labeling(nb,1,1);
                   get_labeling(nb,0,1); 
                   0:63;
                   randperm(2^nb)-ones(1,2^nb);
		               get_labeling(nb,1,0);
                   get_labeling(nb,0,0);
                   0:63;
                   randperm(2^nb)-ones(1,2^nb); 
		               get_labeling(nb,1,0);
                   get_labeling(nb,0,0);
                   0:63;
                   randperm(2^nb)-ones(1,2^nb)];
                          
       lArray =  [ (1/sqrt(42))*[ reshape(ones(8)*(-9-9i)+cumsum(ones(8)*2i,2)+cumsum(ones(8)*2),1,[]) ]; 
                   (1/sqrt(1365))*[-63:2:63];
                   cumprod(ones(1,64)*exp(i*pi/32)) ];
               
    m = mArray(labeling+(mapPamQam-1)*4,1:end);
    l = lArray(mapPamQam,1:end); 
 
 else % nb == 8
 
        mArray = [ get_labeling(nb,1,1);
                   get_labeling(nb,0,1);
                   0:255;
                   randperm(2^nb)-ones(1,2^nb);
                   get_labeling(nb,1,0);
                   get_labeling(nb,0,0);
                   0:255;
                   randperm(2^nb)-ones(1,2^nb);
                   get_labeling(nb,1,0);
                   get_labeling(nb,0,0);
                   0:255;
                   randperm(2^nb)-ones(1,2^nb)];
                          
       lArray =  [ (1/sqrt(170))*[ reshape(ones(16)*(-17-17i)+cumsum(ones(16)*2i,2)+cumsum(ones(16)*2),1,[]) ]; 
                   (1/sqrt(21845))*[-255:2:255];
                   cumprod(ones(1,256)*exp(i*pi/128)) ];
                          
    m = mArray(labeling+(mapPamQam-1)*4,1:end);
    l = lArray(mapPamQam,1:end);
end

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% get labeling
function labelArray = get_labeling(nb,grey,qam)

nb_codes = 2^nb;
Gray_tab = zeros(nb_codes,nb);
Gray_tab(1,:)=-1;

if (grey == 1)
for i = 0:nb-1
for j = 0:(2^i)-1
for s = 0:nb-1
Gray_tab(2^(i+1)-1-j+1,s+1) = Gray_tab(j+1,s+1);
end
Gray_tab(2^(i+1)-1-j+1,i+1) = 1;
end
end

else
% anti-grey
for i = 0:nb-2
for j = 0:(2^i)-1
for s = 0:nb-2
Gray_tab(2^(i+1)-1-j+1,s+1) = Gray_tab(j+1,s+1);
end
Gray_tab(2^(i+1)-1-j+1,nb) = -1;
Gray_tab(2^(i+1)-1-j+1,i+1) = 1;
end
end

% second: rearrange and insert inverted versions (see Hamming-book)
for i = nb_codes/2-1:-1:0
for s = 0:nb-1
Gray_tab(2*i+2,s+1) = -Gray_tab(i+1,s+1);
Gray_tab(2*i+1,s+1) = Gray_tab(i+1,s+1);
end
end

end

Gray_tab(Gray_tab==-1)=0;

Gray_dec = zeros(nb_codes,nb);
for i=1:nb
Gray_dec(:,i)=2^(i-1);
end
Gray_dec = cumsum(Gray_dec.*Gray_tab,2);
labelArray = Gray_dec(:,nb)';

if(qam==1&&nb>2)
labelArray = reshape(labelArray,sqrt(nb_codes),[])';
labelArray(2:2:end) = fliplr(labelArray(2:2:end,:));
labelArray = labelArray'(:)';
end

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% select Mapping and labeling

function plotConstellation(nb,labeling,mapPamQam,sizeFontLabeling,posCorrection,colorSigPoints)

ns=2^nb; % number of symbols    
[m l] = get_mapping_and_labeling(nb,labeling,mapPamQam);
    
bit=zeros(ns,nb);

curPosCorrection = posCorrection;
    
    for k=1:ns
        bit(k,:)=bitget(m(k),1:1:nb);
    end
    
    hold off;
    
    % plot mapping
    plot(real(l), imag(l), '.', 'color', colorSigPoints, 'markersize',20);
    hold on;
    
    for k=1:ns
        str='';
	if(nb <= 4)
        for n=1:nb
            str=[num2str(bit(k,n)),str];
        end
	else
            str=[num2str(m(k)),str];
	end

			if (mapPamQam == 2 && nb >= 4)        
			if ( bitand(k,1) )
			curPosCorrection = +posCorrection;
			else
			curPosCorrection = -posCorrection;
			end
			end       
        text(real(l(k)),imag(l(k))+curPosCorrection,str,'horizontalalignment','center','fontsize',sizeFontLabeling,'color','black');
        hold on;
    end
    
%grid on;
    
scalePlot = 1.2;

if ( mapPamQam == 2 )
if(nb==4)
scalePlot = 1.0;
end
axis autoscale
else    
axis square;
end
if(nb > 4)
scalePlot = 0.86;
end
xLimits = get(gca,'XLim');
yLimits = get(gca,'YLim');
xlim(scalePlot*xLimits);
ylim(scalePlot*yLimits);

xlabel('Re(z)');
ylabel('Im(z)');

end

% END, function definitions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%



