% WEBDEMO .m-file (Octave), Institute of Telecommunications, University of Stuttgart, Germany
% AUTHOR:   Nan Zhao

function [] = signalVisual(
    QAMorder,                   % bpsk = 1, qpsk = 2, 16qam = 3
    nChannel,                   % number of channel
    nSymbol,			% number of bits of each channel
    nTx,                        % number of transmit antenna
    nRx,                        % number of receive antenna
    snr,                        % snr of tx
    RxAlgorithm,                % ZF = 0, MMSE = 1, no processing = 2
    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, 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;     % default

    set(0, "defaultlinelinewidth", 2);

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


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

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

    userWarning = 0;
    warnStr=['Warning: ',"\n"];
    if(nChannel>1000000)
        nChannel = 100000;
    	warnStr= [warnStr "reset the number of channel to 100000\n"];
    	userWarning=1;
    end

    if(nRx<nTx)
    	nRx = nTx;
        warnStr= [warnStr "reset the number of receive antennas equal to the number of transmit antennas\n"];
    	userWarning=1;
    end

% END
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% main function
    s_display = [];

    for ii = 1:nChannel
        [ s_constellation,sigma_n,h,r ] = generate_MIMO_signal(snr,nTx,nRx,nSymbol,QAMorder);
        if(RxAlgorithm == 0)
            s_est_soft = ZF(h,r);
            s_display = [s_display,s_est_soft];
        elseif(RxAlgorithm == 1)
            s_est_soft = MMSE(h,r,nTx,sigma_n);
            s_display = [s_display,s_est_soft];
        else(RxAlgorithm == 2)
	    s_display = [s_display,r];
        endif
    end
    
    scatter(real(s_constellation(1,:)),imag(s_constellation(1,:)),[20],'r','filled');
    
    xlabel('Real part');
    ylabel('Imag. part');
    title(['Constellation Diagram, ' num2str(nTx) ' x ' num2str(nRx) ' MIMO (Rayleigh fading channel)']);
    hold on;
    set(gca, "linewidth", 2)
    scatter(real(s_display(1,:)),imag(s_display(1,:)),'b');
    
    
    axis([-3 3 -3 3]);
    
    if (userWarning)
     text(0.05, 0.5, warnStr, 'Color', 'red', 'FontSize', 7,...
            'Units', 'Normalized', 'HorizontalAlignment', 'left');
    end 

    % Create an image file. This image is displayed on the webpage. Its size
    % must be 640x480.
    if (webdemo_en)
        print(filename, "-dpng",output_format);
    end
    
    if (svg_en)
        print(["fig_",filename], "-dsvg",output_format);
    end

end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% function define

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% channel simulator
    function [s_constellation,sigma_n,h,r] = generate_MIMO_signal(snr,nTx,nRx,nSymbol,QAMorder)
		
        sigma_n = 10^(-snr/10);
        if(QAMorder == 1)
	    s_constellation = [1 -1];
            s_tx = randsrc(nTx,nSymbol,s_constellation);
        end

        if(QAMorder == 2)
	    s_constellation = [(1+1i*1)/sqrt(2) (-1+1i*1)/sqrt(2) (1-1i*1)/sqrt(2) (-1-1i*1)/sqrt(2)];
	    s_tx = randsrc(nTx,nSymbol,s_constellation);
        end
        
        if(QAMorder == 3)
	    s_constellation = [(1+1i*1)/sqrt(10) (1-1i*1)/sqrt(10) (1+1i*3)/sqrt(10) (1-1i*3)/sqrt(10)...
			       (-1+1i*1)/sqrt(10) (-1-1i*1)/sqrt(10) (-1+1i*3)/sqrt(10) (-1-1i*3)/sqrt(10)...
			       (3+1i*1)/sqrt(10) (3-1i*1)/sqrt(10) (3+1i*3)/sqrt(10) (3-1i*3)/sqrt(10)...
			       (-3+1i*1)/sqrt(10) (-3-1i*1)/sqrt(10) (-3+1i*3)/sqrt(10) (-3-1i*3)/sqrt(10)]
	    s_tx = randsrc(nTx,nSymbol,s_constellation);
	end

        h = (normrnd(0,1/sqrt(2),nRx,nTx) + 1i.*normrnd(0,1/sqrt(2),nRx,nTx))/sqrt(nTx);
        n = normrnd(0,sqrt(sigma_n./2),nRx,nSymbol) + 1i.*normrnd(0,sqrt(sigma_n./2),nRx,nSymbol);
        r = h*s_tx+n;
        
    end

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% open source code from octave
  function b = randsrc (n, m, alphabet, seed)

    switch (nargin)
      case 0,
	m = 1;
	n = 1;
	alphabet = [-1,1];
	seed = Inf;
      case 1,
	m = n;
	alphabet = [-1,1];
	seed = Inf;
      case 2,
	alphabet = [-1,1];
	seed = Inf;
      case 3,
	seed = Inf;      
      case 4,
      otherwise
	usage ("b = randsrc (n, [m, [alphabet, [seed]]])");
    endswitch

    ## Check alphabet
    [ar,ac] = size (alphabet);
    if (ac == 1)
      b = alphabet (1, 1) * ones (n, m);
      return;
    endif

    if (ar == 1)
      prob = [1:ac] / ac;
    elseif (ar == 2)
      prob = alphabet(2,:);
      alphabet = alphabet(1,:);
      if (abs(1-sum(prob)) > eps)
	error ("randsrc: probabilities must added up to one");
      endif
      prob = cumsum(prob);
    else
      error ("randsrc: alphabet must have 1 or 2 rows");
    endif
    
    ## Check seed;
    if (!isinf (seed))
      old_seed = rand ("seed");
      rand ("seed", seed);
    endif
    
    ## Create indexes with the right probabilities
    tmp = rand (n, m);
    b = ones (n, m);
    for i = 1:ac-1 
      b = b + (tmp > prob(i));
    end

    ## Map the indexes to the symbols
    b = alphabet(b);
    
    ## BUG: the above gives a row vector for some reason. Force what we want
    b = reshape(b, n, m);
      
    ## Get back to the old
    if (!isinf (seed))
      rand ("seed", old_seed);
    endif

  endfunction
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% ZF, get the soft value after ZF detection
    function [ s_est_soft_ZF ] = ZF(h,r)
            w_ZF = (h'*h)\h';
            s_est_soft_ZF = w_ZF*r;
    end

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


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% MMSE, get the soft value after MMSE detection
    function [ s_est_soft_MMSE ] = MMSE(h,r,nTx,sigma_n)
            w_MMSE = (h'*h+sigma_n*eye(nTx))\h';
            s_est_soft_MMSE = w_MMSE*r;
    end

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

% end function define
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%