function sampling_intro
%
% sampling_intro_in.eps: Example of sampled input to DSP (+quantization)
% sampling_intro_out.eps: Example of DSP output (+quantization)
%

%
% Copyright (c) 2008 by Theodore P. Pavlic
%
% This work is licensed under the Creative Commons
% Attribution-Noncommercial 3.0 United States License. To view a copy of
% this license, visit http://creativecommons.org/licenses/by-nc/3.0/us/
% or send a letter to Creative Commons, 171 Second Street, Suite 300,
% San Francisco, California, 94105, USA.
%

% Upper-case    A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
% Lower-case    a b c d e f g h i j k l m n o p q r s t u v w x y z
% Digits        0 1 2 3 4 5 6 7 8 9
% Exclamation   !           Double quote "          Hash (number) #
% Dollar        $           Percent      %          Ampersand     &
% Acute accent  '           Left paren   (          Right paren   )
% Asterisk      *           Plus         +          Comma         ,
% Minus         -           Point        .          Solidus       /
% Colon         :           Semicolon    ;          Less than     <
% Equals        =           Greater than >          Question mark ?
% At            @           Left bracket [          Backslash     \
% Right bracket ]           Circumflex   ^          Underscore    _
% Grave accent  `           Left brace   {          Vertical bar  |
% Right brace   }           Tilde        ~


%%%%%%%%%%%%%%%%%%%%%%%%%%% Start of Script %%%%%%%%%%%%%%%%%%%%%%%%%%% 

% "Continuous-" and Discrete-Time Vectors
%t = linspace(0,20,10000);
%ts = linspace(0,20,100);
t = 0:2/1000:20-2/1000;
ts = 0:2/10:20-2/10;

% "Continuous-" and Discrete-Time Data
y = exp(-0.1*t) .* cos(2*pi*0.1*t);
ys = exp(-0.1*ts) .* cos(2*pi*0.1*ts);

%% Quantize the data
B = 3;
qlevels = (1/2^(B-1))*(-(2^(B-1)):(2^(B-1)-1));
yq = q( ys, B );

%%% Now filter the data
% z = tf( 'z', ts(2)-ts(1) );
% sys = 1.2/(z^2+0.2);


yfs = zeros(1,length(ts));
yfq = yfs;

% Must quantize the quantized signal; DSP's are quantized everywhere
yfq(1) = q(yfq(1),B);
yfq(2) = q(yfq(2),B);
for i = 3:length(ts)
    
    % Standard DT filter
    yfs(i) = 1.2*ys(i-2) - 0.2*yfs(i-2);
    
    % Quantize result of every operation
    yfq(i) = q( q(q(1.2,B)*yq(i-2),B) - q(q(0.2,B)*yfq(i-2),B), B ); 

end

%%% And sinc interpolate the ideal filtered signal (will ZOH the quantized)

yfssinc = sinc_interp_slow( yfs, ts, t );

%%%% All the crazy plots

%% Input plots (pre-DSP)

figure(1); clf; 

dtfigs = stem(ts, ys, 'filled'); set(dtfigs, 'ShowBaseLine', 'off');
hold on;
qlfigs = ...
    plot( repmat( xlim', 1, 2^(B)), [ qlevels; qlevels ], 'md--' ); 
    set( qlfigs, 'MarkerSize', 6, 'MarkerFaceColor', 'magenta');
qfigs = stem(ts, yq, '*'); 
    set(qfigs, 'MarkerSize', 8, 'MarkerFaceColor', 'blue');
ctfigs = plot(t, y);
hold off;

legfigs = legend( [ctfigs, dtfigs, qfigs, qlfigs(1)], ...
                  'Continuous-Time', ...
                  'Discrete-Time Samples', ...
                  [ num2str(B) '-bit Quantized Samples' ], ...
                  [ num2str(B) '-bit Quantization Levels' ], ...
                  'Location', 'SouthEast' );
set( legfigs, 'Interpreter', 'latex', 'FontSize', 14);

xlabel('Time (s)', 'Interpreter', 'latex', 'FontSize', 14);
ylabel('Data', 'Interpreter', 'latex', 'FontSize', 14);
title('\quad Quantized (``Digital'''') Samples of Continuous-Time Signal', ...
      'Interpreter', 'latex', 'FontSize', 14);
ylim1 = ylim;


%% "Output" plots (post-DSP)

figure(2); clf; 

ctffigs = plot( t, yfssinc );
hold on;
qlfigs = ...
    plot( repmat( xlim', 1, 2^(B)), [ qlevels; qlevels ], 'md--' ); 
    set( qlfigs, 'MarkerSize', 6, 'MarkerFaceColor', 'magenta');
dtfigs = plot(ts, yfs, 'o');
    set(dtfigs, 'MarkerSize', 6, 'MarkerFaceColor', 'blue');
qrfigs = stairs(ts, yfq);
    set( qrfigs, 'LineWidth', 1.5 );
qfigs = plot(ts, yfq, '*'); 
    set(qfigs, 'MarkerSize', 8, 'MarkerFaceColor', 'blue');
hold off;

legfigs = legend( [dtfigs, ctffigs, qfigs, qrfigs, qlfigs(1)], ...
                  'Filtered from Discrete-Time', ...
                  'Perfectly Reconstructed', ...
                  [ 'Filtered from ' num2str(B) ...
                    '-bit Quantization' ], ...
                  [ 'Held from ' num2str(B) ...
                    '-bit Quantization' ], ...
                  [ num2str(B) '-bit Quantization Levels' ], ...
                  'Location', 'SouthEast' );
set( legfigs, 'Interpreter', 'latex', 'FontSize', 14);

xlabel('Time (s)', 'Interpreter', 'latex', 'FontSize', 14);
ylabel('Data', 'Interpreter', 'latex', 'FontSize', 14);
title('\quad Filtered and Reconstructed Signal', ...
      'Interpreter', 'latex', 'FontSize', 14);
ylim2 = ylim;
  
ylimmax = [ min( [ ylim1 ylim2 ] ) max( [ ylim1 ylim2 ] ) ];


%%% Save the figures

figure(1); ylim( ylimmax ); 
set( gcf, 'PaperType', 'usletter', ...
          'PaperOrientation', 'portrait', ...
          'PaperPosition', [0.25 2.5 7.75 4.75]);
saveas( gcf, 'sampling_intro_in.eps', 'epsc2' );
%close(1);

figure(2); 
ylim( ylimmax ); 
set( gcf, 'PaperType', 'usletter', ...
          'PaperOrientation', 'portrait', ...
          'PaperPosition', [0.25 2.5 7.75 4.75]);
saveas( gcf, 'sampling_intro_out.eps', 'epsc2' ); 
%close(2);


%%% Helper functions  

    % Ideally "resamples" x vector from s to u by sinc interpolation
    %
    % NOTE: This *SLOW* version is provided for explanatory power.
    %       Actually use the fast sinc_interp below.
    %
    function y = sinc_interp_slow(x,s,u) 
        % Interpolates x sampled sampled at "s" instants
        % Output y is sampled at "u" instants ("u" for "upsampled")
       
        % Find the period of the undersampled signal
        T = s(2)-s(1);
      
        for i=1:length(u) 
            y( i ) = sum( x .* sinc( (1/T)*(u(i) - s) ) );
        end
    end

    % Calculates B-bit double-ended quantization (-V to V) of x
    function xq = q(x, B, V)

        if nargin < 3
            V = 1;
            
            if nargin < 2
                B = 3;
            end
        end
        
        xq = max( min( quant( x, 1/2^(B-1) ), V - V/2^(B-1) ), -V );

    end

    % Ideally "resamples" x vector from s to u by sinc interpolation
    %
    % NOTE: This is a fast version of sinc_interp_slow above.
    %       Its speed comes from all operations being "vectorized."
    %       That is, we avoid the use of "for" loops.
    %
    %       If you need an even faster version, just use the
    %       
    %          interpft
    %
    %       command. It does an FFT of the data, then it pads it with
    %       zeros, and then it does an IFFT to get the data back. It
    %       basically does the following (assuming length(x) is EVEN):
    %
    %         length( t )/length( ts ) * ...
    %         ifft( fftshift( ...
    %           [ zeros(1,length(u)/2) ...    % Negative padding
    %             fftshift( fft(x) ) ...
    %             zeros(1,length(u)/2) ] ...  % Positive padding
    %              ) )
    %
    %       The FFT algorithm is VERY FAST in general *AND* it's
    %       implemented as a MATLAB internal, so it's even faster.
    %       However, make sure that length(u)/length(s) is an
    %       INTEGER. Also make sure that u lands on the same points as
    %       s. That is, u should be a version of s with points ADDED.
    %       (e.g., s = 0:0.1:10-0.1; u = 0:0.01:10-0.01;).
    %
    function y = sinc_interp(x,s,u)
        % Interpolates x sampled sampled at "s" instants
        % Output y is sampled at "u" instants ("u" for "upsampled")
        
        % Find the period of the undersampled signal
        T = s(2)-s(1);

        % When generating this matrix, remember that "s" and "u" are
        % passed as ROW vectors and "y" is expected to also be a ROW
        % vector. If everything were column vectors, we'd do.
        %
        % sincM = repmat( u, 1, length(s) ) - repmat( s', length(u), 1 );
        %
        % So that the matrix would be longer than it is wide. 
        % Here, we generate the transpose of that matrix.
        sincM = repmat( u, length(s), 1 ) - repmat( s', 1, length(u) );
        
        % Equivalent to column vector math:
        %   y = sinc( sincM'/T )*x';
        y = x*sinc( sincM/T );
        
    end

end

%%%%%%%%%%%%%%%%%%%%%%%%%%% End of Script %%%%%%%%%%%%%%%%%%%%%%%%%%% 
